mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-07-21 15:09:48 +08:00
fix bug
This commit is contained in:
@@ -12,18 +12,23 @@
|
||||
|
||||
package org.dromara.hutool.core.convert;
|
||||
|
||||
import org.dromara.hutool.core.lang.Assert;
|
||||
import org.dromara.hutool.core.reflect.TypeUtil;
|
||||
import org.dromara.hutool.core.array.ArrayUtil;
|
||||
import org.dromara.hutool.core.reflect.TypeUtil;
|
||||
import org.dromara.hutool.core.util.CharUtil;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 抽象转换器,提供通用的转换逻辑,同时通过convertInternal实现对应类型的专属逻辑<br>
|
||||
* 转换器不会抛出转换异常,转换失败时会返回{@code null}
|
||||
* 转换器不会抛出转换异常,转换失败时会返回{@code null}<br>
|
||||
* 抽象转换器的默认逻辑不适用于有泛型参数的对象,如Map、Collection、Entry等。通用逻辑包括:
|
||||
* <ul>
|
||||
* <li>value为{@code null}时返回{@code null}</li>
|
||||
* <li>目标类型是{@code null}或者{@link java.lang.reflect.TypeVariable}时,抛出{@link ConvertException}异常</li>
|
||||
* <li>目标类型非class时,抛出{@link IllegalArgumentException}</li>
|
||||
* <li>目标类型为值的父类或同类,直接强转返回</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
@@ -31,19 +36,21 @@ public abstract class AbstractConverter implements Converter, Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Object convert(final Type targetType, final Object value) {
|
||||
public Object convert(final Type targetType, final Object value) throws ConvertException{
|
||||
if (null == value) {
|
||||
return null;
|
||||
}
|
||||
if (TypeUtil.isUnknown(targetType)) {
|
||||
throw new ConvertException("Unsupported convert to unKnow type: {}", targetType);
|
||||
throw new ConvertException("Unsupported convert to unKnown type: {}", targetType);
|
||||
}
|
||||
|
||||
final Class<?> targetClass = TypeUtil.getClass(targetType);
|
||||
Assert.notNull(targetClass, "Target type is not a class!");
|
||||
if(null == targetClass){
|
||||
throw new ConvertException("Target type [{}] is not a class!", targetType);
|
||||
}
|
||||
|
||||
// 尝试强转
|
||||
if (targetClass.isInstance(value) && false == Map.class.isAssignableFrom(targetClass)) {
|
||||
if (targetClass.isInstance(value)) {
|
||||
// 除Map外,已经是目标类型,不需要转换(Map类型涉及参数类型,需要单独转换)
|
||||
return CastUtil.castTo(targetClass, value);
|
||||
}
|
||||
|
@@ -13,13 +13,7 @@
|
||||
package org.dromara.hutool.core.convert;
|
||||
|
||||
import org.dromara.hutool.core.bean.BeanUtil;
|
||||
import org.dromara.hutool.core.convert.impl.ArrayConverter;
|
||||
import org.dromara.hutool.core.convert.impl.BeanConverter;
|
||||
import org.dromara.hutool.core.convert.impl.CollectionConverter;
|
||||
import org.dromara.hutool.core.convert.impl.EnumConverter;
|
||||
import org.dromara.hutool.core.convert.impl.MapConverter;
|
||||
import org.dromara.hutool.core.convert.impl.NumberConverter;
|
||||
import org.dromara.hutool.core.convert.impl.PrimitiveConverter;
|
||||
import org.dromara.hutool.core.convert.impl.*;
|
||||
import org.dromara.hutool.core.reflect.TypeReference;
|
||||
import org.dromara.hutool.core.reflect.TypeUtil;
|
||||
import org.dromara.hutool.core.util.ObjUtil;
|
||||
@@ -195,6 +189,11 @@ public class CompositeConverter extends RegisterConverter {
|
||||
return (T) MapConverter.INSTANCE.convert(type, value, (Map<?, ?>) defaultValue);
|
||||
}
|
||||
|
||||
// issue#I6SZYB Entry类(含有泛型参数,不可以默认强转)
|
||||
if(Map.Entry.class.isAssignableFrom(rowType)){
|
||||
return (T) EntryConverter.INSTANCE.convert(type, value);
|
||||
}
|
||||
|
||||
// 默认强转
|
||||
if (rowType.isInstance(value)) {
|
||||
return (T) value;
|
||||
|
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 2023 looly(loolly@aliyun.com)
|
||||
* Hutool is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
package org.dromara.hutool.core.convert.impl;
|
||||
|
||||
import org.dromara.hutool.core.bean.BeanUtil;
|
||||
import org.dromara.hutool.core.convert.CompositeConverter;
|
||||
import org.dromara.hutool.core.convert.ConvertException;
|
||||
import org.dromara.hutool.core.convert.Converter;
|
||||
import org.dromara.hutool.core.map.MapUtil;
|
||||
import org.dromara.hutool.core.reflect.ConstructorUtil;
|
||||
import org.dromara.hutool.core.reflect.TypeReference;
|
||||
import org.dromara.hutool.core.reflect.TypeUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.util.CharUtil;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* {@link Map.Entry} 转换器,支持以下类型转为Entry
|
||||
* <ul>
|
||||
* <li>{@link Map}</li>
|
||||
* <li>{@link Map.Entry}</li>
|
||||
* <li>带分隔符的字符串,支持分隔符{@code :}、{@code =}、{@code ,}</li>
|
||||
* <li>Bean,包含{@code getKey}和{@code getValue}方法</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author looly
|
||||
*/
|
||||
public class EntryConverter implements Converter {
|
||||
|
||||
/**
|
||||
* 单例
|
||||
*/
|
||||
public static final EntryConverter INSTANCE = new EntryConverter();
|
||||
|
||||
@Override
|
||||
public Object convert(Type targetType, final 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
|
||||
* @throws ConvertException 转换异常或不支持的类型
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Map.Entry<?, ?> convert(final Type targetType, final Type keyType, final Type valueType, final Object value)
|
||||
throws ConvertException {
|
||||
Map map = null;
|
||||
if (value instanceof Map.Entry) {
|
||||
final Map.Entry entry = (Map.Entry) value;
|
||||
map = MapUtil.of(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (value instanceof Map) {
|
||||
map = (Map) value;
|
||||
} else if (value instanceof CharSequence) {
|
||||
final CharSequence str = (CharSequence) value;
|
||||
map = strToMap(str);
|
||||
} else if (BeanUtil.isBean(value.getClass())) {
|
||||
map = BeanUtil.beanToMap(value);
|
||||
}
|
||||
|
||||
if (null != map) {
|
||||
return mapToEntry(targetType, 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,
|
||||
c -> c == CharUtil.COLON || c == CharUtil.EQUAL || c == CharUtil.COMMA,
|
||||
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 CompositeConverter convert = CompositeConverter.getInstance();
|
||||
return (Map.Entry<?, ?>) ConstructorUtil.newInstance(TypeUtil.getClass(targetType),
|
||||
TypeUtil.isUnknown(keyType) ? key : convert.convert(keyType, key),
|
||||
TypeUtil.isUnknown(valueType) ? value : convert.convert(valueType, value)
|
||||
);
|
||||
}
|
||||
}
|
@@ -13,13 +13,12 @@
|
||||
package org.dromara.hutool.core.convert.impl;
|
||||
|
||||
import org.dromara.hutool.core.bean.BeanUtil;
|
||||
import org.dromara.hutool.core.convert.ConvertException;
|
||||
import org.dromara.hutool.core.convert.CompositeConverter;
|
||||
import org.dromara.hutool.core.convert.ConvertException;
|
||||
import org.dromara.hutool.core.convert.Converter;
|
||||
import org.dromara.hutool.core.map.MapUtil;
|
||||
import org.dromara.hutool.core.reflect.TypeReference;
|
||||
import org.dromara.hutool.core.reflect.TypeUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Type;
|
||||
@@ -27,7 +26,11 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* {@link Map} 转换器
|
||||
* {@link Map} 转换器,通过预定义key和value的类型,实现:
|
||||
* <ul>
|
||||
* <li>Map 转 Map,key和value类型自动转换</li>
|
||||
* <li>Bean 转 Map,字段和字段值类型自动转换</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Looly
|
||||
* @since 3.0.8
|
||||
@@ -35,6 +38,9 @@ import java.util.Objects;
|
||||
public class MapConverter implements Converter, Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 单例
|
||||
*/
|
||||
public static MapConverter INSTANCE = new MapConverter();
|
||||
|
||||
@Override
|
||||
@@ -56,9 +62,11 @@ public class MapConverter implements Converter, Serializable {
|
||||
* @param valueType 值类型
|
||||
* @param value 被转换的值
|
||||
* @return 转换后的Map
|
||||
* @throws ConvertException 转换异常或不支持的类型
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Map<?, ?> convert(final Type targetType, final Type keyType, final Type valueType, final Object value) {
|
||||
public Map<?, ?> convert(final Type targetType, final Type keyType, final Type valueType, final Object value)
|
||||
throws ConvertException{
|
||||
Map map;
|
||||
if (value instanceof Map) {
|
||||
final Class<?> valueClass = value.getClass();
|
||||
@@ -79,7 +87,7 @@ public class MapConverter implements Converter, Serializable {
|
||||
// 二次转换,转换键值类型
|
||||
map = convert(targetType, keyType, valueType, map);
|
||||
} else {
|
||||
throw new UnsupportedOperationException(StrUtil.format("Unsupported toMap value type: {}", value.getClass().getName()));
|
||||
throw new ConvertException("Unsupported to map from [{}] of type: {}", value, value.getClass().getName());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
@@ -93,10 +101,9 @@ public class MapConverter implements Converter, Serializable {
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private void convertMapToMap(final Type keyType, final Type valueType, final Map<?, ?> srcMap, final Map targetMap) {
|
||||
final CompositeConverter convert = CompositeConverter.getInstance();
|
||||
srcMap.forEach((key, value) -> {
|
||||
key = TypeUtil.isUnknown(keyType) ? key : convert.convert(keyType, key, null);
|
||||
value = TypeUtil.isUnknown(valueType) ? value : convert.convert(valueType, value, null);
|
||||
targetMap.put(key, value);
|
||||
});
|
||||
srcMap.forEach((key, value) -> targetMap.put(
|
||||
TypeUtil.isUnknown(keyType) ? key : convert.convert(keyType, key),
|
||||
TypeUtil.isUnknown(valueType) ? value : convert.convert(valueType, value)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@@ -13,6 +13,11 @@
|
||||
/**
|
||||
* 万能类型转换器以及各种类型转换的实现类,其中Convert为转换器入口,提供各种toXXX方法和convert方法
|
||||
*
|
||||
* <p>
|
||||
* 转换器是典型的策略模式应用,通过实现{@link org.dromara.hutool.core.convert.Converter} 接口,
|
||||
* 自定义转换策略。Hutool提供了常用类型的转换策略。
|
||||
* </p>
|
||||
*
|
||||
* @author looly
|
||||
*
|
||||
*/
|
||||
|
@@ -27,6 +27,19 @@ import java.util.Map;
|
||||
public class MutableEntry<K, V> extends AbsEntry<K, V> implements Mutable<Map.Entry<K, V>>, Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 创建{@code MutableEntry}
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param <K> 键类型
|
||||
* @param <V> 值类型
|
||||
* @return
|
||||
*/
|
||||
public static <K, V> MutableEntry<K, V> of(final K key, final V value) {
|
||||
return new MutableEntry<>(key, value);
|
||||
}
|
||||
|
||||
protected K key;
|
||||
protected V value;
|
||||
|
||||
|
Reference in New Issue
Block a user