我们在项目中使用了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了,大家需要注意啊