Bidirectional mapping Dozer (String, String) with user controller impossible?

I have a Dozer mapping with a custom converter:

<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> 

And the converter:

 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; } } 

When I call mapper in one direction (Customer -> CustomerDAO), the 'convertTo' method is called.

Since Dozer is capable of handling bi-directional mapping, I expect that as soon as I call the cartuper in the opposite direction, the convertFrom method is called.

But the convertTo method is never called.

I suspect the problem is that both types are strings - but how can I do this work?

As a workaround, I created two unidirectional mappings, is this a standard solution or is it a behavior bug?

+4
source share
3 answers

Yes, the problem is that your source and target classes are the same. Here's the dozer source for the 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() + ")!"); } } 

Instead of using the convertFrom and convertTo (which are part of the new API) do it your own way, you need to implement CustomConverter.convert , as shown in the tutorial .

+2
source

I had the same problem, and currently (like Dozer 5.5.x) there is no easy way, but there is a complicated one.

Note that it relies on the absence of a security manager in the JVM, otherwise you will need to add a few permissions to the security rules. This is because this solution uses reflection to access the private fields of Dozer classes.

You need to extend 2 classes: DozerBeanMapper and MappingProcessor . You will also need to list the direction and interface in order to get the direction from the above classes.

Listing:

 public enum Direction { TO, FROM; } 

Interface:

 public interface DirectionAware { Direction getDirection(); } 

Class extending 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; } } 

Class 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; } } 

Now use.

1) Each time you want to map the same primitive type (e.g. String-String), use a DozerConverter with this type for both arguments as a custom converter in your dispenser mapping file. The implementation of such a converter should expand: DozerConverter<String,String> and implement the MapperAware interface. This is important if you have MapperAware , because you have a mapper that you can direct to DirectionAware and then get directions.

For instance:

 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) You need to create 2 global Maper Dozer objects, one for each display direction. They must be configured with the same mapping files, but with a different direction argument. For instance:

 DirectionAwareDozerBeanMapper mapperFrom = DirectionAwareDozerBeanMapper(mappingFiles, Direction.FROM); DirectionAwareDozerBeanMapper mapperTo = DirectionAwareDozerBeanMapper(mappingFiles, Direction.TO); 

Of course, you will need to use the proper mapper (from / to) to provide information to the custom mappers which direction you are in.

0
source

I got into the same question after a couple of years, and somehow the DozerConverter API, which is the new API, still does not work as expected, as bidirectional!

So, instead of going into all these complex solutions offered here, I also created 2 one-way comparisons to overcome this problem (c). And then my transformations began to work. I am using the DozerConverter api as shown below:

public class MapToStringConverter extends DozerConverter

0
source

Source: https://habr.com/ru/post/1340314/


All Articles