DozerBeanMapper转换枚举类有问题

我们在项目中使用了com.github.dozermapper的包用来做类的属性赋值,版本为6.5.2。

其中有srcObj(来源类)中status属性为Integer类型,destObj(目标类)中status的属性为一个枚举类。

该枚举类重要的部分如下图所示

public enum DBStatusEnum {
  FAIL(-1, "失败"),
  INVALID(0, "无效"),
  VALID(1, "有效"),
  DELETED(2, "删除");
  

使用转换工具的下列方法,对枚举类的转换,是错误的

map(object, destinationClass)

为此,我翻了一下它的源码,在

com.github.dozermapper.core.converters包下的类PrimitiveOrWrapperConverter里,根据目标属性值的类,拿取具体的转换器
private Converter getPrimitiveOrWrapperConverter(Class destClass, DateFormatContainer dateFormatContainer, String destFieldName, Object destObj) {
    if (String.class.equals(destClass)) {
        return new StringConverter(dateFormatContainer);
    } else {
        Converter result = (Converter)CONVERTER_MAP.get(ClassUtils.primitiveToWrapper(destClass));
        if (result == null) {
            if (Date.class.isAssignableFrom(destClass)) {
                result = new DateConverter(dateFormatContainer.getDateFormat());
            } else if (Calendar.class.isAssignableFrom(destClass)) {
                result = new CalendarConverter(dateFormatContainer.getDateFormat());
            } else if (XMLGregorianCalendar.class.isAssignableFrom(destClass)) {
                result = new XMLGregorianCalendarConverter(dateFormatContainer.getDateFormat());
            } else if (MappingUtils.isEnumType(destClass)) {
                result = new EnumConverter();
            } else if (JAXBElement.class.isAssignableFrom(destClass) && destFieldName != null) {
                result = new JAXBElementConverter(destObj.getClass().getCanonicalName(), destFieldName, dateFormatContainer.getDateFormat(), this.beanContainer);
            } else if (isLocalTime(destClass)) {
                result = new LocalDateTimeConverter(dateFormatContainer.getDateTimeFormatter());
            } else if (isOffsetTime(destClass)) {
                result = new OffsetDateTimeConverter(dateFormatContainer.getDateTimeFormatter());
            } else if (ZonedDateTime.class.isAssignableFrom(destClass)) {
                result = new ZonedDateTimeConverter(dateFormatContainer.getDateTimeFormatter());
            } else if (Instant.class.isAssignableFrom(destClass)) {
                result = new InstantConverter();
            }
        }

        return (Converter)(result == null ? new StringConstructorConverter(dateFormatContainer) : result);
    }
}

枚举类型的复制,走的

MappingUtils.isEnumType(destClass)

这个分支 ,使用了

new EnumConverter()的转换类

我们具体点进去看看,枚举类到底是怎么转换的

public Object convert(Class destClass, Object srcObj) {
    if (null == srcObj) {
        MappingUtils.throwMappingException("Cannot convert null to enum of type " + destClass);
    }

    try {
        if (!srcObj.getClass().equals(Byte.class) && !srcObj.getClass().equals(Byte.TYPE)) {
            if (!srcObj.getClass().equals(Short.class) && !srcObj.getClass().equals(Short.TYPE)) {
                if (!srcObj.getClass().equals(Integer.class) && !srcObj.getClass().equals(Integer.TYPE)) {
                    if (!srcObj.getClass().equals(Long.class) && !srcObj.getClass().equals(Long.TYPE)) {
                        return Enum.class.isAssignableFrom(srcObj.getClass()) ? Enum.valueOf(destClass, ((Enum)srcObj).name()) : Enum.valueOf(destClass, srcObj.toString());
                    } else {
                        return EnumUtils.getEnumList(destClass).get(((Long)srcObj).intValue());
                    }
                } else {
                    return EnumUtils.getEnumList(destClass).get((Integer)srcObj);
                }
            } else {
                return EnumUtils.getEnumList(destClass).get(((Short)srcObj).intValue());
            }
        } else {
            return EnumUtils.getEnumList(destClass).get(((Byte)srcObj).intValue());
        }
    } catch (Exception var4) {
        Exception e = var4;
        MappingUtils.throwMappingException("Cannot convert [" + srcObj + "] to enum of type " + destClass, e);
        return srcObj;
    }
}
public static <E extends Enum<E>> List<E> getEnumList(Class<E> enumClass) {
    return new ArrayList(Arrays.asList(enumClass.getEnumConstants()));
}
public T[] getEnumConstants() {
    T[] values = getEnumConstantsShared();
    return (values != null) ? values.clone() : null;
}

/**
 * Returns the elements of this enum class or null if this
 * Class object does not represent an enum type;
 * identical to getEnumConstants except that the result is
 * uncloned, cached, and shared by all callers.
 */
T[] getEnumConstantsShared() {
    if (enumConstants == null) {
        if (!isEnum()) return null;
        try {
            final Method values = getMethod("values");
            java.security.AccessController.doPrivileged(
                new java.security.PrivilegedAction<Void>() {
                    public Void run() {
                            values.setAccessible(true);
                            return null;
                        }
                    });
            @SuppressWarnings("unchecked")
            T[] temporaryConstants = (T[])values.invoke(null);
            enumConstants = temporaryConstants;
        }
        // These can happen when users concoct enum-like classes
        // that don't comply with the enum spec.
        catch (InvocationTargetException | NoSuchMethodException |
               IllegalAccessException ex) { return null; }
    }
    return enumConstants;
}

到此就很明白了, 比如我来源类里,对应的值是1,这玩意,就会将枚举类里,排第2个的值返回来,跟你定义的值无关,跟枚举类里的值的顺序有关,顺序从0开始排序。

就是它把枚举类里的内容,拉成了一个List,来源的值,作为这个List的index去拿转换后的值

这样,只有当你枚举类里值的定义,从0开始,并且不是乱序,才会复制正确

如果你枚举类的值与排序错乱了,就G了,大家需要注意啊

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

rgbhi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值