123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426 |
- /**
- * Copyright 2008-2009. Chongqing Communications Industry Services Co.,Ltd Information Technology Branch. All rights reserved. <a>http://www.crunii.com</a>
- */
- package com.crunii.micro.common.converter;
- import lombok.extern.slf4j.Slf4j;
- import org.apache.commons.beanutils.ConversionException;
- import org.apache.commons.beanutils.Converter;
- import org.apache.commons.beanutils.converters.DateConverter;
- import org.apache.commons.beanutils.converters.*;
- import java.io.File;
- import java.lang.reflect.Array;
- import java.math.BigDecimal;
- import java.math.BigInteger;
- import java.net.URL;
- import java.sql.Timestamp;
- import java.util.Calendar;
- import java.util.Collection;
- import java.util.concurrent.ConcurrentHashMap;
- /**
- * @author 田平 create 2020年3月31日下午3:44:04
- */
- @Slf4j
- public class ConvertUtilBean {
- private static final Integer ZERO = new Integer(0);
- private static final Character SPACE = new Character(' ');
- private final ConcurrentHashMap<Class<?>, Converter> converters = new ConcurrentHashMap<Class<?>, Converter>(32);
- public ConvertUtilBean() {
- register();
- }
- /**
- * Convert the specified value into a String. If the specified value is an array, the first element (converted to a String) will be returned. The registered {@link Converter} for the <code>java.lang.String</code> class will be used, which allows applications to customize Object->String conversions (the default implementation simply uses toString()).
- *
- * @param value Value to be converted (may be null)
- * @return The converted String value or null if value is null
- */
- public String convert(Object value) {
- if (value == null) {
- return null;
- } else if (value.getClass().isArray()) {
- if (Array.getLength(value) < 1) {
- return (null);
- }
- value = Array.get(value, 0);
- if (value == null) {
- return null;
- } else {
- final Converter converter = lookup(String.class);
- return (converter.convert(String.class, value));
- }
- } else {
- final Converter converter = lookup(String.class);
- return (converter.convert(String.class, value));
- }
- }
- /**
- * Convert the specified value to an object of the specified class (if possible). Otherwise, return a String representation of the value.
- *
- * @param value Value to be converted (may be null)
- * @param clazz Java class to be converted to (must not be null)
- * @return The converted value
- * @throws ConversionException if thrown by an underlying Converter
- */
- public Object convert(final String value, final Class<?> clazz) {
- if (log.isDebugEnabled()) {
- log.debug("Convert string '" + value + "' to class '" +
- clazz.getName() + "'");
- }
- Converter converter = lookup(clazz);
- if (converter == null) {
- converter = lookup(String.class);
- }
- if (log.isTraceEnabled()) {
- log.trace(" Using converter " + converter);
- }
- return (converter.convert(clazz, value));
- }
- /**
- * Convert an array of specified values to an array of objects of the specified class (if possible). If the specified Java class is itself an array class, this class will be the type of the returned value. Otherwise, an array will be constructed whose component type is the specified class.
- *
- * @param values Array of values to be converted
- * @param clazz Java array or element class to be converted to (must not be null)
- * @return The converted value
- * @throws ConversionException if thrown by an underlying Converter
- */
- public Object convert(final String[] values, final Class<?> clazz) {
- Class<?> type = clazz;
- if (clazz.isArray()) {
- type = clazz.getComponentType();
- }
- if (log.isDebugEnabled()) {
- log.debug("Convert String[" + values.length + "] to class '" +
- type.getName() + "[]'");
- }
- Converter converter = lookup(type);
- if (converter == null) {
- converter = lookup(String.class);
- }
- if (log.isTraceEnabled()) {
- log.trace(" Using converter " + converter);
- }
- final Object array = Array.newInstance(type, values.length);
- for (int i = 0; i < values.length; i++) {
- Array.set(array, i, converter.convert(type, values[i]));
- }
- return (array);
- }
- /**
- * Convert the value to an object of the specified class (if possible). If no converter for the desired target type is registered, the passed in object is returned unchanged.
- *
- * @param value Value to be converted (may be null)
- * @param targetType Class of the value to be converted to (must not be null)
- * @return The converted value
- * @throws ConversionException if thrown by an underlying Converter
- */
- public Object convert(final Object value, final Class<?> targetType) {
- final Class<?> sourceType = value == null ? null : value.getClass();
- if (log.isDebugEnabled()) {
- if (value == null) {
- log.debug("Convert null value to type '" +
- targetType.getName() + "'");
- } else {
- log.debug("Convert type '" + sourceType.getName() + "' value '" + value +
- "' to type '" + targetType.getName() + "'");
- }
- }
- Object converted = value;
- Converter converter = lookup(sourceType, targetType);
- if (converter != null) {
- if (log.isTraceEnabled()) {
- log.trace(" Using converter " + converter);
- }
- converted = converter.convert(targetType, value);
- }
- if (String.class.equals(targetType) && converted != null &&
- !(converted instanceof String)) {
- // NOTE: For backwards compatibility, if the Converter
- // doesn't handle conversion-->String then
- // use the registered String Converter
- converter = lookup(String.class);
- if (converter != null) {
- if (log.isTraceEnabled()) {
- log.trace(" Using converter " + converter);
- }
- converted = converter.convert(String.class, converted);
- }
- // If the object still isn't a String, use toString() method
- if (converted != null && !(converted instanceof String)) {
- converted = converted.toString();
- }
- }
- return converted;
- }
- /**
- * Remove all registered {@link Converter}s, and re-establish the standard Converters.
- */
- private void register() {
- registerPrimitives(true);
- registerStandard(true, false);
- registerOther(true);
- registerArrays(true, 0);
- register(BigDecimal.class, new BigDecimalConverter(false));
- register(BigInteger.class, new BigIntegerConverter(false));
- }
- /**
- * Register the converters for primitive types.
- * </p>
- * This method registers the following converters:
- * <ul>
- * <li><code>Boolean.TYPE</code> - {@link BooleanConverter}</li>
- * <li><code>Byte.TYPE</code> - {@link ByteConverter}</li>
- * <li><code>Character.TYPE</code> - {@link CharacterConverter}</li>
- * <li><code>Double.TYPE</code> - {@link DoubleConverter}</li>
- * <li><code>Float.TYPE</code> - {@link FloatConverter}</li>
- * <li><code>Integer.TYPE</code> - {@link IntegerConverter}</li>
- * <li><code>Long.TYPE</code> - {@link LongConverter}</li>
- * <li><code>Short.TYPE</code> - {@link ShortConverter}</li>
- * </ul>
- *
- * @param throwException <code>true</code> if the converters should throw an exception when a conversion error occurs, otherwise <code>
- * <code>false</code> if a default value should be used.
- */
- private void registerPrimitives(final boolean throwException) {
- register(Boolean.TYPE, throwException ? new BooleanConverter() : new BooleanConverter(Boolean.FALSE));
- register(Byte.TYPE, throwException ? new ByteConverter() : new ByteConverter(ZERO));
- register(Character.TYPE, throwException ? new CharacterConverter() : new CharacterConverter(SPACE));
- register(Double.TYPE, throwException ? new DoubleConverter() : new DoubleConverter(ZERO));
- register(Float.TYPE, throwException ? new FloatConverter() : new FloatConverter(ZERO));
- register(Integer.TYPE, throwException ? new IntegerConverter() : new IntegerConverter(ZERO));
- register(Long.TYPE, throwException ? new LongConverter() : new LongConverter(ZERO));
- register(Short.TYPE, throwException ? new ShortConverter() : new ShortConverter(ZERO));
- }
- /**
- * Register the converters for standard types.
- * </p>
- * This method registers the following converters:
- * <ul>
- * <li><code>BigDecimal.class</code> - {@link BigDecimalConverter}</li>
- * <li><code>BigInteger.class</code> - {@link BigIntegerConverter}</li>
- * <li><code>Boolean.class</code> - {@link BooleanConverter}</li>
- * <li><code>Byte.class</code> - {@link ByteConverter}</li>
- * <li><code>Character.class</code> - {@link CharacterConverter}</li>
- * <li><code>Double.class</code> - {@link DoubleConverter}</li>
- * <li><code>Float.class</code> - {@link FloatConverter}</li>
- * <li><code>Integer.class</code> - {@link IntegerConverter}</li>
- * <li><code>Long.class</code> - {@link LongConverter}</li>
- * <li><code>Short.class</code> - {@link ShortConverter}</li>
- * <li><code>String.class</code> - {@link StringConverter}</li>
- * </ul>
- *
- * @param throwException <code>true</code> if the converters should throw an exception when a conversion error occurs, otherwise <code>
- * <code>false</code> if a default value should be used.
- * @param defaultNull <code>true</code>if the <i>standard</i> converters
- */
- private void registerStandard(final boolean throwException, final boolean defaultNull) {
- final Number defaultNumber = defaultNull ? null : ZERO;
- final BigDecimal bigDecDeflt = defaultNull ? null : new BigDecimal("0.0");
- final BigInteger bigIntDeflt = defaultNull ? null : new BigInteger("0");
- final Boolean booleanDefault = defaultNull ? null : Boolean.FALSE;
- final Character charDefault = defaultNull ? null : SPACE;
- final String stringDefault = defaultNull ? null : "";
- register(BigDecimal.class, throwException ? new BigDecimalConverter() : new BigDecimalConverter(bigDecDeflt));
- register(BigInteger.class, throwException ? new BigIntegerConverter() : new BigIntegerConverter(bigIntDeflt));
- register(Boolean.class, throwException ? new BooleanConverter() : new BooleanConverter(booleanDefault));
- register(Byte.class, throwException ? new ByteConverter() : new ByteConverter(defaultNumber));
- register(Character.class, throwException ? new CharacterConverter() : new CharacterConverter(charDefault));
- register(Double.class, throwException ? new DoubleConverter() : new DoubleConverter(defaultNumber));
- register(Float.class, throwException ? new FloatConverter() : new FloatConverter(defaultNumber));
- register(Integer.class, throwException ? new IntegerConverter() : new IntegerConverter(defaultNumber));
- register(Long.class, throwException ? new LongConverter() : new LongConverter(defaultNumber));
- register(Short.class, throwException ? new ShortConverter() : new ShortConverter(defaultNumber));
- register(String.class, throwException ? new StringConverter() : new StringConverter(stringDefault));
- }
- /**
- * Register the converters for other types.
- * </p>
- * This method registers the following converters:
- * <ul>
- * <li><code>Class.class</code> - {@link ClassConverter}</li>
- * <li><code>java.util.Date.class</code> - {@link DateConverter}</li>
- * <li><code>java.util.Calendar.class</code> - {@link CalendarConverter}</li>
- * <li><code>File.class</code> - {@link FileConverter}</li>
- * <li><code>java.sql.Date.class</code> - {@link SqlDateConverter}</li>
- * <li><code>java.sql.Time.class</code> - {@link SqlTimeConverter}</li>
- * <li><code>java.sql.Timestamp.class</code> - {@link SqlTimestampConverter}</li>
- * <li><code>URL.class</code> - {@link URLConverter}</li>
- * </ul>
- *
- * @param throwException <code>true</code> if the converters should throw an exception when a conversion error occurs, otherwise <code>
- * <code>false</code> if a default value should be used.
- */
- private void registerOther(final boolean throwException) {
- register(Class.class, throwException ? new ClassConverter() : new ClassConverter(null));
- //register(java.util.Date.class, throwException ? new DateConverter() : new DateConverter(null));
- register(java.util.Date.class, com.crunii.micro.common.converter.DateConverter.getDateConverter());
- register(Calendar.class, throwException ? new CalendarConverter() : new CalendarConverter(null));
- register(File.class, throwException ? new FileConverter() : new FileConverter(null));
- register(java.sql.Date.class, throwException ? new SqlDateConverter() : new SqlDateConverter(null));
- register(java.sql.Time.class, throwException ? new SqlTimeConverter() : new SqlTimeConverter(null));
- register(Timestamp.class, throwException ? new SqlTimestampConverter() : new SqlTimestampConverter(null));
- register(URL.class, throwException ? new URLConverter() : new URLConverter(null));
- }
- /**
- * Register array converters.
- *
- * @param throwException <code>true</code> if the converters should throw an exception when a conversion error occurs, otherwise <code>
- * <code>false</code> if a default value should be used.
- * @param defaultArraySize The size of the default array value for array converters (N.B. This values is ignored if <code>throwException</code> is <code>true</code>). Specifying a value less than zero causes a <code>null<code> value to be used for the default.
- */
- private void registerArrays(final boolean throwException, final int defaultArraySize) {
- // Primitives
- registerArrayConverter(Boolean.TYPE, new BooleanConverter(), throwException, defaultArraySize);
- registerArrayConverter(Byte.TYPE, new ByteConverter(), throwException, defaultArraySize);
- registerArrayConverter(Character.TYPE, new CharacterConverter(), throwException, defaultArraySize);
- registerArrayConverter(Double.TYPE, new DoubleConverter(), throwException, defaultArraySize);
- registerArrayConverter(Float.TYPE, new FloatConverter(), throwException, defaultArraySize);
- registerArrayConverter(Integer.TYPE, new IntegerConverter(), throwException, defaultArraySize);
- registerArrayConverter(Long.TYPE, new LongConverter(), throwException, defaultArraySize);
- registerArrayConverter(Short.TYPE, new ShortConverter(), throwException, defaultArraySize);
- // Standard
- registerArrayConverter(BigDecimal.class, new BigDecimalConverter(), throwException, defaultArraySize);
- registerArrayConverter(BigInteger.class, new BigIntegerConverter(), throwException, defaultArraySize);
- registerArrayConverter(Boolean.class, new BooleanConverter(), throwException, defaultArraySize);
- registerArrayConverter(Byte.class, new ByteConverter(), throwException, defaultArraySize);
- registerArrayConverter(Character.class, new CharacterConverter(), throwException, defaultArraySize);
- registerArrayConverter(Double.class, new DoubleConverter(), throwException, defaultArraySize);
- registerArrayConverter(Float.class, new FloatConverter(), throwException, defaultArraySize);
- registerArrayConverter(Integer.class, new IntegerConverter(), throwException, defaultArraySize);
- registerArrayConverter(Long.class, new LongConverter(), throwException, defaultArraySize);
- registerArrayConverter(Short.class, new ShortConverter(), throwException, defaultArraySize);
- registerArrayConverter(String.class, new StringConverter(), throwException, defaultArraySize);
- // Other
- registerArrayConverter(Class.class, new ClassConverter(), throwException, defaultArraySize);
- //registerArrayConverter(java.util.Date.class, new DateConverter(), throwException, defaultArraySize);
- registerArrayConverter(java.util.Date.class, com.crunii.micro.common.converter.DateConverter.getDateConverter(), throwException,
- defaultArraySize);
- registerArrayConverter(Calendar.class, new DateConverter(), throwException, defaultArraySize);
- registerArrayConverter(File.class, new FileConverter(), throwException, defaultArraySize);
- registerArrayConverter(java.sql.Date.class, new SqlDateConverter(), throwException, defaultArraySize);
- registerArrayConverter(java.sql.Time.class, new SqlTimeConverter(), throwException, defaultArraySize);
- registerArrayConverter(Timestamp.class, new SqlTimestampConverter(), throwException, defaultArraySize);
- registerArrayConverter(URL.class, new URLConverter(), throwException, defaultArraySize);
- }
- /**
- * Register a new ArrayConverter with the specified element delegate converter that returns a default array of the specified size in the event of conversion errors.
- *
- * @param componentType The component type of the array
- * @param componentConverter The converter to delegate to for the array elements
- * @param throwException Whether a conversion exception should be thrown or a default value used in the event of a conversion error
- * @param defaultArraySize The size of the default array
- */
- private void registerArrayConverter(final Class<?> componentType, final Converter componentConverter, final boolean throwException, final int defaultArraySize) {
- final Class<?> arrayType = Array.newInstance(componentType, 0).getClass();
- Converter arrayConverter = null;
- if (throwException) {
- arrayConverter = new ArrayConverter(arrayType, componentConverter);
- } else {
- arrayConverter = new ArrayConverter(arrayType, componentConverter, defaultArraySize);
- }
- register(arrayType, arrayConverter);
- }
- /**
- * strictly for convenience since it has same parameter order as Map.put
- */
- private void register(final Class<?> clazz, final Converter converter) {
- register(new ConverterFacade(converter), clazz);
- }
- /**
- * Look up and return any registered {@link Converter} for the specified destination class; if there is no registered Converter, return <code>null</code>.
- *
- * @param clazz Class for which to return a registered Converter
- * @return The registered {@link Converter} or <code>null</code> if not found
- */
- private Converter lookup(final Class<?> clazz) {
- return (converters.get(clazz));
- }
- /**
- * Look up and return any registered {@link Converter} for the specified source and destination class; if there is no registered Converter, return <code>null</code>.
- *
- * @param sourceType Class of the value being converted
- * @param targetType Class of the value to be converted to
- * @return The registered {@link Converter} or <code>null</code> if not found
- */
- private Converter lookup(final Class<?> sourceType, final Class<?> targetType) {
- if (targetType == null) {
- throw new IllegalArgumentException("Target type is missing");
- }
- if (sourceType == null) {
- return lookup(targetType);
- }
- Converter converter = null;
- // Convert --> String
- if (targetType == String.class) {
- converter = lookup(sourceType);
- if (converter == null && (sourceType.isArray() ||
- Collection.class.isAssignableFrom(sourceType))) {
- converter = lookup(String[].class);
- }
- if (converter == null) {
- converter = lookup(String.class);
- }
- return converter;
- }
- // Convert --> String array
- if (targetType == String[].class) {
- if (sourceType.isArray() || Collection.class.isAssignableFrom(sourceType)) {
- converter = lookup(sourceType);
- }
- if (converter == null) {
- converter = lookup(String[].class);
- }
- return converter;
- }
- return lookup(targetType);
- }
- /**
- * Register a custom {@link Converter} for the specified destination <code>Class</code>, replacing any previously registered Converter.
- *
- * @param converter Converter to be registered
- * @param clazz Destination class for conversions performed by this Converter
- */
- private void register(final Converter converter, final Class<?> clazz) {
- converters.put(clazz, converter);
- }
- }
|