mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
enhance EnumConverter
This commit is contained in:
parent
b740fe6480
commit
c5e4d0ef34
@ -13,6 +13,8 @@
|
||||
* 【http 】 支持patch方法(issue#666@Github)
|
||||
* 【crypto】 BCUtil支持更加灵活的密钥类型,增加writePemObject方法
|
||||
* 【core 】 增加ServiceLoaderUtil
|
||||
* 【core 】 增加EnumUtil.getEnumAt方法
|
||||
* 【core 】 增强EnumConvert判断能力(issue#I17082@Gitee)
|
||||
|
||||
### Bug修复
|
||||
|
||||
|
@ -10,7 +10,7 @@ import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import cn.hutool.core.convert.impl.CollectionConverter;
|
||||
import cn.hutool.core.convert.impl.GenericEnumConverter;
|
||||
import cn.hutool.core.convert.impl.EnumConverter;
|
||||
import cn.hutool.core.convert.impl.MapConverter;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.lang.TypeReference;
|
||||
@ -522,7 +522,7 @@ public class Convert {
|
||||
* @return Enum
|
||||
*/
|
||||
public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value, E defaultValue) {
|
||||
return (new GenericEnumConverter<>(clazz)).convertQuietly(value, defaultValue);
|
||||
return (E) (new EnumConverter(clazz)).convertQuietly(value, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,22 +1,35 @@
|
||||
package cn.hutool.core.convert.impl;
|
||||
|
||||
import cn.hutool.core.convert.AbstractConverter;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
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.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 无泛型检查的枚举转换器
|
||||
*
|
||||
*
|
||||
* @author Looly
|
||||
* @since 4.0.2
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public class EnumConverter extends AbstractConverter<Object> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Map<Class<?>, Map<Class<?>, Method>> VALUE_OF_METHOD_CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
private Class enumClass;
|
||||
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
*
|
||||
* @param enumClass 转换成的目标Enum类
|
||||
*/
|
||||
public EnumConverter(Class enumClass) {
|
||||
@ -25,11 +38,71 @@ public class EnumConverter extends AbstractConverter<Object> {
|
||||
|
||||
@Override
|
||||
protected Object convertInternal(Object value) {
|
||||
return Enum.valueOf(enumClass, convertToStr(value));
|
||||
Enum enumValue = tryConvertEnum(value, this.enumClass);
|
||||
if(null == enumValue && false == value instanceof String){
|
||||
// 最后尝试valueOf转换
|
||||
enumValue = Enum.valueOf(this.enumClass, convertToStr(value));
|
||||
}
|
||||
return enumValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getTargetType() {
|
||||
return this.enumClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试找到类似转换的静态方法调用实现转换
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @param enumClass enum类
|
||||
* @return 对应的枚举值
|
||||
*/
|
||||
protected static Enum tryConvertEnum(Object value, Class enumClass) {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// 尝试查找其它用户自定义方法
|
||||
if(null == enumResult){
|
||||
final Map<Class<?>, Method> valueOfMethods = getValueOfMethods(enumClass);
|
||||
if (MapUtil.isNotEmpty(valueOfMethods)) {
|
||||
final Class<?> valueClass = value.getClass();
|
||||
for (Map.Entry<Class<?>, Method> entry : valueOfMethods.entrySet()) {
|
||||
if (ClassUtil.isAssignable(entry.getKey(), valueClass)) {
|
||||
enumResult = ReflectUtil.invokeStatic(entry.getValue(), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return enumResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用于转换为enum的所有static方法
|
||||
*
|
||||
* @param enumClass 枚举类
|
||||
* @return 转换方法map
|
||||
*/
|
||||
private static Map<Class<?>, Method> getValueOfMethods(Class<?> enumClass) {
|
||||
Map<Class<?>, Method> valueOfMethods = VALUE_OF_METHOD_CACHE.get(enumClass);
|
||||
if (null == valueOfMethods) {
|
||||
valueOfMethods = 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, (existing, replacement) -> existing));
|
||||
VALUE_OF_METHOD_CACHE.put(enumClass, valueOfMethods);
|
||||
}
|
||||
return valueOfMethods;
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,9 @@ import cn.hutool.core.convert.AbstractConverter;
|
||||
* @param <E> 枚举类类型
|
||||
* @author Looly
|
||||
* @since 4.0.2
|
||||
* @deprecated 请使用{@link EnumConverter}
|
||||
*/
|
||||
@Deprecated
|
||||
public class GenericEnumConverter<E extends Enum<E>> extends AbstractConverter<E> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -25,7 +27,13 @@ public class GenericEnumConverter<E extends Enum<E>> extends AbstractConverter<E
|
||||
|
||||
@Override
|
||||
protected E convertInternal(Object value) {
|
||||
return Enum.valueOf(enumClass, convertToStr(value));
|
||||
//noinspection unchecked
|
||||
E enumValue = (E) EnumConverter.tryConvertEnum(value, this.enumClass);
|
||||
if(null == enumValue && false == value instanceof String){
|
||||
// 最后尝试valueOf转换
|
||||
enumValue = Enum.valueOf(this.enumClass, convertToStr(value));
|
||||
}
|
||||
return enumValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -50,6 +50,20 @@ public class EnumUtil {
|
||||
return null != e ? e.name() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串转枚举,调用{@link Enum#valueOf(Class, String)}
|
||||
*
|
||||
* @param <E> 枚举类型泛型
|
||||
* @param enumClass 枚举类
|
||||
* @param index 枚举索引
|
||||
* @return 枚举值,null表示无此对应枚举
|
||||
* @since 5.1.6
|
||||
*/
|
||||
public static <E extends Enum<E>> E getEnumAt(Class<E> enumClass, int index) {
|
||||
final E[] enumConstants = enumClass.getEnumConstants();
|
||||
return index < enumConstants.length ? enumConstants[index] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串转枚举,调用{@link Enum#valueOf(Class, String)}
|
||||
*
|
||||
@ -206,7 +220,7 @@ public class EnumUtil {
|
||||
* @since 4.0.2
|
||||
*/
|
||||
public static <E extends Enum<E>> LinkedHashMap<String, E> getEnumMap(final Class<E> enumClass) {
|
||||
final LinkedHashMap<String, E> map = new LinkedHashMap<String, E>();
|
||||
final LinkedHashMap<String, E> map = new LinkedHashMap<>();
|
||||
for (final E e : enumClass.getEnumConstants()) {
|
||||
map.put(e.name(), e);
|
||||
}
|
||||
@ -248,7 +262,7 @@ public class EnumUtil {
|
||||
/**
|
||||
* 判断某个值是不存在枚举中
|
||||
*
|
||||
* @param <E> 枚举类型
|
||||
* @param <E> 枚举类型
|
||||
* @param enumClass 枚举类
|
||||
* @param val 需要查找的值
|
||||
* @return 是否不存在
|
||||
|
@ -0,0 +1,56 @@
|
||||
package cn.hutool.core.convert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Enum转换单元测试
|
||||
*/
|
||||
public class EnumConvertTest {
|
||||
|
||||
@Test
|
||||
public void convertTest(){
|
||||
TestEnum bbb = Convert.convert(TestEnum.class, "BBB");
|
||||
Assert.assertEquals(TestEnum.B, bbb);
|
||||
|
||||
bbb = Convert.convert(TestEnum.class, 22);
|
||||
Assert.assertEquals(TestEnum.B, bbb);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toEnumTest(){
|
||||
TestEnum ccc = Convert.toEnum(TestEnum.class, "CCC");
|
||||
Assert.assertEquals(TestEnum.C, ccc);
|
||||
|
||||
ccc = Convert.toEnum(TestEnum.class, 33);
|
||||
Assert.assertEquals(TestEnum.C, ccc);
|
||||
}
|
||||
|
||||
enum TestEnum {
|
||||
A, B, C;
|
||||
|
||||
public static TestEnum parse(String str) {
|
||||
switch (str) {
|
||||
case "AAA":
|
||||
return A;
|
||||
case "BBB":
|
||||
return B;
|
||||
case "CCC":
|
||||
return C;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static TestEnum parseByNumber(int i) {
|
||||
switch (i) {
|
||||
case 11:
|
||||
return A;
|
||||
case 22:
|
||||
return B;
|
||||
case 33:
|
||||
return C;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user