diff --git a/CHANGELOG.md b/CHANGELOG.md index 89ad236a9..3ea0bde8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------------------------------------- -# 5.7.13 (2021-09-13) +# 5.7.13 (2021-09-14) ### 🐣新特性 * 【core 】 CsvReadConfig增加trimField选项(issue#I49M0C@Gitee) @@ -17,6 +17,7 @@ * 【core 】 修复StrJoiner.append配置丢失问题(issue#I49K1L@Gitee) * 【core 】 修复EscapeUtil特殊字符的hex长度不足导致的问题(issue#I49JU8@Gitee) * 【core 】 修复UrlBuilder对Fragment部分编码问题(issue#I49KAL@Gitee) +* 【core 】 修复Enum转换的bug(issue#I49VZB@Gitee) ------------------------------------------------------------------------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/EnumConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/EnumConverter.java index 349223ea5..ba9e2db96 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/EnumConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/EnumConverter.java @@ -1,6 +1,7 @@ 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.lang.SimpleCache; import cn.hutool.core.map.MapUtil; @@ -41,10 +42,15 @@ public class EnumConverter extends AbstractConverter { protected Object convertInternal(Object value) { Enum enumValue = tryConvertEnum(value, this.enumClass); if (null == enumValue && false == value instanceof String) { - // 最后尝试valueOf转换 + // 最后尝试先将value转String,再valueOf转换 enumValue = Enum.valueOf(this.enumClass, convertToStr(value)); } - return enumValue; + + if (null != enumValue) { + return enumValue; + } + + throw new ConvertException("Can not convert {} to {}", value, this.enumClass); } @Override @@ -53,9 +59,13 @@ public class EnumConverter extends AbstractConverter { } /** - * 尝试找到类似转换的静态方法调用实现转换且优先使用
- * 约定枚举类应该提供 valueOf(String) 和 valueOf(Integer)用于转换 - * oriInt /name 转换托底 + * 尝试转换,转换规则为: + * * * @param value 被转换的值 * @param enumClass enum类 @@ -67,10 +77,9 @@ public class EnumConverter extends AbstractConverter { } // EnumItem实现转换 - Enum enumResult = null; if (EnumItem.class.isAssignableFrom(enumClass)) { final EnumItem first = (EnumItem) EnumUtil.getEnumAt(enumClass, 0); - if(null != first){ + if (null != first) { if (value instanceof Integer) { return (Enum) first.fromInt((Integer) value); } else if (value instanceof String) { @@ -81,14 +90,18 @@ public class EnumConverter extends AbstractConverter { // 用户自定义方法 // 查找枚举中所有返回值为目标枚举对象的方法,如果发现方法参数匹配,就执行之 - final Map, Method> methodMap = getMethodMap(enumClass); - if (MapUtil.isNotEmpty(methodMap)) { - final Class valueClass = value.getClass(); - for (Map.Entry, Method> entry : methodMap.entrySet()) { - if (ClassUtil.isAssignable(entry.getKey(), valueClass)) { - enumResult = ReflectUtil.invokeStatic(entry.getValue(), value); + try { + final Map, Method> methodMap = getMethodMap(enumClass); + if (MapUtil.isNotEmpty(methodMap)) { + final Class valueClass = value.getClass(); + for (Map.Entry, 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 性别编码为例,对应整数并非连续数字会导致数字转枚举时失败 @@ -98,17 +111,17 @@ public class EnumConverter extends AbstractConverter { //5 - 女性改(变)为男性 //6 - 男性改(变)为女性 //9 - 未说明的性别 - if (null == enumResult) { - 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 - } + 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; } @@ -119,11 +132,11 @@ public class EnumConverter extends AbstractConverter { * @return 转换方法map,key为方法参数类型,value为方法 */ private static Map, Method> getMethodMap(Class enumClass) { - return VALUE_OF_METHOD_CACHE.get(enumClass, ()-> Arrays.stream(enumClass.getMethods()) + return VALUE_OF_METHOD_CACHE.get(enumClass, () -> 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))); + .collect(Collectors.toMap(m -> m.getParameterTypes()[0], m -> m, (k1, k2) -> k1))); } } diff --git a/hutool-json/src/test/java/IssueI49VZBTest.java b/hutool-json/src/test/java/IssueI49VZBTest.java new file mode 100644 index 000000000..d6abef562 --- /dev/null +++ b/hutool-json/src/test/java/IssueI49VZBTest.java @@ -0,0 +1,75 @@ +import cn.hutool.core.convert.Convert; +import cn.hutool.json.JSONUtil; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.junit.Assert; +import org.junit.Test; + +import java.util.stream.Stream; + +/** + * https://gitee.com/dromara/hutool/issues/I49VZB + */ +public class IssueI49VZBTest { + public enum NBCloudKeyType { + /** + * 指纹-视频云 + */ + fingerPrint, + /** + * 密码 + */ + password, + /** + * 卡片 + */ + card, + /** + * 临时密码 + */ + snapKey; + + public static NBCloudKeyType find(String value) { + return Stream.of(values()).filter(e -> e.getValue().equalsIgnoreCase(value)).findFirst() + .orElse(null); + } + + + public static NBCloudKeyType downFind(String keyType) { + if (fingerPrint.name().equals(keyType.toLowerCase())) { + return NBCloudKeyType.fingerPrint; + } else { + return find(keyType); + } + } + + public String getValue() { + return super.toString().toLowerCase(); + } + + } + + @Data + @EqualsAndHashCode(callSuper = false) + public static class UPOpendoor { + + private String keyId; + private NBCloudKeyType type; + private String time; + private int result; + + } + + @Test + public void toBeanTest(){ + String str = "{type: \"password\"}"; + final UPOpendoor upOpendoor = JSONUtil.toBean(str, UPOpendoor.class); + Assert.assertEquals(NBCloudKeyType.password, upOpendoor.getType()); + } + + @Test + public void enumConvertTest(){ + final NBCloudKeyType type = Convert.toEnum(NBCloudKeyType.class, "snapKey"); + Assert.assertEquals(NBCloudKeyType.snapKey, type); + } +}