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 * <p> 051 * By default, construct a {@link LocaleConverter} that will throw a {@link ConversionException} if a conversion error occurs. The locale is the default 052 * locale for this instance of the Java Virtual Machine and an unlocalized pattern is used for the conversion. 053 * </p> 054 * 055 * @return a new instance. 056 */ 057 @Override 058 public DecimalLocaleConverter<?> get() { 059 return new DecimalLocaleConverter<>(defaultValue, locale, pattern, useDefault || defaultValue != null, localizedPattern); 060 } 061 062 } 063 064 /** All logging goes through this logger */ 065 private static final Log LOG = LogFactory.getLog(DecimalLocaleConverter.class); 066 067 /** 068 * Constructs a new builder. 069 * 070 * @param <B> The builder type. 071 * @param <T> The Number type. 072 * @return a new builder. 073 */ 074 @SuppressWarnings("unchecked") 075 public static <B extends Builder<B, T>, T extends Number> B builder() { 076 return (B) new Builder<>(); 077 } 078 079 /** 080 * Constructs a new instance. 081 * 082 * @param defaultValue default value. 083 * @param locale locale. 084 * @param pattern pattern. 085 * @param useDefault use the default. 086 * @param locPattern localized pattern. 087 */ 088 protected DecimalLocaleConverter(final T defaultValue, final Locale locale, final String pattern, final boolean useDefault, final boolean locPattern) { 089 super(defaultValue, locale, pattern, useDefault, locPattern); 090 } 091 092 /** 093 * Converts the specified locale-sensitive input object into an output object of the specified type. 094 * 095 * @param value The input object to be converted 096 * @param pattern The pattern is used for the conversion 097 * @return The converted value 098 * @throws ConversionException if conversion cannot be performed successfully 099 * @throws ParseException if an error occurs parsing a String to a Number 100 */ 101 @Override 102 protected T parse(final Object value, final String pattern) throws ParseException { 103 if (value instanceof Number) { 104 return (T) value; 105 } 106 107 // Note that despite the ambiguous "getInstance" name, and despite the 108 // fact that objects returned from this method have the same toString 109 // representation, each call to getInstance actually returns a new 110 // object. 111 final DecimalFormat formatter = (DecimalFormat) NumberFormat.getInstance(locale); 112 113 // if some constructors default pattern to null, it makes only sense 114 // to handle null pattern gracefully 115 if (pattern != null) { 116 if (localizedPattern) { 117 formatter.applyLocalizedPattern(pattern); 118 } else { 119 formatter.applyPattern(pattern); 120 } 121 } else { 122 LOG.debug("No pattern provided, using default."); 123 } 124 125 return (T) formatter.parse((String) value); 126 } 127}