From e3d5c2756cddd7d0fed4115467acda22e8e00b21 Mon Sep 17 00:00:00 2001 From: Looly Date: Tue, 7 Jun 2022 09:23:27 +0800 Subject: [PATCH] fix converter --- .../hutool/core/bean/copier/CopyOptions.java | 6 +- .../core/convert/AbstractConverter.java | 2 +- .../java/cn/hutool/core/convert/Convert.java | 10 +- .../cn/hutool/core/convert/Converter.java | 36 +++-- .../core/convert/ConverterRegistry.java | 129 ++++++++---------- .../cn/hutool/core/convert/TypeConverter.java | 24 ---- .../core/convert/impl/ArrayConverter.java | 2 + .../core/convert/impl/BeanConverter.java | 58 ++++---- .../convert/impl/CollectionConverter.java | 68 +++------ .../core/convert/impl/DateConverter.java | 11 +- .../core/convert/impl/EnumConverter.java | 19 +-- .../core/convert/impl/MapConverter.java | 80 +++++------ .../core/convert/impl/NumberConverter.java | 18 +-- .../core/convert/impl/PrimitiveConverter.java | 4 +- .../core/convert/impl/ReferenceConverter.java | 18 +-- .../impl/TemporalAccessorConverter.java | 9 ++ .../core/convert/ConvertToArrayTest.java | 8 +- .../core/convert/ConverterRegistryTest.java | 10 +- .../core/convert/NumberConverterTest.java | 8 +- .../java/cn/hutool/json/JSONConverter.java | 28 ++-- .../{ => cn/hutool/json}/Issue2365Test.java | 2 + 21 files changed, 233 insertions(+), 317 deletions(-) delete mode 100644 hutool-core/src/main/java/cn/hutool/core/convert/TypeConverter.java rename hutool-json/src/test/java/{ => cn/hutool/json}/Issue2365Test.java (95%) diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/copier/CopyOptions.java b/hutool-core/src/main/java/cn/hutool/core/bean/copier/CopyOptions.java index a012ffcc6..e0b5e8f88 100755 --- a/hutool-core/src/main/java/cn/hutool/core/bean/copier/CopyOptions.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/copier/CopyOptions.java @@ -1,7 +1,7 @@ package cn.hutool.core.bean.copier; import cn.hutool.core.convert.Convert; -import cn.hutool.core.convert.TypeConverter; +import cn.hutool.core.convert.Converter; import cn.hutool.core.lang.func.Editor; import cn.hutool.core.lang.func.Func1; import cn.hutool.core.lang.func.LambdaUtil; @@ -70,7 +70,7 @@ public class CopyOptions implements Serializable { /** * 自定义类型转换器,默认使用全局万能转换器转换 */ - protected TypeConverter converter = (type, value) -> + protected Converter converter = (type, value) -> Convert.convertWithCheck(type, value, null, ignoreError); //region create @@ -308,7 +308,7 @@ public class CopyOptions implements Serializable { * @return this * @since 5.8.0 */ - public CopyOptions setConverter(final TypeConverter converter) { + public CopyOptions setConverter(final Converter converter) { this.converter = converter; return this; } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/AbstractConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/AbstractConverter.java index 56c6bc8ec..39e80f59a 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/AbstractConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/AbstractConverter.java @@ -15,7 +15,7 @@ import java.util.Map; * * @author Looly */ -public abstract class AbstractConverter implements TypeConverter, Serializable { +public abstract class AbstractConverter implements Converter, Serializable { private static final long serialVersionUID = 1L; @Override diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/Convert.java b/hutool-core/src/main/java/cn/hutool/core/convert/Convert.java index cdda385cc..4e650eae6 100755 --- a/hutool-core/src/main/java/cn/hutool/core/convert/Convert.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/Convert.java @@ -532,7 +532,11 @@ public class Convert { */ @SuppressWarnings("unchecked") public static > E toEnum(final Class clazz, final Object value, final E defaultValue) { - return (E) (new EnumConverter(clazz)).convertQuietly(value, defaultValue); + try{ + return (E) (new EnumConverter()).convert(clazz, value); + } catch (final Exception ignore){ + return defaultValue; + } } /** @@ -558,7 +562,7 @@ public class Convert { * @since 3.0.8 */ public static Collection toCollection(final Class collectionType, final Class elementType, final Object value) { - return new CollectionConverter(collectionType, elementType).convert(value, null); + return new CollectionConverter().convert(collectionType, elementType, value); } /** @@ -613,7 +617,7 @@ public class Convert { */ @SuppressWarnings("unchecked") public static Map toMap(final Class keyType, final Class valueType, final Object value) { - return (Map) new MapConverter(HashMap.class, keyType, valueType).convert(value, null); + return (Map) new MapConverter().convert(HashMap.class, keyType, valueType, value); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/Converter.java b/hutool-core/src/main/java/cn/hutool/core/convert/Converter.java index e92c4d169..ada1a1d96 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/Converter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/Converter.java @@ -1,23 +1,28 @@ package cn.hutool.core.convert; +import cn.hutool.core.util.ObjUtil; + +import java.lang.reflect.Type; + /** - * 转换器接口,实现类型转换 + * 类型转换接口函数,根据给定的值和目标类型,由用户自定义转换规则。 * - * @param 转换到的目标类型 - * @author Looly + * @author looly + * @since 5.8.0 */ -public interface Converter { +@FunctionalInterface +public interface Converter { /** * 转换为指定类型
* 如果类型无法确定,将读取默认值的类型做为目标类型 * - * @param value 原始值 - * @param defaultValue 默认值 + * @param targetType 目标Type,非泛型类使用 + * @param value 原始值 * @return 转换后的值 - * @throws IllegalArgumentException 无法确定目标类型,且默认值为{@code null},无法确定类型 + * @throws ConvertException 转换无法正常完成或转换异常时抛出此异常 */ - T convert(Object value, T defaultValue) throws IllegalArgumentException; + Object convert(Type targetType, Object value) throws ConvertException; /** * 转换值为指定类型,可选是否不抛异常转换
@@ -25,19 +30,10 @@ public interface Converter { * * @param value 值 * @param defaultValue 默认值 - * @param quietly 是否静默转换,true不抛异常 * @return 转换后的值 - * @since 5.8.0 - * @see #convert(Object, Object) */ - default T convertWithCheck(final Object value, final T defaultValue, final boolean quietly) { - try { - return convert(value, defaultValue); - } catch (final Exception e) { - if(quietly){ - return defaultValue; - } - throw e; - } + @SuppressWarnings("unchecked") + default T convert(final Type targetType, final Object value, final T defaultValue) { + return ObjUtil.defaultIfNull((T)convert(targetType, value), defaultValue); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java b/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java index 79e169b49..9aa235f37 100755 --- a/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java @@ -36,7 +36,6 @@ import cn.hutool.core.convert.impl.UUIDConverter; import cn.hutool.core.date.DateTime; import cn.hutool.core.lang.Opt; import cn.hutool.core.reflect.ClassUtil; -import cn.hutool.core.reflect.ConstructorUtil; import cn.hutool.core.reflect.TypeReference; import cn.hutool.core.reflect.TypeUtil; import cn.hutool.core.util.ObjUtil; @@ -97,11 +96,11 @@ public class ConverterRegistry implements Serializable { /** * 默认类型转换器 */ - private Map> defaultConverterMap; + private Map defaultConverterMap; /** * 用户自定义类型转换器 */ - private volatile Map> customConverterMap; + private volatile Map customConverterMap; /** * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载 @@ -140,23 +139,12 @@ public class ConverterRegistry implements Serializable { if (null != type) { putCustom(type, converter); } - } catch (final Exception e) { + } catch (final Exception ignore) { // 忽略注册失败的 } }); } - /** - * 登记自定义转换器 - * - * @param type 转换的目标类型 - * @param converterClass 转换器类,必须有默认构造方法 - * @return ConverterRegistry - */ - public ConverterRegistry putCustom(final Type type, final Class> converterClass) { - return putCustom(type, ConstructorUtil.newInstance(converterClass)); - } - /** * 登记自定义转换器 * @@ -164,7 +152,7 @@ public class ConverterRegistry implements Serializable { * @param converter 转换器 * @return ConverterRegistry */ - public ConverterRegistry putCustom(final Type type, final Converter converter) { + public ConverterRegistry putCustom(final Type type, final Converter converter) { if (null == customConverterMap) { synchronized (this) { if (null == customConverterMap) { @@ -179,13 +167,12 @@ public class ConverterRegistry implements Serializable { /** * 获得转换器
* - * @param 转换的目标类型 * @param type 类型 * @param isCustomFirst 是否自定义转换器优先 * @return 转换器 */ - public Converter getConverter(final Type type, final boolean isCustomFirst) { - Converter converter; + public Converter getConverter(final Type type, final boolean isCustomFirst) { + Converter converter; if (isCustomFirst) { converter = this.getCustomConverter(type); if (null == converter) { @@ -203,25 +190,21 @@ public class ConverterRegistry implements Serializable { /** * 获得默认转换器 * - * @param 转换的目标类型(转换器转换到的类型) * @param type 类型 * @return 转换器 */ - @SuppressWarnings("unchecked") - public Converter getDefaultConverter(final Type type) { - return (null == defaultConverterMap) ? null : (Converter) defaultConverterMap.get(type); + public Converter getDefaultConverter(final Type type) { + return (null == defaultConverterMap) ? null : defaultConverterMap.get(type); } /** * 获得自定义转换器 * - * @param 转换的目标类型(转换器转换到的类型) * @param type 类型 * @return 转换器 */ - @SuppressWarnings("unchecked") - public Converter getCustomConverter(final Type type) { - return (null == customConverterMap) ? null : (Converter) customConverterMap.get(type); + public Converter getCustomConverter(final Type type) { + return (null == customConverterMap) ? null : customConverterMap.get(type); } /** @@ -253,12 +236,11 @@ public class ConverterRegistry implements Serializable { } // 标准转换器 - final Converter converter = getConverter(type, isCustomFirst); + final Converter converter = getConverter(type, isCustomFirst); if (null != converter) { - return converter.convert(value, defaultValue); + return converter.convert(type, value, defaultValue); } - Class rowType = (Class) TypeUtil.getClass(type); if (null == rowType) { if (null != defaultValue) { @@ -277,7 +259,7 @@ public class ConverterRegistry implements Serializable { // 尝试转Bean if (BeanUtil.isBean(rowType)) { - return new BeanConverter(type).convert(value, defaultValue); + return (T) new BeanConverter().convert(type, value); } // 无法转换 @@ -339,14 +321,14 @@ public class ConverterRegistry implements Serializable { // 集合转换(不可以默认强转) if (Collection.class.isAssignableFrom(rowType)) { - final CollectionConverter collectionConverter = new CollectionConverter(type); - return (T) collectionConverter.convert(value, (Collection) defaultValue); + final CollectionConverter collectionConverter = new CollectionConverter(); + return (T) collectionConverter.convert(type, value, (Collection) defaultValue); } // Map类型(不可以默认强转) if (Map.class.isAssignableFrom(rowType)) { - final MapConverter mapConverter = new MapConverter(type); - return (T) mapConverter.convert(value, (Map) defaultValue); + final MapConverter mapConverter = new MapConverter(); + return (T) mapConverter.convert(type, value, (Map) defaultValue); } // 默认强转 @@ -356,13 +338,12 @@ public class ConverterRegistry implements Serializable { // 枚举转换 if (rowType.isEnum()) { - return (T) new EnumConverter(rowType).convert(value, defaultValue); + return EnumConverter.INSTANCE.convert(type, value, defaultValue); } // 数组转换 if (rowType.isArray()) { - final ArrayConverter arrayConverter = new ArrayConverter(rowType); - return (T) arrayConverter.convert(value, defaultValue); + return ArrayConverter.INSTANCE.convert(type, value, defaultValue); } // 表示非需要特殊转换的对象 @@ -378,32 +359,32 @@ public class ConverterRegistry implements Serializable { defaultConverterMap = new ConcurrentHashMap<>(); // 原始类型转换器 - defaultConverterMap.put(int.class, new PrimitiveConverter(int.class)); - defaultConverterMap.put(long.class, new PrimitiveConverter(long.class)); - defaultConverterMap.put(byte.class, new PrimitiveConverter(byte.class)); - defaultConverterMap.put(short.class, new PrimitiveConverter(short.class)); - defaultConverterMap.put(float.class, new PrimitiveConverter(float.class)); - defaultConverterMap.put(double.class, new PrimitiveConverter(double.class)); - defaultConverterMap.put(char.class, new PrimitiveConverter(char.class)); - defaultConverterMap.put(boolean.class, new PrimitiveConverter(boolean.class)); + defaultConverterMap.put(int.class, PrimitiveConverter.INSTANCE); + defaultConverterMap.put(long.class, PrimitiveConverter.INSTANCE); + defaultConverterMap.put(byte.class, PrimitiveConverter.INSTANCE); + defaultConverterMap.put(short.class, PrimitiveConverter.INSTANCE); + defaultConverterMap.put(float.class, PrimitiveConverter.INSTANCE); + defaultConverterMap.put(double.class, PrimitiveConverter.INSTANCE); + defaultConverterMap.put(char.class, PrimitiveConverter.INSTANCE); + defaultConverterMap.put(boolean.class, PrimitiveConverter.INSTANCE); // 包装类转换器 - defaultConverterMap.put(Number.class, new NumberConverter()); - defaultConverterMap.put(Integer.class, new NumberConverter(Integer.class)); - defaultConverterMap.put(AtomicInteger.class, new NumberConverter(AtomicInteger.class));// since 3.0.8 - defaultConverterMap.put(Long.class, new NumberConverter(Long.class)); - defaultConverterMap.put(LongAdder.class, new NumberConverter(LongAdder.class)); - defaultConverterMap.put(AtomicLong.class, new NumberConverter(AtomicLong.class));// since 3.0.8 - defaultConverterMap.put(Byte.class, new NumberConverter(Byte.class)); - defaultConverterMap.put(Short.class, new NumberConverter(Short.class)); - defaultConverterMap.put(Float.class, new NumberConverter(Float.class)); - defaultConverterMap.put(Double.class, new NumberConverter(Double.class)); - defaultConverterMap.put(DoubleAdder.class, new NumberConverter(DoubleAdder.class)); + defaultConverterMap.put(Number.class, NumberConverter.INSTANCE); + defaultConverterMap.put(Integer.class, NumberConverter.INSTANCE); + defaultConverterMap.put(AtomicInteger.class, NumberConverter.INSTANCE);// since 3.0.8 + defaultConverterMap.put(Long.class, NumberConverter.INSTANCE); + defaultConverterMap.put(LongAdder.class, NumberConverter.INSTANCE); + defaultConverterMap.put(AtomicLong.class, NumberConverter.INSTANCE);// since 3.0.8 + defaultConverterMap.put(Byte.class, NumberConverter.INSTANCE); + defaultConverterMap.put(Short.class, NumberConverter.INSTANCE); + defaultConverterMap.put(Float.class, NumberConverter.INSTANCE); + defaultConverterMap.put(Double.class, NumberConverter.INSTANCE); + defaultConverterMap.put(DoubleAdder.class, NumberConverter.INSTANCE); defaultConverterMap.put(Character.class, new CharacterConverter()); defaultConverterMap.put(Boolean.class, new BooleanConverter()); defaultConverterMap.put(AtomicBoolean.class, new AtomicBooleanConverter());// since 3.0.8 - defaultConverterMap.put(BigDecimal.class, new NumberConverter(BigDecimal.class)); - defaultConverterMap.put(BigInteger.class, new NumberConverter(BigInteger.class)); + defaultConverterMap.put(BigDecimal.class, NumberConverter.INSTANCE); + defaultConverterMap.put(BigInteger.class, NumberConverter.INSTANCE); defaultConverterMap.put(CharSequence.class, new StringConverter()); defaultConverterMap.put(String.class, new StringConverter()); @@ -413,27 +394,27 @@ public class ConverterRegistry implements Serializable { // 日期时间 defaultConverterMap.put(Calendar.class, new CalendarConverter()); - defaultConverterMap.put(java.util.Date.class, new DateConverter(java.util.Date.class)); - defaultConverterMap.put(DateTime.class, new DateConverter(DateTime.class)); - defaultConverterMap.put(java.sql.Date.class, new DateConverter(java.sql.Date.class)); - defaultConverterMap.put(java.sql.Time.class, new DateConverter(java.sql.Time.class)); - defaultConverterMap.put(java.sql.Timestamp.class, new DateConverter(java.sql.Timestamp.class)); + defaultConverterMap.put(java.util.Date.class, DateConverter.INSTANCE); + defaultConverterMap.put(DateTime.class, DateConverter.INSTANCE); + defaultConverterMap.put(java.sql.Date.class, DateConverter.INSTANCE); + defaultConverterMap.put(java.sql.Time.class, DateConverter.INSTANCE); + defaultConverterMap.put(java.sql.Timestamp.class, DateConverter.INSTANCE); // 日期时间 JDK8+(since 5.0.0) - defaultConverterMap.put(TemporalAccessor.class, new TemporalAccessorConverter(Instant.class)); - defaultConverterMap.put(Instant.class, new TemporalAccessorConverter(Instant.class)); - defaultConverterMap.put(LocalDateTime.class, new TemporalAccessorConverter(LocalDateTime.class)); - defaultConverterMap.put(LocalDate.class, new TemporalAccessorConverter(LocalDate.class)); - defaultConverterMap.put(LocalTime.class, new TemporalAccessorConverter(LocalTime.class)); - defaultConverterMap.put(ZonedDateTime.class, new TemporalAccessorConverter(ZonedDateTime.class)); - defaultConverterMap.put(OffsetDateTime.class, new TemporalAccessorConverter(OffsetDateTime.class)); - defaultConverterMap.put(OffsetTime.class, new TemporalAccessorConverter(OffsetTime.class)); + defaultConverterMap.put(TemporalAccessor.class, TemporalAccessorConverter.INSTANCE); + defaultConverterMap.put(Instant.class, TemporalAccessorConverter.INSTANCE); + defaultConverterMap.put(LocalDateTime.class, TemporalAccessorConverter.INSTANCE); + defaultConverterMap.put(LocalDate.class, TemporalAccessorConverter.INSTANCE); + defaultConverterMap.put(LocalTime.class, TemporalAccessorConverter.INSTANCE); + defaultConverterMap.put(ZonedDateTime.class, TemporalAccessorConverter.INSTANCE); + defaultConverterMap.put(OffsetDateTime.class, TemporalAccessorConverter.INSTANCE); + defaultConverterMap.put(OffsetTime.class, TemporalAccessorConverter.INSTANCE); defaultConverterMap.put(Period.class, new PeriodConverter()); defaultConverterMap.put(Duration.class, new DurationConverter()); // Reference - defaultConverterMap.put(WeakReference.class, new ReferenceConverter(WeakReference.class));// since 3.0.8 - defaultConverterMap.put(SoftReference.class, new ReferenceConverter(SoftReference.class));// since 3.0.8 + defaultConverterMap.put(WeakReference.class, ReferenceConverter.INSTANCE);// since 3.0.8 + defaultConverterMap.put(SoftReference.class, ReferenceConverter.INSTANCE);// since 3.0.8 defaultConverterMap.put(AtomicReference.class, new AtomicReferenceConverter());// since 3.0.8 //AtomicXXXArray,since 5.4.5 diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/TypeConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/TypeConverter.java deleted file mode 100644 index 8754bd396..000000000 --- a/hutool-core/src/main/java/cn/hutool/core/convert/TypeConverter.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.hutool.core.convert; - -import java.lang.reflect.Type; - -/** - * 类型转换接口函数,根据给定的值和目标类型,由用户自定义转换规则。 - * - * @author looly - * @since 5.8.0 - */ -@FunctionalInterface -public interface TypeConverter { - - /** - * 转换为指定类型
- * 如果类型无法确定,将读取默认值的类型做为目标类型 - * - * @param targetType 目标Type,非泛型类使用 - * @param value 原始值 - * @return 转换后的值 - * @throws ConvertException 转换无法正常完成或转换异常时抛出此异常 - */ - Object convert(Type targetType, Object value) throws ConvertException; -} diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/ArrayConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/ArrayConverter.java index 7af729cd8..739e372e3 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/ArrayConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/ArrayConverter.java @@ -24,6 +24,8 @@ import java.util.List; public class ArrayConverter extends AbstractConverter { private static final long serialVersionUID = 1L; + public static final ArrayConverter INSTANCE = new ArrayConverter(); + /** * 是否忽略元素转换错误 */ diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/BeanConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/BeanConverter.java index 4721850ce..44cc9b0bb 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/BeanConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/BeanConverter.java @@ -4,13 +4,15 @@ import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.copier.BeanCopier; import cn.hutool.core.bean.copier.CopyOptions; import cn.hutool.core.bean.copier.ValueProvider; -import cn.hutool.core.convert.AbstractConverter; import cn.hutool.core.convert.ConvertException; +import cn.hutool.core.convert.Converter; +import cn.hutool.core.lang.Assert; import cn.hutool.core.map.MapProxy; import cn.hutool.core.reflect.ConstructorUtil; import cn.hutool.core.reflect.TypeUtil; import cn.hutool.core.util.ObjUtil; +import java.io.Serializable; import java.lang.reflect.Type; import java.util.Map; @@ -22,63 +24,57 @@ import java.util.Map; * ValueProvider =》 Bean * * - * @param Bean类型 * @author Looly * @since 4.0.2 */ -public class BeanConverter extends AbstractConverter { +public class BeanConverter implements Converter, Serializable { private static final long serialVersionUID = 1L; - private final Type beanType; - private final Class beanClass; private final CopyOptions copyOptions; /** - * 构造,默认转换选项,注入失败的字段忽略 - * - * @param beanType 转换成的目标Bean类型 + * 构造 */ - public BeanConverter(final Type beanType) { - this(beanType, CopyOptions.create().setIgnoreError(true)); - } - - /** - * 构造,默认转换选项,注入失败的字段忽略 - * - * @param beanClass 转换成的目标Bean类 - */ - public BeanConverter(final Class beanClass) { - this(beanClass, CopyOptions.create().setIgnoreError(true)); + public BeanConverter() { + this(CopyOptions.create().setIgnoreError(true)); } /** * 构造 * - * @param beanType 转换成的目标Bean类 * @param copyOptions Bean转换选项参数 */ - @SuppressWarnings("unchecked") - public BeanConverter(final Type beanType, final CopyOptions copyOptions) { - this.beanType = beanType; - this.beanClass = (Class) TypeUtil.getClass(beanType); + public BeanConverter(final CopyOptions copyOptions) { this.copyOptions = copyOptions; } @Override - protected T convertInternal(final Class targetClass, final Object value) { - if(value instanceof Map || + public Object convert(Type targetType, Object value) throws ConvertException { + Assert.notNull(targetType); + if (null == value) { + return null; + } + + Class targetClass = TypeUtil.getClass(targetType); + Assert.notNull(targetClass, "Target type is not a class!"); + + return convertInternal(targetType, targetClass, value); + } + + private Object convertInternal(final Type targetType, final Class targetClass, final Object value) { + if (value instanceof Map || value instanceof ValueProvider || BeanUtil.isBean(value.getClass())) { - if(value instanceof Map && this.beanClass.isInterface()) { + if (value instanceof Map && targetClass.isInterface()) { // 将Map动态代理为Bean - return MapProxy.create((Map)value).toProxyBean(this.beanClass); + return MapProxy.create((Map) value).toProxyBean(targetClass); } //限定被转换对象类型 - return BeanCopier.create(value, ConstructorUtil.newInstanceIfPossible(this.beanClass), this.beanType, this.copyOptions).copy(); - } else if(value instanceof byte[]){ + return BeanCopier.create(value, ConstructorUtil.newInstanceIfPossible(targetClass), targetType, this.copyOptions).copy(); + } else if (value instanceof byte[]) { // 尝试反序列化 - return ObjUtil.deserialize((byte[])value); + return ObjUtil.deserialize((byte[]) value); } throw new ConvertException("Unsupported source type: {}", value.getClass()); diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/CollectionConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/CollectionConverter.java index 9de4b900f..65975242d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/CollectionConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/CollectionConverter.java @@ -1,7 +1,8 @@ package cn.hutool.core.convert.impl; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.convert.TypeConverter; +import cn.hutool.core.convert.Converter; +import cn.hutool.core.reflect.TypeReference; import cn.hutool.core.reflect.TypeUtil; import java.lang.reflect.Type; @@ -13,64 +14,27 @@ import java.util.Collection; * @author Looly * @since 3.0.8 */ -public class CollectionConverter implements TypeConverter { - - /** 集合类型 */ - private final Type collectionType; - /** 集合元素类型 */ - private final Type elementType; - - /** - * 构造,默认集合类型使用{@link Collection} - */ - public CollectionConverter() { - this(Collection.class); - } - - // ---------------------------------------------------------------------------------------------- Constractor start - /** - * 构造 - * - * @param collectionType 集合类型 - */ - public CollectionConverter(final Type collectionType) { - this(collectionType, TypeUtil.getTypeArgument(collectionType)); - } - - /** - * 构造 - * - * @param collectionType 集合类型 - */ - public CollectionConverter(final Class collectionType) { - this(collectionType, TypeUtil.getTypeArgument(collectionType)); - } - - /** - * 构造 - * - * @param collectionType 集合类型 - * @param elementType 集合元素类型 - */ - public CollectionConverter(final Type collectionType, final Type elementType) { - this.collectionType = collectionType; - this.elementType = elementType; - } - // ---------------------------------------------------------------------------------------------- Constractor end +public class CollectionConverter implements Converter { @Override - public Collection convert(final Type targetType, final Object value) { - return convertInternal(value); + public Collection convert(Type targetType, final Object value) { + if (targetType instanceof TypeReference) { + targetType = ((TypeReference) targetType).getType(); + } + + return convert(targetType, TypeUtil.getTypeArgument(targetType), value); } /** - * 内部转换 + * 转换 * - * @param value 值 + * @param collectionType 集合类型 + * @param elementType 集合中元素类型 + * @param value 被转换的值 * @return 转换后的集合对象 */ - protected Collection convertInternal(final Object value) { - final Collection collection = CollUtil.create(TypeUtil.getClass(this.collectionType)); - return CollUtil.addAll(collection, value, this.elementType); + public Collection convert(final Type collectionType, final Type elementType, final Object value) { + final Collection collection = CollUtil.create(TypeUtil.getClass(collectionType)); + return CollUtil.addAll(collection, value, elementType); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/DateConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/DateConverter.java index 018286cff..e6ee1a5a7 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/DateConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/DateConverter.java @@ -17,15 +17,24 @@ import java.util.Calendar; public class DateConverter extends AbstractConverter { private static final long serialVersionUID = 1L; + public static final DateConverter INSTANCE = new DateConverter(); + /** * 日期格式化 */ private String format; + /** + * 构造 + */ + public DateConverter() { + this(null); + } + /** * 构造 * - * @param format 日期格式 + * @param format 日期格式 */ public DateConverter(final String format) { this.format = format; diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/EnumConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/EnumConverter.java index bfd277450..245a35bf3 100755 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/EnumConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/EnumConverter.java @@ -25,32 +25,23 @@ import java.util.stream.Collectors; public class EnumConverter extends AbstractConverter { private static final long serialVersionUID = 1L; + public static final EnumConverter INSTANCE = new EnumConverter(); + private static final WeakConcurrentMap, Map, Method>> VALUE_OF_METHOD_CACHE = new WeakConcurrentMap<>(); - private final Class enumClass; - - /** - * 构造 - * - * @param enumClass 转换成的目标Enum类 - */ - public EnumConverter(final Class enumClass) { - this.enumClass = enumClass; - } - @Override protected Object convertInternal(final Class targetClass, final Object value) { - Enum enumValue = tryConvertEnum(value, this.enumClass); + Enum enumValue = tryConvertEnum(value, targetClass); if (null == enumValue && false == value instanceof String) { // 最后尝试先将value转String,再valueOf转换 - enumValue = Enum.valueOf(this.enumClass, convertToStr(value)); + enumValue = Enum.valueOf((Class) targetClass, convertToStr(value)); } if (null != enumValue) { return enumValue; } - throw new ConvertException("Can not convert {} to {}", value, this.enumClass); + throw new ConvertException("Can not convert {} to {}", value, targetClass); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/MapConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/MapConverter.java index dff43fd2d..08d3b50de 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/MapConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/MapConverter.java @@ -1,12 +1,15 @@ package cn.hutool.core.convert.impl; import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.convert.AbstractConverter; +import cn.hutool.core.convert.ConvertException; import cn.hutool.core.convert.ConverterRegistry; +import cn.hutool.core.convert.Converter; import cn.hutool.core.map.MapUtil; -import cn.hutool.core.text.StrUtil; +import cn.hutool.core.reflect.TypeReference; import cn.hutool.core.reflect.TypeUtil; +import cn.hutool.core.text.StrUtil; +import java.io.Serializable; import java.lang.reflect.Type; import java.util.Map; import java.util.Objects; @@ -17,60 +20,56 @@ import java.util.Objects; * @author Looly * @since 3.0.8 */ -public class MapConverter extends AbstractConverter { +public class MapConverter implements Converter, Serializable { private static final long serialVersionUID = 1L; - /** Map类型 */ - private final Type mapType; - /** 键类型 */ - private final Type keyType; - /** 值类型 */ - private final Type valueType; - - /** - * 构造,Map的key和value泛型类型自动获取 - * - * @param mapType Map类型 - */ - public MapConverter(final Type mapType) { - this(mapType, TypeUtil.getTypeArgument(mapType, 0), TypeUtil.getTypeArgument(mapType, 1)); - } - /** * 构造 - * - * @param mapType Map类型 - * @param keyType 键类型 - * @param valueType 值类型 */ - public MapConverter(final Type mapType, final Type keyType, final Type valueType) { - this.mapType = mapType; - this.keyType = keyType; - this.valueType = valueType; + public MapConverter() { } @Override - @SuppressWarnings({ "rawtypes", "unchecked" }) - protected Map convertInternal(final Class targetClass, final Object value) { + public Object convert(Type targetType, Object value) throws ConvertException { + if (targetType instanceof TypeReference) { + targetType = ((TypeReference) targetType).getType(); + } + final Type keyType = TypeUtil.getTypeArgument(targetType, 0); + final Type valueType = TypeUtil.getTypeArgument(targetType, 1); + + return convert(targetType, keyType, valueType, value); + } + + /** + * 转换对象为指定键值类型的指定类型Map + * + * @param targetType 目标的Map类型 + * @param keyType 键类型 + * @param valueType 值类型 + * @param value 被转换的值 + * @return 转换后的Map + */ + @SuppressWarnings("rawtypes") + public Map convert(final Type targetType, final Type keyType, final Type valueType, final Object value) { Map map; if (value instanceof Map) { final Class valueClass = value.getClass(); - if(valueClass.equals(this.mapType)){ + if (valueClass.equals(targetType)) { final Type[] typeArguments = TypeUtil.getTypeArguments(valueClass); if (null != typeArguments // && 2 == typeArguments.length// - && Objects.equals(this.keyType, typeArguments[0]) // - && Objects.equals(this.valueType, typeArguments[1])) { + && Objects.equals(keyType, typeArguments[0]) // + && Objects.equals(valueType, typeArguments[1])) { //对于键值对类型一致的Map对象,不再做转换,直接返回原对象 return (Map) value; } } - map = MapUtil.createMap(TypeUtil.getClass(this.mapType)); - convertMapToMap((Map) value, map); + map = MapUtil.createMap(TypeUtil.getClass(targetType)); + convertMapToMap(keyType, valueType, (Map) value, map); } else if (BeanUtil.isBean(value.getClass())) { map = BeanUtil.beanToMap(value); // 二次转换,转换键值类型 - map = convertInternal(targetClass, map); + map = convert(targetType, keyType, valueType, map); } else { throw new UnsupportedOperationException(StrUtil.format("Unsupport toMap value type: {}", value.getClass().getName())); } @@ -80,14 +79,15 @@ public class MapConverter extends AbstractConverter { /** * Map转Map * - * @param srcMap 源Map + * @param srcMap 源Map * @param targetMap 目标Map */ - private void convertMapToMap(final Map srcMap, final Map targetMap) { + @SuppressWarnings({"rawtypes", "unchecked"}) + private void convertMapToMap(Type keyType, Type valueType, final Map srcMap, final Map targetMap) { final ConverterRegistry convert = ConverterRegistry.getInstance(); - srcMap.forEach((key, value)->{ - key = TypeUtil.isUnknown(this.keyType) ? key : convert.convert(this.keyType, key); - value = TypeUtil.isUnknown(this.valueType) ? value : convert.convert(this.valueType, value); + srcMap.forEach((key, value) -> { + key = TypeUtil.isUnknown(keyType) ? key : convert.convert(keyType, key); + value = TypeUtil.isUnknown(valueType) ? value : convert.convert(valueType, value); targetMap.put(key, value); }); } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/NumberConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/NumberConverter.java index 2858fc453..1f1db1f61 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/NumberConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/NumberConverter.java @@ -39,24 +39,12 @@ import java.util.function.Function; public class NumberConverter extends AbstractConverter { private static final long serialVersionUID = 1L; - private final Class targetType; - - public NumberConverter() { - this.targetType = Number.class; - } - - /** - * 构造
- * - * @param clazz 需要转换的数字类型,默认 {@link Number} - */ - public NumberConverter(final Class clazz) { - this.targetType = (null == clazz) ? Number.class : clazz; - } + public static final NumberConverter INSTANCE = new NumberConverter(); + @SuppressWarnings("unchecked") @Override protected Number convertInternal(final Class targetClass, final Object value) { - return convert(value, this.targetType, this::convertToStr); + return convert(value, (Class) targetClass, this::convertToStr); } @Override diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/PrimitiveConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/PrimitiveConverter.java index 7f905c69b..e00aa4fe7 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/PrimitiveConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/PrimitiveConverter.java @@ -3,8 +3,8 @@ package cn.hutool.core.convert.impl; import cn.hutool.core.convert.AbstractConverter; import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.ConvertException; -import cn.hutool.core.util.ObjUtil; import cn.hutool.core.text.StrUtil; +import cn.hutool.core.util.ObjUtil; import java.util.function.Function; @@ -27,6 +27,8 @@ import java.util.function.Function; public class PrimitiveConverter extends AbstractConverter { private static final long serialVersionUID = 1L; + public static final PrimitiveConverter INSTANCE = new PrimitiveConverter(); + /** * 构造
* diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/ReferenceConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/ReferenceConverter.java index 53ef0d1bc..8899f5d5e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/ReferenceConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/ReferenceConverter.java @@ -20,15 +20,7 @@ import java.lang.reflect.Type; public class ReferenceConverter extends AbstractConverter { private static final long serialVersionUID = 1L; - private final Class targetType; - - /** - * 构造 - * @param targetType {@link Reference}实现类型 - */ - public ReferenceConverter(final Class targetType) { - this.targetType = targetType; - } + public static ReferenceConverter INSTANCE = new ReferenceConverter(); @SuppressWarnings("unchecked") @Override @@ -36,7 +28,7 @@ public class ReferenceConverter extends AbstractConverter { //尝试将值转换为Reference泛型的类型 Object targetValue = null; - final Type paramType = TypeUtil.getTypeArgument(targetType); + final Type paramType = TypeUtil.getTypeArgument(targetClass); if(false == TypeUtil.isUnknown(paramType)){ targetValue = ConverterRegistry.getInstance().convert(paramType, value); } @@ -44,13 +36,13 @@ public class ReferenceConverter extends AbstractConverter { targetValue = value; } - if(this.targetType == WeakReference.class){ + if(targetClass == WeakReference.class){ return new WeakReference(targetValue); - }else if(this.targetType == SoftReference.class){ + }else if(targetClass == SoftReference.class){ return new SoftReference(targetValue); } - throw new UnsupportedOperationException(StrUtil.format("Unsupport Reference type: {}", this.targetType.getName())); + throw new UnsupportedOperationException(StrUtil.format("Unsupport Reference type: {}", targetClass.getName())); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/TemporalAccessorConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/TemporalAccessorConverter.java index 99a37c6e4..94da2e376 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/TemporalAccessorConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/TemporalAccessorConverter.java @@ -40,11 +40,20 @@ import java.util.Objects; public class TemporalAccessorConverter extends AbstractConverter { private static final long serialVersionUID = 1L; + public static final TemporalAccessorConverter INSTANCE = new TemporalAccessorConverter(); + /** * 日期格式化 */ private String format; + /** + * 构造 + */ + public TemporalAccessorConverter() { + this(null); + } + /** * 构造 * diff --git a/hutool-core/src/test/java/cn/hutool/core/convert/ConvertToArrayTest.java b/hutool-core/src/test/java/cn/hutool/core/convert/ConvertToArrayTest.java index 0e96c964d..44fa3b833 100644 --- a/hutool-core/src/test/java/cn/hutool/core/convert/ConvertToArrayTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/convert/ConvertToArrayTest.java @@ -39,8 +39,8 @@ public class ConvertToArrayTest { public void toIntArrayTestIgnoreComponentErrorTest() { final String[] b = { "a", "1" }; - final ArrayConverter arrayConverter = new ArrayConverter(Integer[].class, true); - final Integer[] integerArray = (Integer[]) arrayConverter.convert(b, null); + final ArrayConverter arrayConverter = new ArrayConverter(true); + final Integer[] integerArray = arrayConverter.convert(Integer[].class, b, null); Assert.assertArrayEquals(integerArray, new Integer[]{null, 1}); } @@ -89,8 +89,8 @@ public class ConvertToArrayTest { //字符串转数组 final String arrayStr = "1,2,3,4,5"; //获取Converter类的方法2,自己实例化相应Converter对象 - final ArrayConverter c3 = new ArrayConverter(int[].class); - final int[] result3 = (int[]) c3.convert(arrayStr, null); + final ArrayConverter c3 = new ArrayConverter(); + final int[] result3 = c3.convert(int[].class, arrayStr, null); Assert.assertArrayEquals(new int[]{1,2,3,4,5}, result3); } diff --git a/hutool-core/src/test/java/cn/hutool/core/convert/ConverterRegistryTest.java b/hutool-core/src/test/java/cn/hutool/core/convert/ConverterRegistryTest.java index 7fe2c7af3..4e96e9570 100644 --- a/hutool-core/src/test/java/cn/hutool/core/convert/ConverterRegistryTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/convert/ConverterRegistryTest.java @@ -3,6 +3,8 @@ package cn.hutool.core.convert; import org.junit.Assert; import org.junit.Test; +import java.lang.reflect.Type; + /** * ConverterRegistry 单元测试 * @author Looly @@ -12,7 +14,7 @@ public class ConverterRegistryTest { @Test public void getConverterTest() { - final Converter converter = ConverterRegistry.getInstance().getConverter(CharSequence.class, false); + final Converter converter = ConverterRegistry.getInstance().getConverter(CharSequence.class, false); Assert.assertNotNull(converter); } @@ -26,14 +28,14 @@ public class ConverterRegistryTest { //此处做为示例自定义CharSequence转换,因为Hutool中已经提供CharSequence转换,请尽量不要替换 //替换可能引发关联转换异常(例如覆盖CharSequence转换会影响全局) - converterRegistry.putCustom(CharSequence.class, CustomConverter.class); + converterRegistry.putCustom(CharSequence.class, new CustomConverter()); result = converterRegistry.convert(CharSequence.class, a); Assert.assertEquals("Custom: 454553", result); } - public static class CustomConverter implements Converter{ + public static class CustomConverter implements Converter{ @Override - public CharSequence convert(final Object value, final CharSequence defaultValue) throws IllegalArgumentException { + public Object convert(Type targetType, Object value) throws ConvertException { return "Custom: " + value.toString(); } } diff --git a/hutool-core/src/test/java/cn/hutool/core/convert/NumberConverterTest.java b/hutool-core/src/test/java/cn/hutool/core/convert/NumberConverterTest.java index 795d79fa1..3ed82e6a9 100644 --- a/hutool-core/src/test/java/cn/hutool/core/convert/NumberConverterTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/convert/NumberConverterTest.java @@ -8,15 +8,15 @@ public class NumberConverterTest { @Test public void toDoubleTest(){ - final NumberConverter numberConverter = new NumberConverter(Double.class); - final Number convert = numberConverter.convert("1,234.55", null); + final NumberConverter numberConverter = new NumberConverter(); + final Number convert = numberConverter.convert(Double.class, "1,234.55", null); Assert.assertEquals(1234.55D, convert); } @Test public void toIntegerTest(){ - final NumberConverter numberConverter = new NumberConverter(Integer.class); - final Number convert = numberConverter.convert("1,234.55", null); + final NumberConverter numberConverter = new NumberConverter(); + final Number convert = numberConverter.convert(Integer.class, "1,234.55", null); Assert.assertEquals(1234, convert); } } diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONConverter.java b/hutool-json/src/main/java/cn/hutool/json/JSONConverter.java index 126df29f3..4efb2a8e6 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONConverter.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONConverter.java @@ -24,14 +24,21 @@ import java.util.List; * @author looly * @since 4.2.2 */ -public class JSONConverter implements Converter { +public class JSONConverter implements Converter { + + public static JSONConverter INSTANCE = new JSONConverter(); static { // 注册到转换中心 final ConverterRegistry registry = ConverterRegistry.getInstance(); - registry.putCustom(JSON.class, JSONConverter.class); - registry.putCustom(JSONObject.class, JSONConverter.class); - registry.putCustom(JSONArray.class, JSONConverter.class); + registry.putCustom(JSON.class, INSTANCE); + registry.putCustom(JSONObject.class, INSTANCE); + registry.putCustom(JSONArray.class, INSTANCE); + } + + @Override + public Object convert(Type targetType, Object value) throws ConvertException { + return JSONUtil.parse(value); } /** @@ -42,7 +49,7 @@ public class JSONConverter implements Converter { * @return 数组对象 */ protected static Object toArray(final JSONArray jsonArray, final Class arrayClass) { - return new ArrayConverter(arrayClass).convert(jsonArray, null); + return ArrayConverter.INSTANCE.convert(arrayClass, jsonArray, null); } /** @@ -124,9 +131,9 @@ public class JSONConverter implements Converter { if(value instanceof JSONGetter && targetType instanceof Class && BeanUtil.hasSetter((Class) targetType)){ final JSONConfig config = ((JSONGetter) value).getConfig(); - final Converter converter = new BeanConverter<>(targetType, - InternalJSONUtil.toCopyOptions(config).setIgnoreError(ignoreError)); - return converter.convertWithCheck(value, null, ignoreError); + final Converter converter = new BeanConverter(InternalJSONUtil.toCopyOptions(config).setIgnoreError(ignoreError)); + return ignoreError ? converter.convert(targetType, value, null) + : (T) converter.convert(targetType, value); } } @@ -144,9 +151,4 @@ public class JSONConverter implements Converter { return targetValue; } - - @Override - public JSON convert(final Object value, final JSON defaultValue) throws IllegalArgumentException { - return JSONUtil.parse(value); - } } diff --git a/hutool-json/src/test/java/Issue2365Test.java b/hutool-json/src/test/java/cn/hutool/json/Issue2365Test.java similarity index 95% rename from hutool-json/src/test/java/Issue2365Test.java rename to hutool-json/src/test/java/cn/hutool/json/Issue2365Test.java index 2b16fea50..c5785d7c5 100644 --- a/hutool-json/src/test/java/Issue2365Test.java +++ b/hutool-json/src/test/java/cn/hutool/json/Issue2365Test.java @@ -1,3 +1,5 @@ +package cn.hutool.json; + import cn.hutool.json.JSONUtil; import lombok.Data; import org.junit.Assert;