All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.feilong.lib.beanutils.converters.NumberConverter Maven / Gradle / Ivy

Go to download

feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.

There is a newer version: 4.0.8
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.feilong.lib.beanutils.converters;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.text.ParsePosition;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.feilong.lib.beanutils.ConversionException;

/**
 * {@link com.feilong.lib.beanutils.Converter} implementaion that handles conversion
 * to and from java.lang.Number objects.
 * 

* This implementation handles conversion for the following * java.lang.Number types. *

    *
  • java.lang.Byte
  • *
  • java.lang.Short
  • *
  • java.lang.Integer
  • *
  • java.lang.Long
  • *
  • java.lang.Float
  • *
  • java.lang.Double
  • *
  • java.math.BigDecimal
  • *
  • java.math.BigInteger
  • *
* *

String Conversions (to and from)

* This class provides a number of ways in which number * conversions to/from Strings can be achieved: *
    *
  • Using the default format for the default Locale, configure using:
  • *
      *
    • setUseLocaleFormat(true)
    • *
    *
  • Using the default format for a specified Locale, configure using:
  • *
      *
    • setLocale(Locale)
    • *
    *
  • Using a specified pattern for the default Locale, configure using:
  • *
      *
    • setPattern(String)
    • *
    *
  • Using a specified pattern for a specified Locale, configure using:
  • *
      *
    • setPattern(String)
    • *
    • setLocale(Locale)
    • *
    *
  • If none of the above are configured the * toNumber(String) method is used to convert * from String to Number and the Number's * toString() method used to convert from * Number to String.
  • *
* *

* N.B.Patterns can only be specified using the standard * pattern characters and NOT in localized form (see java.text.DecimalFormat). * For example to cater for number styles used in Germany such as 0.000,00 the pattern * is specified in the normal form 0,000.00 and the locale set to Locale.GERMANY. * * @version $Id$ * @since 1.8.0 */ public abstract class NumberConverter extends AbstractConverter{ /** The Constant log. */ private static final Logger LOGGER = LoggerFactory.getLogger(NumberConverter.class); //--------------------------------------------------------------- private static final Integer ZERO = new Integer(0); private static final Integer ONE = new Integer(1); private String pattern; private final boolean allowDecimals; private boolean useLocaleFormat; private Locale locale; // ----------------------------------------------------------- Constructors /** * Construct a java.lang.Number Converter * that throws a ConversionException if a error occurs. * * @param allowDecimals * Indicates whether decimals are allowed */ public NumberConverter(final boolean allowDecimals){ super(); this.allowDecimals = allowDecimals; } /** * Construct a java.lang.Number Converter that returns * a default value if an error occurs. * * @param allowDecimals * Indicates whether decimals are allowed * @param defaultValue * The default value to be returned */ public NumberConverter(final boolean allowDecimals, final Object defaultValue){ super(); this.allowDecimals = allowDecimals; setDefaultValue(defaultValue); } // --------------------------------------------------------- Public Methods /** * Return whether decimals are allowed in the number. * * @return Whether decimals are allowed in the number */ public boolean isAllowDecimals(){ return allowDecimals; } /** * Set whether a format should be used to convert * the Number. * * @param useLocaleFormat * true if a number format * should be used. */ public void setUseLocaleFormat(final boolean useLocaleFormat){ this.useLocaleFormat = useLocaleFormat; } /** * Return the number format pattern used to convert * Numbers to/from a java.lang.String * (or null if none specified). *

* See java.text.DecimalFormat for details * of how to specify the pattern. * * @return The format pattern. */ public String getPattern(){ return pattern; } /** * Set a number format pattern to use to convert * Numbers to/from a java.lang.String. *

* See java.text.DecimalFormat for details * of how to specify the pattern. * * @param pattern * The format pattern. */ public void setPattern(final String pattern){ this.pattern = pattern; setUseLocaleFormat(true); } /** * Return the Locale for the Converter * (or null if none specified). * * @return The locale to use for conversion */ public Locale getLocale(){ return locale; } /** * Set the Locale for the Converter. * * @param locale * The locale to use for conversion */ public void setLocale(final Locale locale){ this.locale = locale; setUseLocaleFormat(true); } // ------------------------------------------------------ Protected Methods /** * Convert an input Number object into a String. * * @param value * The input value to be converted * @return the converted String value. * @throws Throwable * if an error occurs converting to a String */ @Override protected String convertToString(final Object value) throws Throwable{ String result = null; if (useLocaleFormat && value instanceof Number){ final NumberFormat format = getFormat(); format.setGroupingUsed(false); result = format.format(value); if (LOGGER.isDebugEnabled()){ LOGGER.debug(" Converted to String using format '" + result + "'"); } }else{ result = value.toString(); if (LOGGER.isDebugEnabled()){ LOGGER.debug(" Converted to String using toString() '" + result + "'"); } } return result; } /** * Convert the input object into a Number object of the * specified type. * * @param * Target type of the conversion. * @param targetType * Data type to which this value should be converted. * @param value * The input value to be converted. * @return The converted value. * @throws Throwable * if an error occurs converting to the specified type */ @Override protected T convertToType(final Class targetType,final Object value) throws Throwable{ final Class sourceType = value.getClass(); // Handle Number if (value instanceof Number){ return toNumber(sourceType, targetType, (Number) value); } // Handle Boolean if (value instanceof Boolean){ return toNumber(sourceType, targetType, ((Boolean) value).booleanValue() ? ONE : ZERO); } // Handle Date --> Long if (value instanceof Date && Long.class.equals(targetType)){ return targetType.cast(new Long(((Date) value).getTime())); } // Handle Calendar --> Long if (value instanceof Calendar && Long.class.equals(targetType)){ return targetType.cast(new Long(((Calendar) value).getTime().getTime())); } // Convert all other types to String & handle final String stringValue = value.toString().trim(); if (stringValue.length() == 0){ return handleMissing(targetType); } // Convert/Parse a String Number number = null; if (useLocaleFormat){ final NumberFormat format = getFormat(); number = parse(sourceType, targetType, stringValue, format); }else{ if (LOGGER.isDebugEnabled()){ LOGGER.debug(" No NumberFormat, using default conversion"); } number = toNumber(sourceType, targetType, stringValue); } // Ensure the correct number type is returned return toNumber(sourceType, targetType, number); } /** * Convert any Number object to the specified type for this * Converter. *

* This method handles conversion to the following types: *

    *
  • java.lang.Byte
  • *
  • java.lang.Short
  • *
  • java.lang.Integer
  • *
  • java.lang.Long
  • *
  • java.lang.Float
  • *
  • java.lang.Double
  • *
  • java.math.BigDecimal
  • *
  • java.math.BigInteger
  • *
* * @param sourceType * The type being converted from * @param targetType * The Number type to convert to * @param value * The Number to convert. * * @return The converted value. */ private T toNumber(final Class sourceType,final Class targetType,final Number value){ // Correct Number type already if (targetType.equals(value.getClass())){ return targetType.cast(value); } // Byte if (targetType.equals(Byte.class)){ final long longValue = value.longValue(); if (longValue > Byte.MAX_VALUE){ throw new ConversionException(toString(sourceType) + " value '" + value + "' is too large for " + toString(targetType)); } if (longValue < Byte.MIN_VALUE){ throw new ConversionException(toString(sourceType) + " value '" + value + "' is too small " + toString(targetType)); } return targetType.cast(new Byte(value.byteValue())); } // Short if (targetType.equals(Short.class)){ final long longValue = value.longValue(); if (longValue > Short.MAX_VALUE){ throw new ConversionException(toString(sourceType) + " value '" + value + "' is too large for " + toString(targetType)); } if (longValue < Short.MIN_VALUE){ throw new ConversionException(toString(sourceType) + " value '" + value + "' is too small " + toString(targetType)); } return targetType.cast(new Short(value.shortValue())); } // Integer if (targetType.equals(Integer.class)){ final long longValue = value.longValue(); if (longValue > Integer.MAX_VALUE){ throw new ConversionException(toString(sourceType) + " value '" + value + "' is too large for " + toString(targetType)); } if (longValue < Integer.MIN_VALUE){ throw new ConversionException(toString(sourceType) + " value '" + value + "' is too small " + toString(targetType)); } return targetType.cast(new Integer(value.intValue())); } // Long if (targetType.equals(Long.class)){ return targetType.cast(new Long(value.longValue())); } // Float if (targetType.equals(Float.class)){ if (value.doubleValue() > Float.MAX_VALUE){ throw new ConversionException(toString(sourceType) + " value '" + value + "' is too large for " + toString(targetType)); } return targetType.cast(new Float(value.floatValue())); } // Double if (targetType.equals(Double.class)){ return targetType.cast(new Double(value.doubleValue())); } // BigDecimal if (targetType.equals(BigDecimal.class)){ if (value instanceof Float || value instanceof Double){ return targetType.cast(new BigDecimal(value.toString())); }else if (value instanceof BigInteger){ return targetType.cast(new BigDecimal((BigInteger) value)); }else if (value instanceof BigDecimal){ return targetType.cast(new BigDecimal(value.toString())); }else{ return targetType.cast(BigDecimal.valueOf(value.longValue())); } } // BigInteger if (targetType.equals(BigInteger.class)){ if (value instanceof BigDecimal){ return targetType.cast(((BigDecimal) value).toBigInteger()); } return targetType.cast(BigInteger.valueOf(value.longValue())); } final String msg = toString(getClass()) + " cannot handle conversion to '" + toString(targetType) + "'"; if (LOGGER.isWarnEnabled()){ LOGGER.warn(" " + msg); } throw new ConversionException(msg); } /** * Default String to Number conversion. *

* This method handles conversion from a String to the following types: *

    *
  • java.lang.Byte
  • *
  • java.lang.Short
  • *
  • java.lang.Integer
  • *
  • java.lang.Long
  • *
  • java.lang.Float
  • *
  • java.lang.Double
  • *
  • java.math.BigDecimal
  • *
  • java.math.BigInteger
  • *
* * @param sourceType * The type being converted from * @param targetType * The Number type to convert to * @param value * The String value to convert. * * @return The converted Number value. */ private Number toNumber(final Class sourceType,final Class targetType,final String value){ // Byte if (targetType.equals(Byte.class)){ return new Byte(value); } // Short if (targetType.equals(Short.class)){ return new Short(value); } // Integer if (targetType.equals(Integer.class)){ return new Integer(value); } // Long if (targetType.equals(Long.class)){ return new Long(value); } // Float if (targetType.equals(Float.class)){ return new Float(value); } // Double if (targetType.equals(Double.class)){ return new Double(value); } // BigDecimal if (targetType.equals(BigDecimal.class)){ return new BigDecimal(value); } // BigInteger if (targetType.equals(BigInteger.class)){ return new BigInteger(value); } final String msg = toString(getClass()) + " cannot handle conversion from '" + toString(sourceType) + "' to '" + toString(targetType) + "'"; if (LOGGER.isWarnEnabled()){ LOGGER.warn(" " + msg); } throw new ConversionException(msg); } /** * Provide a String representation of this number converter. * * @return A String representation of this number converter */ @Override public String toString(){ final StringBuilder buffer = new StringBuilder(); buffer.append(toString(getClass())); buffer.append("[UseDefault="); buffer.append(isUseDefault()); buffer.append(", UseLocaleFormat="); buffer.append(useLocaleFormat); if (pattern != null){ buffer.append(", Pattern="); buffer.append(pattern); } if (locale != null){ buffer.append(", Locale="); buffer.append(locale); } buffer.append(']'); return buffer.toString(); } /** * Return a NumberFormat to use for Conversion. * * @return The NumberFormat. */ private NumberFormat getFormat(){ NumberFormat format = null; if (pattern != null){ if (locale == null){ if (LOGGER.isDebugEnabled()){ LOGGER.debug(" Using pattern '" + pattern + "'"); } format = new DecimalFormat(pattern); }else{ if (LOGGER.isDebugEnabled()){ LOGGER.debug(" Using pattern '" + pattern + "'" + " with Locale[" + locale + "]"); } final DecimalFormatSymbols symbols = new DecimalFormatSymbols(locale); format = new DecimalFormat(pattern, symbols); } }else{ if (locale == null){ if (LOGGER.isDebugEnabled()){ LOGGER.debug(" Using default Locale format"); } format = NumberFormat.getInstance(); }else{ if (LOGGER.isDebugEnabled()){ LOGGER.debug(" Using Locale[" + locale + "] format"); } format = NumberFormat.getInstance(locale); } } if (!allowDecimals){ format.setParseIntegerOnly(true); } return format; } /** * Convert a String into a Number object. * * @param sourceType * the source type of the conversion * @param targetType * The type to convert the value to * @param value * The String date value. * @param format * The NumberFormat to parse the String value. * * @return The converted Number object. * @throws ConversionException * if the String cannot be converted. */ private Number parse(final Class sourceType,final Class targetType,final String value,final NumberFormat format){ final ParsePosition pos = new ParsePosition(0); final Number parsedNumber = format.parse(value, pos); if (pos.getErrorIndex() >= 0 || pos.getIndex() != value.length() || parsedNumber == null){ String msg = "Error converting from '" + toString(sourceType) + "' to '" + toString(targetType) + "'"; if (format instanceof DecimalFormat){ msg += " using pattern '" + ((DecimalFormat) format).toPattern() + "'"; } if (locale != null){ msg += " for locale=[" + locale + "]"; } if (LOGGER.isDebugEnabled()){ LOGGER.debug(" " + msg); } throw new ConversionException(msg); } return parsedNumber; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy