custom dozer mapping
I'm trying to use Dozer to convert an instance of
class Source {
private List<Foo> foos = new ArrayList<Foo>();
public List<Foo> getFoos() {
return foos;
}
public void setFoos(List<Foo> foos) {
this.foos = foos;
}
}
to an instance of:
class Target {
private List<Foo> foos = new ArrayList<Foo>();
public List<Foo> getFoos() {
return foos;
}
}
In Java code I would preform the converstion like this
Source s = new Source();
Target t = new Target();
t.getFoos().addAll(s.getFoos());
Dozer doesn't perform this conversion by default because Target
doesn't have a foos
property (开发者_开发知识库just a getter).
In reality, I have lots of properties like this that I need to map. One option is to tell Dozer to map the private fields directly, but this is not entirely satisfactory because:
- I will need to specify each field to be mapped in this way by name in the Dozer XML config
- accessing private fields is bad
Is there a better way?
There is no easy way to get around this other than the is-accessible
flag.
But you could define a custom converter that uses the getter to do:
t.getFoos().addAll(s.getFoos());
This would be very heavy handed and alot of work. You would need to define a custom converter (see http://dozer.sourceforge.net/documentation/customconverter.html) between Source
and Target
that used the getter instead of the setter:
public class TestCustomConverter implements CustomConverter {
public Object convert(Object destination, Object source, Class destClass, Class sourceClass) {
if (source == null) {
return null;
}
if (source instanceof Source) {
Target dest = null;
// check to see if the object already exists
if (destination == null) {
dest = new Target();
} else {
dest = (Target) destination;
}
dest.getFoos().addAll(((Source)source).getFoos());
return dest;
} else if (source instanceof Target) {
Source dest = null;
// check to see if the object already exists
if (destination == null) {
dest = new Source();
} else {
dest = (Source) destination;
}
dest.setFoos(((Target)source).getFoos());
return dest;
} else {
throw new MappingException("Converter TestCustomConverter used incorrectly. Arguments passed in were:"
+ destination + " and " + source);
}
}
I think, good luck
You could add a method to Target:
public void addFoo(Foo item) {
foos.add(item);
}
<mapping>
<class-a>Source</class-a>
<class-b>Target</class-b>
<field>
<a>foos</a>
<b set-method="addFoo" type="iterate">foos</b>
</field>
</mapping>
Maybe suggest a feature to allow use of EL in a setter or getter expression
If for example you do not have a setter for a list value (like I had for whatever reason...) you can use the field mapping in combination with "this", to identify the attribute you can use "key":
<field custom-converter="de.xyz.custom.MyConverter">
<a key="variablename">this</a>
<b>targetvariablename</b>
</field>
You can then proceed to implement the converter. You will be given the Object containing the field "variablename" as source. you are now able to manipulate the source object the way you need to (in this case use the getter, get the list, addAll() and you're good).
精彩评论