fix converter

This commit is contained in:
Looly 2022-06-07 09:23:27 +08:00
parent 1473d4625f
commit e3d5c2756c
21 changed files with 233 additions and 317 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -532,7 +532,11 @@ public class Convert {
*/
@SuppressWarnings("unchecked")
public static <E extends Enum<E>> E toEnum(final Class<E> 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 <K, V> Map<K, V> toMap(final Class<K> keyType, final Class<V> valueType, final Object value) {
return (Map<K, V>) new MapConverter(HashMap.class, keyType, valueType).convert(value, null);
return (Map<K, V>) new MapConverter().convert(HashMap.class, keyType, valueType, value);
}
/**

View File

@ -1,23 +1,28 @@
package cn.hutool.core.convert;
import cn.hutool.core.util.ObjUtil;
import java.lang.reflect.Type;
/**
* 转换器接口实现类型转换
* 类型转换接口函数根据给定的值和目标类型由用户自定义转换规则
*
* @param <T> 转换到的目标类型
* @author Looly
* @author looly
* @since 5.8.0
*/
public interface Converter<T> {
@FunctionalInterface
public interface Converter {
/**
* 转换为指定类型<br>
* 如果类型无法确定将读取默认值的类型做为目标类型
*
* @param targetType 目标Type非泛型类使用
* @param value 原始值
* @param defaultValue 默认值
* @return 转换后的值
* @throws IllegalArgumentException 无法确定目标类型且默认值为{@code null}无法确定类型
* @throws ConvertException 转换无法正常完成或转换异常时抛出此异常
*/
T convert(Object value, T defaultValue) throws IllegalArgumentException;
Object convert(Type targetType, Object value) throws ConvertException;
/**
* 转换值为指定类型可选是否不抛异常转换<br>
@ -25,19 +30,10 @@ public interface Converter<T> {
*
* @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> T convert(final Type targetType, final Object value, final T defaultValue) {
return ObjUtil.defaultIfNull((T)convert(targetType, value), defaultValue);
}
}

View File

@ -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<Type, Converter<?>> defaultConverterMap;
private Map<Type, Converter> defaultConverterMap;
/**
* 用户自定义类型转换器
*/
private volatile Map<Type, Converter<?>> customConverterMap;
private volatile Map<Type, Converter> 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<? extends Converter<?>> 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 {
/**
* 获得转换器<br>
*
* @param <T> 转换的目标类型
* @param type 类型
* @param isCustomFirst 是否自定义转换器优先
* @return 转换器
*/
public <T> Converter<T> getConverter(final Type type, final boolean isCustomFirst) {
Converter<T> 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 <T> 转换的目标类型转换器转换到的类型
* @param type 类型
* @return 转换器
*/
@SuppressWarnings("unchecked")
public <T> Converter<T> getDefaultConverter(final Type type) {
return (null == defaultConverterMap) ? null : (Converter<T>) defaultConverterMap.get(type);
public Converter getDefaultConverter(final Type type) {
return (null == defaultConverterMap) ? null : defaultConverterMap.get(type);
}
/**
* 获得自定义转换器
*
* @param <T> 转换的目标类型转换器转换到的类型
* @param type 类型
* @return 转换器
*/
@SuppressWarnings("unchecked")
public <T> Converter<T> getCustomConverter(final Type type) {
return (null == customConverterMap) ? null : (Converter<T>) 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<T> 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<T> rowType = (Class<T>) 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<T>(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
//AtomicXXXArraysince 5.4.5

View File

@ -1,24 +0,0 @@
package cn.hutool.core.convert;
import java.lang.reflect.Type;
/**
* 类型转换接口函数根据给定的值和目标类型由用户自定义转换规则
*
* @author looly
* @since 5.8.0
*/
@FunctionalInterface
public interface TypeConverter {
/**
* 转换为指定类型<br>
* 如果类型无法确定将读取默认值的类型做为目标类型
*
* @param targetType 目标Type非泛型类使用
* @param value 原始值
* @return 转换后的值
* @throws ConvertException 转换无法正常完成或转换异常时抛出此异常
*/
Object convert(Type targetType, Object value) throws ConvertException;
}

View File

@ -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();
/**
* 是否忽略元素转换错误
*/

View File

@ -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,60 +24,54 @@ import java.util.Map;
* ValueProvider = Bean
* </pre>
*
* @param <T> Bean类型
* @author Looly
* @since 4.0.2
*/
public class BeanConverter<T> extends AbstractConverter {
public class BeanConverter implements Converter, Serializable {
private static final long serialVersionUID = 1L;
private final Type beanType;
private final Class<T> 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<T> 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<T>) TypeUtil.getClass(beanType);
public BeanConverter(final CopyOptions copyOptions) {
this.copyOptions = copyOptions;
}
@Override
protected T convertInternal(final Class<?> targetClass, final Object value) {
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();
return BeanCopier.create(value, ConstructorUtil.newInstanceIfPossible(targetClass), targetType, this.copyOptions).copy();
} else if (value instanceof byte[]) {
// 尝试反序列化
return ObjUtil.deserialize((byte[]) value);

View File

@ -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<Object> 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<Object> collection = CollUtil.create(TypeUtil.getClass(collectionType));
return CollUtil.addAll(collection, value, elementType);
}
}

View File

@ -17,11 +17,20 @@ 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);
}
/**
* 构造
*

View File

@ -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<Class<?>, Map<Class<?>, 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);
}
/**

View File

@ -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()));
}
@ -83,11 +82,12 @@ public class MapConverter extends AbstractConverter {
* @param srcMap 源Map
* @param targetMap 目标Map
*/
private void convertMapToMap(final Map<?, ?> srcMap, final Map<Object, Object> 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);
key = TypeUtil.isUnknown(keyType) ? key : convert.convert(keyType, key);
value = TypeUtil.isUnknown(valueType) ? value : convert.convert(valueType, value);
targetMap.put(key, value);
});
}

View File

@ -39,24 +39,12 @@ import java.util.function.Function;
public class NumberConverter extends AbstractConverter {
private static final long serialVersionUID = 1L;
private final Class<? extends Number> targetType;
public NumberConverter() {
this.targetType = Number.class;
}
/**
* 构造<br>
*
* @param clazz 需要转换的数字类型默认 {@link Number}
*/
public NumberConverter(final Class<? extends Number> 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<? extends Number>) targetClass, this::convertToStr);
}
@Override

View File

@ -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();
/**
* 构造<br>
*

View File

@ -20,15 +20,7 @@ import java.lang.reflect.Type;
public class ReferenceConverter extends AbstractConverter {
private static final long serialVersionUID = 1L;
private final Class<? extends Reference> targetType;
/**
* 构造
* @param targetType {@link Reference}实现类型
*/
public ReferenceConverter(final Class<? extends Reference> 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()));
}
}

View File

@ -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);
}
/**
* 构造
*

View File

@ -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);
}

View File

@ -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<Object> 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<CharSequence>{
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();
}
}

View File

@ -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);
}
}

View File

@ -24,14 +24,21 @@ import java.util.List;
* @author looly
* @since 4.2.2
*/
public class JSONConverter implements Converter<JSON> {
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<JSON> {
* @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<JSON> {
if(value instanceof JSONGetter
&& targetType instanceof Class && BeanUtil.hasSetter((Class<?>) targetType)){
final JSONConfig config = ((JSONGetter<?>) value).getConfig();
final Converter<T> 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<JSON> {
return targetValue;
}
@Override
public JSON convert(final Object value, final JSON defaultValue) throws IllegalArgumentException {
return JSONUtil.parse(value);
}
}

View File

@ -1,3 +1,5 @@
package cn.hutool.json;
import cn.hutool.json.JSONUtil;
import lombok.Data;
import org.junit.Assert;