I need help configuring my dozer mapping file.
Mainly I would like to know how to get User user obejct to convert to Long userId.
Hence map: user >> userId
But I have multiple objects such as comment >> commentId or address >> addressId
therefor I'd like to have something more elegant than just writing mapping for each of the fields. All of the object implement Loadable interface.
The bellow code is now functioning thanks to the getParameter() DozerConverter method, but if you know any better way than the converter that I wrote please let me know.
<?xml version="1.0" encoding="UTF-8"?>
<mappings xmlns="http://dozer.sourceforge.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://dozer.sourceforge.net http://dozer.sourceforge.net/schema/beanmapping.xsd">
<configuration>
<custom-converters>
<converter type="project.shared.domain.dto.dozer.LoadableIdConverter" >
<class-a>project.shared.domain.Loadable</class-a>
<class-b>java.lang.Long</class-b>
</converter>
</custom-converters>
</configuration>
<mapping>
<class-a>project.shared.domain.Suggestion</class-a>
<class-b>project.shared.domain.dto.DTOSuggestion</class-b>
<field custom-converter-param="User">
<a>user</a>
<b>userId</b>
</field>
</mapping>
</mappings>\
<bean id="loadableIdConverter" class="project.shared.domain.dto.dozer.LoadableIdConverter">
<property name="userService" ref="userService"/>
<property name="commentService" ref="commentService"/>
<property name="addressService" ref="addressService"/>
</bean>
<bean id="gwtMapper" class="org.dozer.DozerBeanMapper">
<property name="mappingFiles">
<list>
<value>classpath:/dozer.xml</value>
</list>
</property>
<property name="customConverters">
<list>
<ref bean="loadableIdConverter"/>
</list>
</property>
</bean>
public class Suggestion implements Serializable, Loadable {
private long id = -1;
private Date dateCreated;
private User user; //trying to use dozer to covert this bad boy to Long userId
//...
}
public class DTOSuggestion implements IsSerializable {
private long id = -1;
private Date dateCreated;
private Long userId; //trying to get this ID via the dozer converter
//...
}
public interface Loadable extends Serializable {
public long getId();
public void setId(long id);
}
public class LoadableIdConverter extends DozerConverter<Loadable, Long> {
private UserService userService; //configured in applicationcontext
private AddressService addressService; //configured in applicationcontext
private CommentService commentService; //configured in applicationcontext
public LoadableIdConverter() {
super(Loadable.class, Long.class);
}
public Long convertTo(Loadable object, Long id) {
return object.getId();
}
public Loadable convertFrom(Long id, Loadable object) {
if (id < 0) return null;
String loadable = getParameter();
if (loadable.equalsIgnoreCase("User"))
return userService.get(User.class, id);
if (loadable.equalsIgnoreCase("Address"))
return addressService.get(Address.class, id);
if (loadable.equalsIgnoreCase("Comment"))
return commentService.get(Comment.class, id);
return null;
}
}
There is one trick you could use to avoid converter parameters. If you fall back to older custom converter approach in Dozer, which is implementing CustomConverter interface, you will get two additional parameters: existingDestinationValue and destinationClass.
convert(Object existingDestinationFieldValue, Object sourceFieldValue, Class<?> destinationClass, Class<?> sourceClass)
By using these values you could introspect your destination field via reflection and know what is the expected concrete implementation of Loadable interface. This works only if you define the field types with concrete types of course. But you already have it in your example, so this should not be a problem. CustomConverter implementation will be more verbose as you need to determine the direction of the mapping manually, but it gives you full control of what is going on during the mapping process.