mirror of
				https://gitee.com/dromara/hutool.git
				synced 2025-10-26 18:59:23 +08:00 
			
		
		
		
	修复Pair反序列化报错问题
This commit is contained in:
		| @@ -6,12 +6,7 @@ import cn.hutool.core.convert.impl.MapConverter; | ||||
| import cn.hutool.core.lang.Assert; | ||||
| import cn.hutool.core.lang.TypeReference; | ||||
| import cn.hutool.core.text.UnicodeUtil; | ||||
| import cn.hutool.core.util.ByteUtil; | ||||
| import cn.hutool.core.util.CharUtil; | ||||
| import cn.hutool.core.util.CharsetUtil; | ||||
| import cn.hutool.core.util.ClassUtil; | ||||
| import cn.hutool.core.util.HexUtil; | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import cn.hutool.core.util.*; | ||||
|  | ||||
| import java.lang.reflect.Type; | ||||
| import java.math.BigDecimal; | ||||
| @@ -19,14 +14,7 @@ import java.math.BigInteger; | ||||
| import java.nio.charset.Charset; | ||||
| import java.time.Instant; | ||||
| import java.time.LocalDateTime; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collection; | ||||
| import java.util.Date; | ||||
| import java.util.HashMap; | ||||
| import java.util.HashSet; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.Set; | ||||
| import java.util.*; | ||||
| import java.util.concurrent.TimeUnit; | ||||
|  | ||||
| /** | ||||
|   | ||||
| @@ -1,48 +1,13 @@ | ||||
| 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.convert.impl.*; | ||||
| import cn.hutool.core.date.DateTime; | ||||
| import cn.hutool.core.lang.Opt; | ||||
| import cn.hutool.core.lang.Pair; | ||||
| import cn.hutool.core.lang.TypeReference; | ||||
| import cn.hutool.core.map.SafeConcurrentHashMap; | ||||
| import cn.hutool.core.util.ClassUtil; | ||||
| import cn.hutool.core.util.ObjUtil; | ||||
| 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 cn.hutool.core.util.*; | ||||
|  | ||||
| import java.io.Serializable; | ||||
| import java.lang.ref.SoftReference; | ||||
| @@ -54,35 +19,10 @@ 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.*; | ||||
| 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; | ||||
| import java.util.*; | ||||
| import java.util.concurrent.atomic.*; | ||||
|  | ||||
| /** | ||||
|  * 转换器登记中心 | ||||
| @@ -357,6 +297,12 @@ public class ConverterRegistry implements Serializable { | ||||
| 			return (T) mapConverter.convert(value, (Map<?, ?>) defaultValue); | ||||
| 		} | ||||
|  | ||||
| 		// Map类型(不可以默认强转) | ||||
| 		if (Map.Entry.class.isAssignableFrom(rowType)) { | ||||
| 			final EntryConverter mapConverter = new EntryConverter(type); | ||||
| 			return (T) mapConverter.convert(value, (Map.Entry<?, ?>) defaultValue); | ||||
| 		} | ||||
|  | ||||
| 		// 默认强转 | ||||
| 		if (rowType.isInstance(value)) { | ||||
| 			return (T) value; | ||||
| @@ -462,6 +408,7 @@ public class ConverterRegistry implements Serializable { | ||||
| 		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 | ||||
| 		defaultConverterMap.put(Pair.class, new PairConverter(Pair.class));// since 5.8.17 | ||||
|  | ||||
| 		return this; | ||||
| 	} | ||||
|   | ||||
| @@ -0,0 +1,115 @@ | ||||
| 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) | ||||
| 		); | ||||
| 	} | ||||
| } | ||||
| @@ -0,0 +1,115 @@ | ||||
| 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 PairConverter extends AbstractConverter<Pair<?, ?>> { | ||||
|  | ||||
| 	/** Pair类型 */ | ||||
| 	private final Type pairType; | ||||
| 	/** 键类型 */ | ||||
| 	private final Type keyType; | ||||
| 	/** 值类型 */ | ||||
| 	private final Type valueType; | ||||
|  | ||||
| 	/** | ||||
| 	 * 构造,Pair的key和value泛型类型自动获取 | ||||
| 	 * | ||||
| 	 * @param pairType Map类型 | ||||
| 	 */ | ||||
| 	public PairConverter(Type pairType) { | ||||
| 		this(pairType, null, null); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * 构造 | ||||
| 	 * | ||||
| 	 * @param pairType Pair类型 | ||||
| 	 * @param keyType 键类型 | ||||
| 	 * @param valueType 值类型 | ||||
| 	 */ | ||||
| 	public PairConverter(Type pairType, Type keyType, Type valueType) { | ||||
| 		this.pairType = pairType; | ||||
| 		this.keyType = keyType; | ||||
| 		this.valueType = valueType; | ||||
| 	} | ||||
|  | ||||
| 	@SuppressWarnings("rawtypes") | ||||
| 	@Override | ||||
| 	protected Pair<?, ?> convertInternal(Object value) { | ||||
| 		Map map = null; | ||||
| 		if (value instanceof Map.Entry) { | ||||
| 			final Map.Entry entry = (Map.Entry) value; | ||||
| 			map = MapUtil.of(entry.getKey(), entry.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 mapToPair(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 Pair<?, ?> mapToPair(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 (Pair<?, ?>) ReflectUtil.newInstance(TypeUtil.getClass(targetType), | ||||
| 			TypeUtil.isUnknown(keyType) ? key : convert.convert(keyType, key), | ||||
| 			TypeUtil.isUnknown(valueType) ? value : convert.convert(valueType, value) | ||||
| 		); | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Looly
					Looly