cn.hutool.core.convert.ConverterRegistry Maven / Gradle / Ivy
package cn.hutool.core.convert;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.impl.ArrayConverter;
import cn.hutool.core.convert.impl.AtomicBooleanConverter;
import cn.hutool.core.convert.impl.AtomicIntegerArrayConverter;
import cn.hutool.core.convert.impl.AtomicLongArrayConverter;
import cn.hutool.core.convert.impl.AtomicReferenceConverter;
import cn.hutool.core.convert.impl.BeanConverter;
import cn.hutool.core.convert.impl.BooleanConverter;
import cn.hutool.core.convert.impl.CalendarConverter;
import cn.hutool.core.convert.impl.CharacterConverter;
import cn.hutool.core.convert.impl.CharsetConverter;
import cn.hutool.core.convert.impl.ClassConverter;
import cn.hutool.core.convert.impl.CollectionConverter;
import cn.hutool.core.convert.impl.CurrencyConverter;
import cn.hutool.core.convert.impl.DateConverter;
import cn.hutool.core.convert.impl.DurationConverter;
import cn.hutool.core.convert.impl.EnumConverter;
import cn.hutool.core.convert.impl.LocaleConverter;
import cn.hutool.core.convert.impl.MapConverter;
import cn.hutool.core.convert.impl.NumberConverter;
import cn.hutool.core.convert.impl.OptConverter;
import cn.hutool.core.convert.impl.OptionalConverter;
import cn.hutool.core.convert.impl.PathConverter;
import cn.hutool.core.convert.impl.PeriodConverter;
import cn.hutool.core.convert.impl.PrimitiveConverter;
import cn.hutool.core.convert.impl.ReferenceConverter;
import cn.hutool.core.convert.impl.StackTraceElementConverter;
import cn.hutool.core.convert.impl.StringConverter;
import cn.hutool.core.convert.impl.TemporalAccessorConverter;
import cn.hutool.core.convert.impl.TimeZoneConverter;
import cn.hutool.core.convert.impl.URIConverter;
import cn.hutool.core.convert.impl.URLConverter;
import cn.hutool.core.convert.impl.UUIDConverter;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.util.ClassLoaderUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.ServiceLoaderUtil;
import cn.hutool.core.util.TypeUtil;
import java.io.Serializable;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URI;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.time.DayOfWeek;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.MonthDay;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.Period;
import java.time.ZonedDateTime;
import java.time.temporal.TemporalAccessor;
import java.util.Calendar;
import java.util.Collection;
import java.util.Currency;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.TimeZone;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicLongArray;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.DoubleAdder;
import java.util.concurrent.atomic.LongAdder;
/**
* 转换器登记中心
*
* 将各种类型Convert对象放入登记中心,通过convert方法查找目标类型对应的转换器,将被转换对象转换之。
*
*
* 在此类中,存放着默认转换器和自定义转换器,默认转换器是Hutool中预定义的一些转换器,自定义转换器存放用户自定的转换器。
*
*
* @author Looly
*/
public class ConverterRegistry implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 默认类型转换器
*/
private Map> defaultConverterMap;
/**
* 用户自定义类型转换器
*/
private volatile Map> customConverterMap;
/**
* 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载
*/
private static class SingletonHolder {
/**
* 静态初始化器,由JVM来保证线程安全
*/
private static final ConverterRegistry INSTANCE = new ConverterRegistry();
}
/**
* 获得单例的 ConverterRegistry
*
* @return ConverterRegistry
*/
public static ConverterRegistry getInstance() {
return SingletonHolder.INSTANCE;
}
/**
* 构造
*/
public ConverterRegistry() {
defaultConverter();
putCustomBySpi();
}
/**
* 使用SPI加载转换器
*/
private void putCustomBySpi() {
ServiceLoaderUtil.load(Converter.class).forEach(converter -> {
try {
Type type = TypeUtil.getTypeArgument(ClassUtil.getClass(converter));
if (null != type) {
putCustom(type, converter);
}
} catch (Exception e) {
// 忽略注册失败的
}
});
}
/**
* 登记自定义转换器
*
* @param type 转换的目标类型
* @param converterClass 转换器类,必须有默认构造方法
* @return ConverterRegistry
*/
public ConverterRegistry putCustom(Type type, Class extends Converter>> converterClass) {
return putCustom(type, ReflectUtil.newInstance(converterClass));
}
/**
* 登记自定义转换器
*
* @param type 转换的目标类型
* @param converter 转换器
* @return ConverterRegistry
*/
public ConverterRegistry putCustom(Type type, Converter> converter) {
if (null == customConverterMap) {
synchronized (this) {
if (null == customConverterMap) {
customConverterMap = new SafeConcurrentHashMap<>();
}
}
}
customConverterMap.put(type, converter);
return this;
}
/**
* 获得转换器
*
* @param 转换的目标类型
* @param type 类型
* @param isCustomFirst 是否自定义转换器优先
* @return 转换器
*/
public Converter getConverter(Type type, boolean isCustomFirst) {
Converter converter;
if (isCustomFirst) {
converter = this.getCustomConverter(type);
if (null == converter) {
converter = this.getDefaultConverter(type);
}
} else {
converter = this.getDefaultConverter(type);
if (null == converter) {
converter = this.getCustomConverter(type);
}
}
return converter;
}
/**
* 获得默认转换器
*
* @param 转换的目标类型(转换器转换到的类型)
* @param type 类型
* @return 转换器
*/
@SuppressWarnings("unchecked")
public Converter getDefaultConverter(Type type) {
return (null == defaultConverterMap) ? null : (Converter) defaultConverterMap.get(type);
}
/**
* 获得自定义转换器
*
* @param 转换的目标类型(转换器转换到的类型)
* @param type 类型
* @return 转换器
*/
@SuppressWarnings("unchecked")
public Converter getCustomConverter(Type type) {
return (null == customConverterMap) ? null : (Converter) customConverterMap.get(type);
}
/**
* 转换值为指定类型
*
* @param 转换的目标类型(转换器转换到的类型)
* @param type 类型目标
* @param value 被转换值
* @param defaultValue 默认值
* @param isCustomFirst 是否自定义转换器优先
* @return 转换后的值
* @throws ConvertException 转换器不存在
*/
@SuppressWarnings("unchecked")
public T convert(Type type, Object value, T defaultValue, boolean isCustomFirst) throws ConvertException {
if (TypeUtil.isUnknown(type) && null == defaultValue) {
// 对于用户不指定目标类型的情况,返回原值
return (T) value;
}
if (ObjectUtil.isNull(value)) {
return defaultValue;
}
if (TypeUtil.isUnknown(type)) {
type = defaultValue.getClass();
}
if (type instanceof TypeReference) {
type = ((TypeReference>) type).getType();
}
// 标准转换器
final Converter converter = getConverter(type, isCustomFirst);
if (null != converter) {
return converter.convert(value, defaultValue);
}
Class rowType = (Class) TypeUtil.getClass(type);
if (null == rowType) {
if (null != defaultValue) {
rowType = (Class) defaultValue.getClass();
} else {
// 无法识别的泛型类型,按照Object处理
return (T) value;
}
}
// 特殊类型转换,包括Collection、Map、强转、Array等
final T result = convertSpecial(type, rowType, value, defaultValue);
if (null != result) {
return result;
}
// 尝试转Bean
if (BeanUtil.isBean(rowType)) {
try {
// 由于5.x设计缺陷,JSON转bean无法实现自定义转换,因此此处临时使用反射方式获取自定义的转换器,此问题会在6.x中彻底解决。
final Class> clazz = ClassLoaderUtil.loadClass("cn.hutool.json.BeanConverterForJSON");
return ((Converter)ReflectUtil.newInstance(clazz, type)).convert(value, defaultValue);
}catch (final Throwable ignore){
}
return new BeanConverter(type).convert(value, defaultValue);
}
// 无法转换
throw new ConvertException("Can not Converter from [{}] to [{}]", value.getClass().getName(), type.getTypeName());
}
/**
* 转换值为指定类型
* 自定义转换器优先
*
* @param 转换的目标类型(转换器转换到的类型)
* @param type 类型
* @param value 值
* @param defaultValue 默认值
* @return 转换后的值
* @throws ConvertException 转换器不存在
*/
public T convert(Type type, Object value, T defaultValue) throws ConvertException {
return convert(type, value, defaultValue, true);
}
/**
* 转换值为指定类型
*
* @param 转换的目标类型(转换器转换到的类型)
* @param type 类型
* @param value 值
* @return 转换后的值,默认为{@code null}
* @throws ConvertException 转换器不存在
*/
public T convert(Type type, Object value) throws ConvertException {
return convert(type, value, null);
}
// ----------------------------------------------------------- Private method start
/**
* 特殊类型转换
* 包括:
*
*
* Collection
* Map
* 强转(无需转换)
* 数组
*
*
* @param 转换的目标类型(转换器转换到的类型)
* @param type 类型
* @param value 值
* @param defaultValue 默认值
* @return 转换后的值
*/
@SuppressWarnings("unchecked")
private T convertSpecial(Type type, Class rowType, Object value, T defaultValue) {
if (null == rowType) {
return null;
}
// 集合转换(不可以默认强转)
if (Collection.class.isAssignableFrom(rowType)) {
final CollectionConverter collectionConverter = new CollectionConverter(type);
return (T) collectionConverter.convert(value, (Collection>) defaultValue);
}
// Map类型(不可以默认强转)
if (Map.class.isAssignableFrom(rowType)) {
final MapConverter mapConverter = new MapConverter(type);
return (T) mapConverter.convert(value, (Map, ?>) defaultValue);
}
// 默认强转
if (rowType.isInstance(value)) {
return (T) value;
}
// 枚举转换
if (rowType.isEnum()) {
return (T) new EnumConverter(rowType).convert(value, defaultValue);
}
// 数组转换
if (rowType.isArray()) {
final ArrayConverter arrayConverter = new ArrayConverter(rowType);
return (T) arrayConverter.convert(value, defaultValue);
}
// 表示非需要特殊转换的对象
return null;
}
/**
* 注册默认转换器
*
* @return 转换器
*/
private ConverterRegistry defaultConverter() {
defaultConverterMap = new SafeConcurrentHashMap<>();
// 原始类型转换器
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(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(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(CharSequence.class, new StringConverter());
defaultConverterMap.put(String.class, new StringConverter());
// URI and URL
defaultConverterMap.put(URI.class, new URIConverter());
defaultConverterMap.put(URL.class, new URLConverter());
// 日期时间
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));
// 日期时间 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(DayOfWeek.class, new TemporalAccessorConverter(DayOfWeek.class));
defaultConverterMap.put(Month.class, new TemporalAccessorConverter(Month.class));
defaultConverterMap.put(MonthDay.class, new TemporalAccessorConverter(MonthDay.class));
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(AtomicReference.class, new AtomicReferenceConverter());// since 3.0.8
//AtomicXXXArray,since 5.4.5
defaultConverterMap.put(AtomicIntegerArray.class, new AtomicIntegerArrayConverter());
defaultConverterMap.put(AtomicLongArray.class, new AtomicLongArrayConverter());
// 其它类型
defaultConverterMap.put(Class.class, new ClassConverter());
defaultConverterMap.put(TimeZone.class, new TimeZoneConverter());
defaultConverterMap.put(Locale.class, new LocaleConverter());
defaultConverterMap.put(Charset.class, new CharsetConverter());
defaultConverterMap.put(Path.class, new PathConverter());
defaultConverterMap.put(Currency.class, new CurrencyConverter());// since 3.0.8
defaultConverterMap.put(UUID.class, new UUIDConverter());// since 4.0.10
defaultConverterMap.put(StackTraceElement.class, new StackTraceElementConverter());// since 4.5.2
defaultConverterMap.put(Optional.class, new OptionalConverter());// since 5.0.0
defaultConverterMap.put(Opt.class, new OptConverter());// since 5.7.16
return this;
}
// ----------------------------------------------------------- Private method end
}