001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.beanutils2.locale.converters; 019 020import java.text.DecimalFormat; 021import java.text.NumberFormat; 022import java.text.ParseException; 023import java.util.Locale; 024 025import org.apache.commons.beanutils2.ConversionException; 026import org.apache.commons.beanutils2.locale.BaseLocaleConverter; 027import org.apache.commons.beanutils2.locale.LocaleConverter; 028import org.apache.commons.logging.Log; 029import org.apache.commons.logging.LogFactory; 030 031/** 032 * Standard {@link LocaleConverter} implementation that converts an incoming locale-sensitive String into a {@link Number} object, optionally using a default 033 * value or throwing a {@link ConversionException} if a conversion error occurs. 034 * 035 * @param <T> The converter type. 036 * @since 1.7 037 */ 038public class DecimalLocaleConverter<T extends Number> extends BaseLocaleConverter<T> { 039 040 /** 041 * Builds instances of {@link DateLocaleConverter}. 042 * 043 * @param <B> The builder type. 044 * @param <T> The Number type. 045 */ 046 public static class Builder<B extends Builder<B, T>, T extends Number> extends BaseLocaleConverter.Builder<B, T> { 047 048 /** 049 * Constructs a new instance. 050 */ 051 public Builder() { 052 // empty 053 } 054 055 /** 056 * Constructs a new instance. 057 * <p> 058 * By default, construct a {@link LocaleConverter} that will throw a {@link ConversionException} if a conversion error occurs. The locale is the default 059 * locale for this instance of the Java Virtual Machine and an unlocalized pattern is used for the conversion. 060 * </p> 061 * 062 * @return a new instance. 063 */ 064 @Override 065 public DecimalLocaleConverter<?> get() { 066 return new DecimalLocaleConverter<>(defaultValue, locale, pattern, useDefault || defaultValue != null, localizedPattern); 067 } 068 069 } 070 071 /** All logging goes through this logger */ 072 private static final Log LOG = LogFactory.getLog(DecimalLocaleConverter.class); 073 074 /** 075 * Constructs a new builder. 076 * 077 * @param <B> The builder type. 078 * @param <T> The Number type. 079 * @return a new builder. 080 */ 081 @SuppressWarnings("unchecked") 082 public static <B extends Builder<B, T>, T extends Number> B builder() { 083 return (B) new Builder<>(); 084 } 085 086 /** 087 * Constructs a new instance. 088 * 089 * @param defaultValue default value. 090 * @param locale locale. 091 * @param pattern pattern. 092 * @param useDefault use the default. 093 * @param locPattern localized pattern. 094 */ 095 protected DecimalLocaleConverter(final T defaultValue, final Locale locale, final String pattern, final boolean useDefault, final boolean locPattern) { 096 super(defaultValue, locale, pattern, useDefault, locPattern); 097 } 098 099 /** 100 * Converts the specified locale-sensitive input object into an output object of the specified type. 101 * 102 * @param value The input object to be converted 103 * @param pattern The pattern is used for the conversion 104 * @return The converted value 105 * @throws ConversionException if conversion cannot be performed successfully 106 * @throws ParseException if an error occurs parsing a String to a Number 107 */ 108 @Override 109 protected T parse(final Object value, final String pattern) throws ParseException { 110 if (value instanceof Number) { 111 return (T) value; 112 } 113 114 // Note that despite the ambiguous "getInstance" name, and despite the 115 // fact that objects returned from this method have the same toString 116 // representation, each call to getInstance actually returns a new 117 // object. 118 final DecimalFormat formatter = (DecimalFormat) NumberFormat.getInstance(locale); 119 120 // if some constructors default pattern to null, it makes only sense 121 // to handle null pattern gracefully 122 if (pattern != null) { 123 if (localizedPattern) { 124 formatter.applyLocalizedPattern(pattern); 125 } else { 126 formatter.applyPattern(pattern); 127 } 128 } else { 129 LOG.debug("No pattern provided, using default."); 130 } 131 132 return (T) formatter.parse((String) value); 133 } 134}