mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-07-21 15:09:48 +08:00
enhance EnumConverter
This commit is contained in:
@@ -13,6 +13,8 @@
|
|||||||
* 【http 】 支持patch方法(issue#666@Github)
|
* 【http 】 支持patch方法(issue#666@Github)
|
||||||
* 【crypto】 BCUtil支持更加灵活的密钥类型,增加writePemObject方法
|
* 【crypto】 BCUtil支持更加灵活的密钥类型,增加writePemObject方法
|
||||||
* 【core 】 增加ServiceLoaderUtil
|
* 【core 】 增加ServiceLoaderUtil
|
||||||
|
* 【core 】 增加EnumUtil.getEnumAt方法
|
||||||
|
* 【core 】 增强EnumConvert判断能力(issue#I17082@Gitee)
|
||||||
|
|
||||||
### Bug修复
|
### Bug修复
|
||||||
|
|
||||||
|
@@ -10,7 +10,7 @@ import java.util.*;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import cn.hutool.core.convert.impl.CollectionConverter;
|
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.convert.impl.MapConverter;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.lang.TypeReference;
|
import cn.hutool.core.lang.TypeReference;
|
||||||
@@ -522,7 +522,7 @@ public class Convert {
|
|||||||
* @return Enum
|
* @return Enum
|
||||||
*/
|
*/
|
||||||
public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value, E defaultValue) {
|
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,6 +1,17 @@
|
|||||||
package cn.hutool.core.convert.impl;
|
package cn.hutool.core.convert.impl;
|
||||||
|
|
||||||
import cn.hutool.core.convert.AbstractConverter;
|
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 无泛型检查的枚举转换器
|
* 无泛型检查的枚举转换器
|
||||||
@@ -8,10 +19,12 @@ import cn.hutool.core.convert.AbstractConverter;
|
|||||||
* @author Looly
|
* @author Looly
|
||||||
* @since 4.0.2
|
* @since 4.0.2
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
public class EnumConverter extends AbstractConverter<Object> {
|
public class EnumConverter extends AbstractConverter<Object> {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private static final Map<Class<?>, Map<Class<?>, Method>> VALUE_OF_METHOD_CACHE = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private Class enumClass;
|
private Class enumClass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,11 +38,71 @@ public class EnumConverter extends AbstractConverter<Object> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object convertInternal(Object value) {
|
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
|
@Override
|
||||||
public Class getTargetType() {
|
public Class getTargetType() {
|
||||||
return this.enumClass;
|
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> 枚举类类型
|
* @param <E> 枚举类类型
|
||||||
* @author Looly
|
* @author Looly
|
||||||
* @since 4.0.2
|
* @since 4.0.2
|
||||||
|
* @deprecated 请使用{@link EnumConverter}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class GenericEnumConverter<E extends Enum<E>> extends AbstractConverter<E> {
|
public class GenericEnumConverter<E extends Enum<E>> extends AbstractConverter<E> {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@@ -25,7 +27,13 @@ public class GenericEnumConverter<E extends Enum<E>> extends AbstractConverter<E
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected E convertInternal(Object value) {
|
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
|
@Override
|
||||||
|
@@ -50,6 +50,20 @@ public class EnumUtil {
|
|||||||
return null != e ? e.name() : null;
|
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)}
|
* 字符串转枚举,调用{@link Enum#valueOf(Class, String)}
|
||||||
*
|
*
|
||||||
@@ -206,7 +220,7 @@ public class EnumUtil {
|
|||||||
* @since 4.0.2
|
* @since 4.0.2
|
||||||
*/
|
*/
|
||||||
public static <E extends Enum<E>> LinkedHashMap<String, E> getEnumMap(final Class<E> enumClass) {
|
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()) {
|
for (final E e : enumClass.getEnumConstants()) {
|
||||||
map.put(e.name(), e);
|
map.put(e.name(), e);
|
||||||
}
|
}
|
||||||
@@ -248,7 +262,7 @@ public class EnumUtil {
|
|||||||
/**
|
/**
|
||||||
* 判断某个值是不存在枚举中
|
* 判断某个值是不存在枚举中
|
||||||
*
|
*
|
||||||
* @param <E> 枚举类型
|
* @param <E> 枚举类型
|
||||||
* @param enumClass 枚举类
|
* @param enumClass 枚举类
|
||||||
* @param val 需要查找的值
|
* @param val 需要查找的值
|
||||||
* @return 是否不存在
|
* @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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user