[英]Dozer bidirectional mapping (String, String) with custom comverter impossible?
我有一个带有自定义转换器的推土机映射:
<mapping>
<class-a>com.xyz.Customer</class-a>
<class-b>com.xyz.CustomerDAO</class-b>
<field custom-converter="com.xyz.DozerEmptyString2NullConverter">
<a>customerName</a>
<b>customerName</b>
</field>
</mapping>
和转换器:
public class DozerEmptyString2NullConverter extends DozerConverter<String, String> {
public DozerEmptyString2NullConverter() {
super(String.class, String.class);
}
public String convertFrom(String source, String destination) {
String ret = null;
if (source != null) {
if (!source.equals(""))
{
ret = StringFormatter.wildcard(source);
}
}
return ret;
}
public String convertTo(String source, String destination) {
return source;
}
}
当我沿一个方向(客户-> CustomerDAO)调用映射器时,将调用方法“ convertTo”。
由于Dozer能够处理双向映射,因此我希望,一旦我以相反的方向调用映射器,就会调用方法“ convertFrom”。
但是永远不会调用convertTo方法。
我怀疑问题在于,这两种类型都是Strings-但是如何使这项工作有效?
解决方法是创建两个单向映射,这是标准解决方案,还是行为错误?
是的,问题在于您的源类和目标类是相同的。 这是DozerConverter
的推土机源 :
public Object convert(Object existingDestinationFieldValue, Object sourceFieldValue, Class<?> destinationClass, Class<?> sourceClass) {
Class<?> wrappedDestinationClass = ClassUtils.primitiveToWrapper(destinationClass);
Class<?> wrappedSourceClass = ClassUtils.primitiveToWrapper(sourceClass);
if (prototypeA.equals(wrappedDestinationClass)) {
return convertFrom((B) sourceFieldValue, (A) existingDestinationFieldValue);
} else if (prototypeB.equals(wrappedDestinationClass)) {
return convertTo((A) sourceFieldValue, (B) existingDestinationFieldValue);
} else if (prototypeA.equals(wrappedSourceClass)) {
return convertTo((A) sourceFieldValue, (B) existingDestinationFieldValue);
} else if (prototypeB.equals(wrappedSourceClass)) {
return convertFrom((B) sourceFieldValue, (A) existingDestinationFieldValue);
} else if (prototypeA.isAssignableFrom(wrappedDestinationClass)) {
return convertFrom((B) sourceFieldValue, (A) existingDestinationFieldValue);
} else if (prototypeB.isAssignableFrom(wrappedDestinationClass)) {
return convertTo((A) sourceFieldValue, (B) existingDestinationFieldValue);
} else if (prototypeA.isAssignableFrom(wrappedSourceClass)) {
return convertTo((A) sourceFieldValue, (B) existingDestinationFieldValue);
} else if (prototypeB.isAssignableFrom(wrappedSourceClass)) {
return convertFrom((B) sourceFieldValue, (A) existingDestinationFieldValue);
} else {
throw new MappingException("Destination Type (" + wrappedDestinationClass.getName()
+ ") is not accepted by this Custom Converter ("
+ this.getClass().getName() + ")!");
}
}
不必使用convertFrom
和convertTo
方法(它们是新API的一部分),而是必须按照本教程中所示的那样实现CustomConverter.convert
的原始方法。
我遇到了同样的问题,目前(从Dozer 5.5.x开始)没有简单的方法,但是有一个复杂的方法。
请注意,它依赖于在JVM中未启用安全管理器,否则您将需要在安全规则中添加少量权限。 这是因为此解决方案使用反射来访问Dozer类的私有字段。
您需要扩展2个类: DozerBeanMapper
和MappingProcessor
。 您还需要枚举的方向和接口,以从上述类中获取方向。
枚举:
public enum Direction {
TO,
FROM;
}
界面:
public interface DirectionAware {
Direction getDirection();
}
扩展DozerBeanMapper
的类:
public class DirectionAwareDozerBeanMapper extends DozerBeanMapper implements DirectionAware {
private Direction direction;
public DirectionAwareDozerBeanMapper(Direction direction) {
super();
this.direction = direction;
}
public DirectionAwareDozerBeanMapper(Direction direction, List<String> mappingFiles) {
super(mappingFiles);
this.direction = direction;
}
@Override
protected Mapper getMappingProcessor() {
try {
Method m = DozerBeanMapper.class.getDeclaredMethod("initMappings");
m.setAccessible(true);
m.invoke(this);
} catch (NoSuchMethodException|SecurityException|IllegalAccessException|IllegalArgumentException|InvocationTargetException e) {
// Handle the exception as you want
}
ClassMappings arg1 = (ClassMappings)getField("customMappings");
Configuration arg2 = (Configuration)getFieldValue("globalConfiguration");
CacheManager arg3 = (CacheManager)getField("cacheManager");
StatisticsManager arg4 = (StatisticsManager)getField("statsMgr");
List<CustomConverter> arg5 = (List<CustomConverter>)getField("customConverters");
DozerEventManager arg6 = (DozerEventManager)getField("eventManager");
Map<String, CustomConverter> arg7 = (Map<String, CustomConverter>)getField("customConvertersWithId");
Mapper mapper = new DirectionAwareMappingProcessor(arg1, arg2, arg3, arg4, arg5,
arg6, getCustomFieldMapper(), arg7, direction);
return mapper;
}
private Object getField(String fieldName) {
try {
Field field = DozerBeanMapper.class.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(this);
} catch (NoSuchFieldException|SecurityException|IllegalArgumentException|IllegalAccessException e) {
// Handle the exception as you want
}
return null;
}
public Direction getDirection() {
return direction;
}
}
扩展MappingProcessor
的类:
public class DirectionAwareMappingProcessor extends MappingProcessor implements DirectionAware {
private Direction direction;
protected DirectionAwareMappingProcessor(ClassMappings arg1, Configuration arg2, CacheManager arg3, StatisticsManager arg4, List<CustomConverter> arg5, DozerEventManager arg6, CustomFieldMapper arg7, Map<String, CustomConverter> arg8, Direction direction) {
super(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
this.direction = direction;
}
public Direction getDirection() {
return direction;
}
}
现在,用法。
1)每当您要映射相同的原始类型(例如String-String)时,都将具有该类型的DozerConverter
用作两个参数,作为dozer映射文件中的自定义转换器。 此类转换器的实现应扩展: DozerConverter<String,String>
并实现MapperAware
接口。 这一点很重要,因为您可以使用MapperAware
,因为有了Mapper,您就可以将其投射到DirectionAware
,然后获取方向。
例如:
public class MyMapper extends DozerConverter<String, String> implements MapperAware {
private DirectionAware dirAware;
public MyMapper(Class<String> cls) {
super(cls, cls);
}
@Override
public Object convert(Object existingDestinationFieldValue, Object sourceFieldValue, Class<String> destinationClass, Class<String> sourceClass) {
if (dirAware.getDirection() == Direction.FROM) {
// TODO convert sourceFieldValue for "FROM" direction and return it
} else {
// TODO convert sourceFieldValue for "TO" direction and return it
}
}
@Override
public void setMapper(Mapper mapper) {
dirAware = (DirectionAware)mapper;
}
}
2)您需要创建2个全局Dozer映射器对象,每个映射方向一个。 应该为它们配置相同的映射文件,但使用不同的direction参数。 例如:
DirectionAwareDozerBeanMapper mapperFrom = DirectionAwareDozerBeanMapper(mappingFiles, Direction.FROM);
DirectionAwareDozerBeanMapper mapperTo = DirectionAwareDozerBeanMapper(mappingFiles, Direction.TO);
当然,您将需要使用正确的映射器(从/到)以向自定义映射器提供有关映射方向的信息。
几年后,我遇到了同样的问题,以某种方式,作为新API的DozerConverter API仍然不能作为双向正常工作!
因此,我没有创建这里建议的所有这些复杂解决方案,而是创建了2个单向映射来解决此问题(使用)。 然后我的转换开始工作。 我正在使用DozerConverter api,如下所示:
公共类MapToStringConverter扩展了DozerConverter
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.