Commit 45cda665 authored by ma yanling's avatar ma yanling
Browse files

project commit

parent ad2fb30a
Pipeline #2354 failed with stages
in 0 seconds
package cn.hutool.core.convert.impl;
import cn.hutool.core.convert.AbstractConverter;
import cn.hutool.core.convert.Convert;
import java.util.concurrent.atomic.AtomicLongArray;
/**
* {@link AtomicLongArray}转换器
*
* @author Looly
* @since 5.4.5
*/
public class AtomicLongArrayConverter extends AbstractConverter<AtomicLongArray> {
private static final long serialVersionUID = 1L;
@Override
protected AtomicLongArray convertInternal(Object value) {
return new AtomicLongArray(Convert.convert(long[].class, value));
}
}
package cn.hutool.core.convert.impl;
import java.lang.reflect.Type;
import java.util.concurrent.atomic.AtomicReference;
import cn.hutool.core.convert.AbstractConverter;
import cn.hutool.core.convert.ConverterRegistry;
import cn.hutool.core.util.TypeUtil;
/**
* {@link AtomicReference}转换器
*
* @author Looly
* @since 3.0.8
*/
@SuppressWarnings("rawtypes")
public class AtomicReferenceConverter extends AbstractConverter<AtomicReference> {
private static final long serialVersionUID = 1L;
@Override
protected AtomicReference<?> convertInternal(Object value) {
//尝试将值转换为Reference泛型的类型
Object targetValue = null;
final Type paramType = TypeUtil.getTypeArgument(AtomicReference.class);
if(false == TypeUtil.isUnknown(paramType)){
targetValue = ConverterRegistry.getInstance().convert(paramType, value);
}
if(null == targetValue){
targetValue = value;
}
return new AtomicReference<>(targetValue);
}
}
package cn.hutool.core.convert.impl;
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.map.MapProxy;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.TypeUtil;
import java.lang.reflect.Type;
import java.util.Map;
/**
* Bean转换器,支持:
* <pre>
* Map =》 Bean
* Bean =》 Bean
* ValueProvider =》 Bean
* </pre>
*
* @param <T> Bean类型
* @author Looly
* @since 4.0.2
*/
public class BeanConverter<T> extends AbstractConverter<T> {
private static final long serialVersionUID = 1L;
private final Type beanType;
private final Class<T> beanClass;
private final CopyOptions copyOptions;
/**
* 构造,默认转换选项,注入失败的字段忽略
*
* @param beanType 转换成的目标Bean类型
*/
public BeanConverter(Type beanType) {
this(beanType, CopyOptions.create().setIgnoreError(true));
}
/**
* 构造,默认转换选项,注入失败的字段忽略
*
* @param beanClass 转换成的目标Bean类
*/
public BeanConverter(Class<T> beanClass) {
this(beanClass, CopyOptions.create().setIgnoreError(true));
}
/**
* 构造
*
* @param beanType 转换成的目标Bean类
* @param copyOptions Bean转换选项参数
*/
@SuppressWarnings("unchecked")
public BeanConverter(Type beanType, CopyOptions copyOptions) {
this.beanType = beanType;
this.beanClass = (Class<T>) TypeUtil.getClass(beanType);
this.copyOptions = copyOptions;
}
@Override
protected T convertInternal(Object value) {
if(value instanceof Map ||
value instanceof ValueProvider ||
BeanUtil.isBean(value.getClass())) {
if(value instanceof Map && this.beanClass.isInterface()) {
// 将Map动态代理为Bean
return MapProxy.create((Map<?, ?>)value).toProxyBean(this.beanClass);
}
//限定被转换对象类型
return BeanCopier.create(value, ReflectUtil.newInstanceIfPossible(this.beanClass), this.beanType, this.copyOptions).copy();
} else if(value instanceof byte[]){
// 尝试反序列化
return ObjectUtil.deserialize((byte[])value);
}
throw new ConvertException("Unsupported source type: {}", value.getClass());
}
@Override
public Class<T> getTargetType() {
return this.beanClass;
}
}
package cn.hutool.core.convert.impl;
import cn.hutool.core.convert.AbstractConverter;
import cn.hutool.core.util.BooleanUtil;
/**
* 布尔转换器
*
* <p>
* 对象转为boolean,规则如下:
* </p>
* <pre>
* 1、数字0为false,其它数字为true
* 2、转换为字符串,形如"true", "yes", "y", "t", "ok", "1", "on", "是", "对", "真", "對", "√"为true,其它字符串为false.
* </pre>
*
* @author Looly
*/
public class BooleanConverter extends AbstractConverter<Boolean> {
private static final long serialVersionUID = 1L;
@Override
protected Boolean convertInternal(Object value) {
if (value instanceof Number) {
// 0为false,其它数字为true
return 0 != ((Number) value).doubleValue();
}
//Object不可能出现Primitive类型,故忽略
return BooleanUtil.toBoolean(convertToStr(value));
}
}
package cn.hutool.core.convert.impl;
import java.util.Calendar;
import java.util.Date;
import cn.hutool.core.convert.AbstractConverter;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
/**
* 日期转换器
*
* @author Looly
*
*/
public class CalendarConverter extends AbstractConverter<Calendar> {
private static final long serialVersionUID = 1L;
/** 日期格式化 */
private String format;
/**
* 获取日期格式
*
* @return 设置日期格式
*/
public String getFormat() {
return format;
}
/**
* 设置日期格式
*
* @param format 日期格式
*/
public void setFormat(String format) {
this.format = format;
}
@Override
protected Calendar convertInternal(Object value) {
// Handle Date
if (value instanceof Date) {
return DateUtil.calendar((Date)value);
}
// Handle Long
if (value instanceof Long) {
//此处使用自动拆装箱
return DateUtil.calendar((Long)value);
}
final String valueStr = convertToStr(value);
return DateUtil.calendar(StrUtil.isBlank(format) ? DateUtil.parse(valueStr) : DateUtil.parse(valueStr, format));
}
}
package cn.hutool.core.convert.impl;
import cn.hutool.core.convert.AbstractConverter;
import cn.hutool.core.convert.ConvertException;
/**
* 强转转换器
*
* @author Looly
* @param <T> 强制转换到的类型
* @since 4.0.2
*/
public class CastConverter<T> extends AbstractConverter<T> {
private static final long serialVersionUID = 1L;
private Class<T> targetType;
@Override
protected T convertInternal(Object value) {
// 由于在AbstractConverter中已经有类型判断并强制转换,因此当在上一步强制转换失败时直接抛出异常
throw new ConvertException("Can not cast value to [{}]", this.targetType);
}
@Override
public Class<T> getTargetType() {
return this.targetType;
}
}
package cn.hutool.core.convert.impl;
import cn.hutool.core.convert.AbstractConverter;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
/**
* 字符转换器
*
* @author Looly
*
*/
public class CharacterConverter extends AbstractConverter<Character> {
private static final long serialVersionUID = 1L;
@Override
protected Character convertInternal(Object value) {
if (value instanceof Boolean) {
return BooleanUtil.toCharacter((Boolean) value);
} else {
final String valueStr = convertToStr(value);
if (StrUtil.isNotBlank(valueStr)) {
return valueStr.charAt(0);
}
}
return null;
}
}
package cn.hutool.core.convert.impl;
import java.nio.charset.Charset;
import cn.hutool.core.convert.AbstractConverter;
import cn.hutool.core.util.CharsetUtil;
/**
* 编码对象转换器
* @author Looly
*
*/
public class CharsetConverter extends AbstractConverter<Charset>{
private static final long serialVersionUID = 1L;
@Override
protected Charset convertInternal(Object value) {
return CharsetUtil.charset(convertToStr(value));
}
}
package cn.hutool.core.convert.impl;
import cn.hutool.core.convert.AbstractConverter;
import cn.hutool.core.util.ClassLoaderUtil;
/**
* 类转换器<br>
* 将类名转换为类,默认初始化这个类(执行static块)
*
* @author Looly
*/
public class ClassConverter extends AbstractConverter<Class<?>> {
private static final long serialVersionUID = 1L;
private final boolean isInitialized;
/**
* 构造
*/
public ClassConverter() {
this(true);
}
/**
* 构造
*
* @param isInitialized 是否初始化类(调用static模块内容和初始化static属性)
* @since 5.5.0
*/
public ClassConverter(boolean isInitialized) {
this.isInitialized = isInitialized;
}
@Override
protected Class<?> convertInternal(Object value) {
return ClassLoaderUtil.loadClass(convertToStr(value), isInitialized);
}
}
package cn.hutool.core.convert.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Converter;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.TypeUtil;
import java.lang.reflect.Type;
import java.util.Collection;
/**
* 各种集合类转换器
*
* @author Looly
* @since 3.0.8
*/
public class CollectionConverter implements Converter<Collection<?>> {
/** 集合类型 */
private final Type collectionType;
/** 集合元素类型 */
private final Type elementType;
/**
* 构造,默认集合类型使用{@link Collection}
*/
public CollectionConverter() {
this(Collection.class);
}
// ---------------------------------------------------------------------------------------------- Constractor start
/**
* 构造
*
* @param collectionType 集合类型
*/
public CollectionConverter(Type collectionType) {
this(collectionType, TypeUtil.getTypeArgument(collectionType));
}
/**
* 构造
*
* @param collectionType 集合类型
*/
public CollectionConverter(Class<?> collectionType) {
this(collectionType, TypeUtil.getTypeArgument(collectionType));
}
/**
* 构造
*
* @param collectionType 集合类型
* @param elementType 集合元素类型
*/
public CollectionConverter(Type collectionType, Type elementType) {
this.collectionType = collectionType;
this.elementType = elementType;
}
// ---------------------------------------------------------------------------------------------- Constractor end
@Override
public Collection<?> convert(Object value, Collection<?> defaultValue) throws IllegalArgumentException {
final Collection<?> result = convertInternal(value);
return ObjectUtil.defaultIfNull(result, defaultValue);
}
/**
* 内部转换
*
* @param value 值
* @return 转换后的集合对象
*/
protected Collection<?> convertInternal(Object value) {
final Collection<?> collection = CollUtil.create(TypeUtil.getClass(this.collectionType), TypeUtil.getClass(this.elementType));
return CollUtil.addAll(collection, value, this.elementType);
}
}
package cn.hutool.core.convert.impl;
import java.util.Currency;
import cn.hutool.core.convert.AbstractConverter;
/**
* 货币{@link Currency} 转换器
*
* @author Looly
* @since 3.0.8
*/
public class CurrencyConverter extends AbstractConverter<Currency> {
private static final long serialVersionUID = 1L;
@Override
protected Currency convertInternal(Object value) {
return Currency.getInstance(convertToStr(value));
}
}
package cn.hutool.core.convert.impl;
import cn.hutool.core.convert.AbstractConverter;
import cn.hutool.core.convert.ConvertException;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.format.GlobalCustomFormat;
import cn.hutool.core.util.StrUtil;
import java.time.temporal.TemporalAccessor;
import java.util.Calendar;
/**
* 日期转换器
*
* @author Looly
*/
public class DateConverter extends AbstractConverter<java.util.Date> {
private static final long serialVersionUID = 1L;
private final Class<? extends java.util.Date> targetType;
/**
* 日期格式化
*/
private String format;
/**
* 构造
*
* @param targetType 目标类型
*/
public DateConverter(Class<? extends java.util.Date> targetType) {
this.targetType = targetType;
}
/**
* 构造
*
* @param targetType 目标类型
* @param format 日期格式
*/
public DateConverter(Class<? extends java.util.Date> targetType, String format) {
this.targetType = targetType;
this.format = format;
}
/**
* 获取日期格式
*
* @return 设置日期格式
*/
public String getFormat() {
return format;
}
/**
* 设置日期格式
*
* @param format 日期格式
*/
public void setFormat(String format) {
this.format = format;
}
@Override
protected java.util.Date convertInternal(Object value) {
if (value == null || (value instanceof CharSequence && StrUtil.isBlank(value.toString()))) {
return null;
}
if (value instanceof TemporalAccessor) {
return wrap(DateUtil.date((TemporalAccessor) value));
} else if (value instanceof Calendar) {
return wrap(DateUtil.date((Calendar) value));
} else if (value instanceof Number) {
return wrap(((Number) value).longValue());
} else {
// 统一按照字符串处理
final String valueStr = convertToStr(value);
final DateTime dateTime = StrUtil.isBlank(this.format) //
? DateUtil.parse(valueStr) //
: DateUtil.parse(valueStr, this.format);
if (null != dateTime) {
return wrap(dateTime);
}
}
throw new ConvertException("Can not convert {}:[{}] to {}", value.getClass().getName(), value, this.targetType.getName());
}
/**
* java.util.Date转为子类型
*
* @param date Date
* @return 目标类型对象
*/
private java.util.Date wrap(DateTime date) {
// 返回指定类型
if (java.util.Date.class == targetType) {
return date.toJdkDate();
}
if (DateTime.class == targetType) {
return date;
}
if (java.sql.Date.class == targetType) {
return date.toSqlDate();
}
if (java.sql.Time.class == targetType) {
return new java.sql.Time(date.getTime());
}
if (java.sql.Timestamp.class == targetType) {
return date.toTimestamp();
}
throw new UnsupportedOperationException(StrUtil.format("Unsupported target Date type: {}", this.targetType.getName()));
}
/**
* java.util.Date转为子类型
*
* @param mills Date
* @return 目标类型对象
*/
private java.util.Date wrap(long mills) {
if(GlobalCustomFormat.FORMAT_SECONDS.equals(this.format)){
// Unix时间戳
return DateUtil.date(mills * 1000);
}
// 返回指定类型
if (java.util.Date.class == targetType) {
return new java.util.Date(mills);
}
if (DateTime.class == targetType) {
return DateUtil.date(mills);
}
if (java.sql.Date.class == targetType) {
return new java.sql.Date(mills);
}
if (java.sql.Time.class == targetType) {
return new java.sql.Time(mills);
}
if (java.sql.Timestamp.class == targetType) {
return new java.sql.Timestamp(mills);
}
throw new UnsupportedOperationException(StrUtil.format("Unsupported target Date type: {}", this.targetType.getName()));
}
@SuppressWarnings("unchecked")
@Override
public Class<java.util.Date> getTargetType() {
return (Class<java.util.Date>) this.targetType;
}
}
package cn.hutool.core.convert.impl;
import cn.hutool.core.convert.AbstractConverter;
import java.time.Duration;
import java.time.temporal.TemporalAmount;
/**
*
* {@link Duration}对象转换器
*
* @author Looly
* @since 5.0.0
*/
public class DurationConverter extends AbstractConverter<Duration> {
private static final long serialVersionUID = 1L;
@Override
protected Duration convertInternal(Object value) {
if(value instanceof TemporalAmount){
return Duration.from((TemporalAmount) value);
} else if(value instanceof Long){
return Duration.ofMillis((Long) value);
} else {
return Duration.parse(convertToStr(value));
}
}
}
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.lang.Pair;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.TypeUtil;
import java.lang.reflect.Type;
import java.util.Map;
public class EntryConverter extends AbstractConverter<Map.Entry<?, ?>> {
/** Pair类型 */
private final Type pairType;
/** 键类型 */
private final Type keyType;
/** 值类型 */
private final Type valueType;
/**
* 构造,Pair的key和value泛型类型自动获取
*
* @param entryType Map类型
*/
public EntryConverter(Type entryType) {
this(entryType, TypeUtil.getTypeArgument(entryType, 0), TypeUtil.getTypeArgument(entryType, 1));
}
/**
* 构造
*
* @param entryType Pair类型
* @param keyType 键类型
* @param valueType 值类型
*/
public EntryConverter(Type entryType, Type keyType, Type valueType) {
this.pairType = entryType;
this.keyType = keyType;
this.valueType = valueType;
}
@SuppressWarnings("rawtypes")
@Override
protected Map.Entry<?, ?> convertInternal(Object value) {
Map map = null;
if (value instanceof Pair) {
final Pair pair = (Pair) value;
map = MapUtil.of(pair.getKey(), pair.getValue());
}else if (value instanceof Map) {
map = (Map) value;
} else if (value instanceof CharSequence) {
final CharSequence str = (CharSequence) value;
map = strToMap(str);
} else if (BeanUtil.isReadableBean(value.getClass())) {
map = BeanUtil.beanToMap(value);
}
if (null != map) {
return mapToEntry(pairType, keyType, valueType, map);
}
throw new ConvertException("Unsupported to map from [{}] of type: {}", value, value.getClass().getName());
}
/**
* 字符串转单个键值对的Map,支持分隔符{@code :}、{@code =}、{@code ,}
*
* @param str 字符串
* @return map or null
*/
private static Map<CharSequence, CharSequence> strToMap(final CharSequence str) {
// key:value key=value key,value
final int index = StrUtil.indexOf(str, '=', 0, str.length());
if (index > -1) {
return MapUtil.of(str.subSequence(0, index + 1), str.subSequence(index, str.length()));
}
return null;
}
/**
* Map转Entry
*
* @param targetType 目标的Map类型
* @param keyType 键类型
* @param valueType 值类型
* @param map 被转换的map
* @return Entry
*/
@SuppressWarnings("rawtypes")
private static Map.Entry<?, ?> mapToEntry(final Type targetType, final Type keyType, final Type valueType, final Map map) {
Object key = null;
Object value = null;
if (1 == map.size()) {
final Map.Entry entry = (Map.Entry) map.entrySet().iterator().next();
key = entry.getKey();
value = entry.getValue();
} else if (2 == map.size()) {
key = map.get("key");
value = map.get("value");
}
final ConverterRegistry convert = ConverterRegistry.getInstance();
return (Map.Entry<?, ?>) ReflectUtil.newInstance(TypeUtil.getClass(targetType),
TypeUtil.isUnknown(keyType) ? key : convert.convert(keyType, key),
TypeUtil.isUnknown(valueType) ? value : convert.convert(valueType, value)
);
}
}
package cn.hutool.core.convert.impl;
import cn.hutool.core.convert.AbstractConverter;
import cn.hutool.core.convert.ConvertException;
import cn.hutool.core.lang.EnumItem;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.WeakConcurrentMap;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ModifierUtil;
import cn.hutool.core.util.ReflectUtil;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 无泛型检查的枚举转换器
*
* @author Looly
* @since 4.0.2
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public class EnumConverter extends AbstractConverter<Object> {
private static final long serialVersionUID = 1L;
private static final WeakConcurrentMap<Class<?>, Map<Class<?>, Method>> VALUE_OF_METHOD_CACHE = new WeakConcurrentMap<>();
private final Class enumClass;
/**
* 构造
*
* @param enumClass 转换成的目标Enum类
*/
public EnumConverter(Class enumClass) {
this.enumClass = enumClass;
}
@Override
protected Object convertInternal(Object value) {
Enum enumValue = tryConvertEnum(value, this.enumClass);
if (null == enumValue && false == value instanceof String) {
// 最后尝试先将value转String,再valueOf转换
enumValue = Enum.valueOf(this.enumClass, convertToStr(value));
}
if (null != enumValue) {
return enumValue;
}
throw new ConvertException("Can not convert {} to {}", value, this.enumClass);
}
@Override
public Class getTargetType() {
return this.enumClass;
}
/**
* 尝试转换,转换规则为:
* <ul>
* <li>如果实现{@link EnumItem}接口,则调用fromInt或fromStr转换</li>
* <li>找到类似转换的静态方法调用实现转换且优先使用</li>
* <li>约定枚举类应该提供 valueOf(String) 和 valueOf(Integer)用于转换</li>
* <li>oriInt /name 转换托底</li>
* </ul>
*
* @param value 被转换的值
* @param enumClass enum类
* @return 对应的枚举值
*/
protected static Enum tryConvertEnum(Object value, Class enumClass) {
if (value == null) {
return null;
}
// EnumItem实现转换
if (EnumItem.class.isAssignableFrom(enumClass)) {
final EnumItem first = (EnumItem) EnumUtil.getEnumAt(enumClass, 0);
if (null != first) {
if (value instanceof Integer) {
return (Enum) first.fromInt((Integer) value);
} else if (value instanceof String) {
return (Enum) first.fromStr(value.toString());
}
}
}
// 用户自定义方法
// 查找枚举中所有返回值为目标枚举对象的方法,如果发现方法参数匹配,就执行之
try {
final Map<Class<?>, Method> methodMap = getMethodMap(enumClass);
if (MapUtil.isNotEmpty(methodMap)) {
final Class<?> valueClass = value.getClass();
for (Map.Entry<Class<?>, Method> entry : methodMap.entrySet()) {
if (ClassUtil.isAssignable(entry.getKey(), valueClass)) {
return ReflectUtil.invokeStatic(entry.getValue(), value);
}
}
}
} catch (Exception ignore) {
//ignore
}
//oriInt 应该滞后使用 以 GB/T 2261.1-2003 性别编码为例,对应整数并非连续数字会导致数字转枚举时失败
//0 - 未知的性别
//1 - 男性
//2 - 女性
//5 - 女性改(变)为男性
//6 - 男性改(变)为女性
//9 - 未说明的性别
Enum enumResult = null;
if (value instanceof Integer) {
enumResult = EnumUtil.getEnumAt(enumClass, (Integer) value);
} else if (value instanceof String) {
try {
enumResult = Enum.valueOf(enumClass, (String) value);
} catch (IllegalArgumentException e) {
//ignore
}
}
return enumResult;
}
/**
* 获取用于转换为enum的所有static方法
*
* @param enumClass 枚举类
* @return 转换方法map,key为方法参数类型,value为方法
*/
private static Map<Class<?>, Method> getMethodMap(Class<?> enumClass) {
return VALUE_OF_METHOD_CACHE.computeIfAbsent(enumClass, (key) -> Arrays.stream(enumClass.getMethods())
.filter(ModifierUtil::isStatic)
.filter(m -> m.getReturnType() == enumClass)
.filter(m -> m.getParameterCount() == 1)
.filter(m -> false == "valueOf".equals(m.getName()))
.collect(Collectors.toMap(m -> m.getParameterTypes()[0], m -> m, (k1, k2) -> k1)));
}
}
package cn.hutool.core.convert.impl;
import java.util.Locale;
import cn.hutool.core.convert.AbstractConverter;
import cn.hutool.core.util.StrUtil;
/**
*
* {@link Locale}对象转换器<br>
* 只提供String转换支持
*
* @author Looly
* @since 4.5.2
*/
public class LocaleConverter extends AbstractConverter<Locale> {
private static final long serialVersionUID = 1L;
@Override
protected Locale convertInternal(Object value) {
try {
String str = convertToStr(value);
if (StrUtil.isEmpty(str)) {
return null;
}
final String[] items = str.split("_");
if (items.length == 1) {
return new Locale(items[0]);
}
if (items.length == 2) {
return new Locale(items[0], items[1]);
}
return new Locale(items[0], items[1], items[2]);
} catch (Exception e) {
// Ignore Exception
}
return null;
}
}
package cn.hutool.core.convert.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.AbstractConverter;
import cn.hutool.core.convert.ConverterRegistry;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.TypeUtil;
import java.lang.reflect.Type;
import java.util.*;
/**
* {@link Map} 转换器
*
* @author Looly
* @since 3.0.8
*/
public class MapConverter extends AbstractConverter<Map<?, ?>> {
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(Type mapType) {
this(mapType, TypeUtil.getTypeArgument(mapType, 0), TypeUtil.getTypeArgument(mapType, 1));
}
/**
* 构造
*
* @param mapType Map类型
* @param keyType 键类型
* @param valueType 值类型
*/
public MapConverter(Type mapType, Type keyType, Type valueType) {
this.mapType = mapType;
this.keyType = keyType;
this.valueType = valueType;
}
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
protected Map<?, ?> convertInternal(Object value) {
Map map;
if (value instanceof Map) {
final Class<?> valueClass = value.getClass();
if(valueClass.equals(this.mapType)){
final Type[] typeArguments = TypeUtil.getTypeArguments(valueClass);
if (null != typeArguments //
&& 2 == typeArguments.length//
&& Objects.equals(this.keyType, typeArguments[0]) //
&& Objects.equals(this.valueType, typeArguments[1])) {
//对于键值对类型一致的Map对象,不再做转换,直接返回原对象
return (Map) value;
}
}
final Class<?> mapClass = TypeUtil.getClass(this.mapType);
if (null == mapClass || mapClass.isAssignableFrom(AbstractMap.class)) {
// issue#I6YN2A,默认有序
map = new LinkedHashMap<>();
} else{
map = MapUtil.createMap(mapClass);
}
convertMapToMap((Map) value, map);
} else if (BeanUtil.isBean(value.getClass())) {
map = BeanUtil.beanToMap(value);
// 二次转换,转换键值类型
map = convertInternal(map);
} else {
throw new UnsupportedOperationException(StrUtil.format("Unsupported toMap value type: {}", value.getClass().getName()));
}
return map;
}
/**
* Map转Map
*
* @param srcMap 源Map
* @param targetMap 目标Map
*/
private void convertMapToMap(Map<?, ?> srcMap, Map<Object, Object> 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);
targetMap.put(key, value);
});
}
@Override
@SuppressWarnings("unchecked")
public Class<Map<?, ?>> getTargetType() {
return (Class<Map<?, ?>>) TypeUtil.getClass(this.mapType);
}
}
package cn.hutool.core.convert.impl;
import cn.hutool.core.convert.AbstractConverter;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ByteUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.temporal.TemporalAccessor;
import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.DoubleAdder;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.Function;
/**
* 数字转换器<br>
* 支持类型为:<br>
* <ul>
* <li>{@code java.lang.Byte}</li>
* <li>{@code java.lang.Short}</li>
* <li>{@code java.lang.Integer}</li>
* <li>{@code java.util.concurrent.atomic.AtomicInteger}</li>
* <li>{@code java.lang.Long}</li>
* <li>{@code java.util.concurrent.atomic.AtomicLong}</li>
* <li>{@code java.lang.Float}</li>
* <li>{@code java.lang.Double}</li>
* <li>{@code java.math.BigDecimal}</li>
* <li>{@code java.math.BigInteger}</li>
* </ul>
*
* @author Looly
*/
public class NumberConverter extends AbstractConverter<Number> {
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(Class<? extends Number> clazz) {
this.targetType = (null == clazz) ? Number.class : clazz;
}
@Override
@SuppressWarnings("unchecked")
public Class<Number> getTargetType() {
return (Class<Number>) this.targetType;
}
@Override
protected Number convertInternal(Object value) {
return convert(value, this.targetType, this::convertToStr);
}
@Override
protected String convertToStr(Object value) {
final String result = StrUtil.trim(super.convertToStr(value));
if (null != result && result.length() > 1) {
final char c = Character.toUpperCase(result.charAt(result.length() - 1));
if (c == 'D' || c == 'L' || c == 'F') {
// 类型标识形式(例如123.6D)
return StrUtil.subPre(result, -1);
}
}
return result;
}
/**
* 转换对象为数字,支持的对象包括:
* <ul>
* <li>Number对象</li>
* <li>Boolean</li>
* <li>byte[]</li>
* <li>String</li>
* </ul>
*
*
* @param value 对象值
* @param targetType 目标的数字类型
* @param toStrFunc 转换为字符串的函数
* @return 转换后的数字
* @since 5.5.0
*/
protected static Number convert(Object value, Class<? extends Number> targetType, Function<Object, String> toStrFunc) {
// 枚举转换为数字默认为其顺序
if (value instanceof Enum) {
return convert(((Enum<?>) value).ordinal(), targetType, toStrFunc);
}
// since 5.7.18
if(value instanceof byte[]){
return ByteUtil.bytesToNumber((byte[])value, targetType, ByteUtil.DEFAULT_ORDER);
}
if (Byte.class == targetType) {
if (value instanceof Number) {
return ((Number) value).byteValue();
} else if (value instanceof Boolean) {
return BooleanUtil.toByteObj((Boolean) value);
}
final String valueStr = toStrFunc.apply(value);
try{
return StrUtil.isBlank(valueStr) ? null : Byte.valueOf(valueStr);
} catch (NumberFormatException e){
return NumberUtil.parseNumber(valueStr).byteValue();
}
} else if (Short.class == targetType) {
if (value instanceof Number) {
return ((Number) value).shortValue();
} else if (value instanceof Boolean) {
return BooleanUtil.toShortObj((Boolean) value);
}
final String valueStr = toStrFunc.apply((value));
try{
return StrUtil.isBlank(valueStr) ? null : Short.valueOf(valueStr);
} catch (NumberFormatException e){
return NumberUtil.parseNumber(valueStr).shortValue();
}
} else if (Integer.class == targetType) {
if (value instanceof Number) {
return ((Number) value).intValue();
} else if (value instanceof Boolean) {
return BooleanUtil.toInteger((Boolean) value);
} else if (value instanceof Date) {
return (int) ((Date) value).getTime();
} else if (value instanceof Calendar) {
return (int) ((Calendar) value).getTimeInMillis();
} else if (value instanceof TemporalAccessor) {
return (int) DateUtil.toInstant((TemporalAccessor) value).toEpochMilli();
}
final String valueStr = toStrFunc.apply((value));
return StrUtil.isBlank(valueStr) ? null : NumberUtil.parseInt(valueStr);
} else if (AtomicInteger.class == targetType) {
final Number number = convert(value, Integer.class, toStrFunc);
if (null != number) {
return new AtomicInteger(number.intValue());
}
} else if (Long.class == targetType) {
if (value instanceof Number) {
return ((Number) value).longValue();
} else if (value instanceof Boolean) {
return BooleanUtil.toLongObj((Boolean) value);
} else if (value instanceof Date) {
return ((Date) value).getTime();
} else if (value instanceof Calendar) {
return ((Calendar) value).getTimeInMillis();
} else if (value instanceof TemporalAccessor) {
return DateUtil.toInstant((TemporalAccessor) value).toEpochMilli();
}
final String valueStr = toStrFunc.apply((value));
return StrUtil.isBlank(valueStr) ? null : NumberUtil.parseLong(valueStr);
} else if (AtomicLong.class == targetType) {
final Number number = convert(value, Long.class, toStrFunc);
if (null != number) {
return new AtomicLong(number.longValue());
}
} else if (LongAdder.class == targetType) {
//jdk8 新增
final Number number = convert(value, Long.class, toStrFunc);
if (null != number) {
final LongAdder longValue = new LongAdder();
longValue.add(number.longValue());
return longValue;
}
} else if (Float.class == targetType) {
if (value instanceof Number) {
return ((Number) value).floatValue();
} else if (value instanceof Boolean) {
return BooleanUtil.toFloatObj((Boolean) value);
}
final String valueStr = toStrFunc.apply((value));
return StrUtil.isBlank(valueStr) ? null : NumberUtil.parseFloat(valueStr);
} else if (Double.class == targetType) {
if (value instanceof Number) {
return NumberUtil.toDouble((Number) value);
} else if (value instanceof Boolean) {
return BooleanUtil.toDoubleObj((Boolean) value);
}
final String valueStr = toStrFunc.apply((value));
return StrUtil.isBlank(valueStr) ? null : NumberUtil.parseDouble(valueStr);
} else if (DoubleAdder.class == targetType) {
//jdk8 新增
final Number number = convert(value, Double.class, toStrFunc);
if (null != number) {
final DoubleAdder doubleAdder = new DoubleAdder();
doubleAdder.add(number.doubleValue());
return doubleAdder;
}
} else if (BigDecimal.class == targetType) {
return toBigDecimal(value, toStrFunc);
} else if (BigInteger.class == targetType) {
return toBigInteger(value, toStrFunc);
} else if (Number.class == targetType) {
if (value instanceof Number) {
return (Number) value;
} else if (value instanceof Boolean) {
return BooleanUtil.toInteger((Boolean) value);
}
final String valueStr = toStrFunc.apply((value));
return StrUtil.isBlank(valueStr) ? null : NumberUtil.parseNumber(valueStr);
}
throw new UnsupportedOperationException(StrUtil.format("Unsupport Number type: {}", targetType.getName()));
}
/**
* 转换为BigDecimal<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param toStrFunc 转换为字符串的函数规则
* @return 结果
*/
private static BigDecimal toBigDecimal(Object value, Function<Object, String> toStrFunc) {
if (value instanceof Number) {
return NumberUtil.toBigDecimal((Number) value);
} else if (value instanceof Boolean) {
return ((boolean) value) ? BigDecimal.ONE : BigDecimal.ZERO;
}
//对于Double类型,先要转换为String,避免精度问题
return NumberUtil.toBigDecimal(toStrFunc.apply(value));
}
/**
* 转换为BigInteger<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param toStrFunc 转换为字符串的函数规则
* @return 结果
*/
private static BigInteger toBigInteger(Object value, Function<Object, String> toStrFunc) {
if (value instanceof Long) {
return BigInteger.valueOf((Long) value);
} else if (value instanceof Boolean) {
return (boolean) value ? BigInteger.ONE : BigInteger.ZERO;
}
return NumberUtil.toBigInteger(toStrFunc.apply(value));
}
}
package cn.hutool.core.convert.impl;
import cn.hutool.core.convert.AbstractConverter;
import cn.hutool.core.lang.Opt;
/**
*
* {@link Opt}对象转换器
*
* @author Looly
* @since 5.7.16
*/
public class OptConverter extends AbstractConverter<Opt<?>> {
private static final long serialVersionUID = 1L;
@Override
protected Opt<?> convertInternal(Object value) {
return Opt.ofNullable(value);
}
}
package cn.hutool.core.convert.impl;
import cn.hutool.core.convert.AbstractConverter;
import java.util.Optional;
/**
*
* {@link Optional}对象转换器
*
* @author Looly
* @since 5.0.0
*/
public class OptionalConverter extends AbstractConverter<Optional<?>> {
private static final long serialVersionUID = 1L;
@Override
protected Optional<?> convertInternal(Object value) {
return Optional.ofNullable(value);
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment