View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.beanutils2.locale.converters;
19  
20  import java.text.DecimalFormat;
21  import java.text.NumberFormat;
22  import java.text.ParseException;
23  import java.util.Locale;
24  
25  import org.apache.commons.beanutils2.ConversionException;
26  import org.apache.commons.beanutils2.locale.BaseLocaleConverter;
27  import org.apache.commons.beanutils2.locale.LocaleConverter;
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  
31  /**
32   * Standard {@link LocaleConverter} implementation that converts an incoming locale-sensitive String into a {@link Number} object, optionally using a default
33   * value or throwing a {@link ConversionException} if a conversion error occurs.
34   *
35   * @param <T> The converter type.
36   * @since 1.7
37   */
38  public class DecimalLocaleConverter<T extends Number> extends BaseLocaleConverter<T> {
39  
40      /**
41       * Builds instances of {@link DateLocaleConverter}.
42       *
43       * @param <B> The builder type.
44       * @param <T> The Number type.
45       */
46      public static class Builder<B extends Builder<B, T>, T extends Number> extends BaseLocaleConverter.Builder<B, T> {
47  
48          /**
49           * Constructs a new instance.
50           */
51          public Builder() {
52              // empty
53          }
54  
55          /**
56           * Constructs a new instance.
57           * <p>
58           * By default, construct a {@link LocaleConverter} that will throw a {@link ConversionException} if a conversion error occurs. The locale is the default
59           * locale for this instance of the Java Virtual Machine and an unlocalized pattern is used for the conversion.
60           * </p>
61           *
62           * @return a new instance.
63           */
64          @Override
65          public DecimalLocaleConverter<?> get() {
66              return new DecimalLocaleConverter<>(defaultValue, locale, pattern, useDefault || defaultValue != null, localizedPattern);
67          }
68  
69      }
70  
71      /** All logging goes through this logger */
72      private static final Log LOG = LogFactory.getLog(DecimalLocaleConverter.class);
73  
74      /**
75       * Constructs a new builder.
76       *
77       * @param <B> The builder type.
78       * @param <T> The Number type.
79       * @return a new builder.
80       */
81      @SuppressWarnings("unchecked")
82      public static <B extends Builder<B, T>, T extends Number> B builder() {
83          return (B) new Builder<>();
84      }
85  
86      /**
87       * Constructs a new instance.
88       *
89       * @param defaultValue default value.
90       * @param locale       locale.
91       * @param pattern      pattern.
92       * @param useDefault   use the default.
93       * @param locPattern   localized pattern.
94       */
95      protected DecimalLocaleConverter(final T defaultValue, final Locale locale, final String pattern, final boolean useDefault, final boolean locPattern) {
96          super(defaultValue, locale, pattern, useDefault, locPattern);
97      }
98  
99      /**
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 }