Mapping deep properties with intermediate collections in dozer - java

Suppose I have the following classes
public class Baz {
private List<Foo> foos = new ArrayList<Foo>();
}
public class Foo {
private String string;
}
public class Target {
private List<String> fooStrings = new ArrayList<String>();
}
Is there any mapping I can use to, given a Baz, map it to the target class and get a list of the strings contained within the foo's in Baz? The following mapping does not work
<mapping>
<class-a>Baz</class-a>
<class-b>Target</class-b>
<field>
<a>foos.string</a>
<b>fooStrings</b>
</field>
</mapping>
Because string is not a property of foos (which is of type List). I would have thought Dozer would be clever enough to, if it encountered a collection in a deep mapping, and the target was also a collection, to be able to break the deep property name into two and iterate across the collection to get the child part of the deep mapping from the collection members. Apparently not. Is there a solution short of making a feature request of Dozer?

You could always write your own CustomConverter.
It makes sense why Dozer isn't able to handle this as you expect since at runtime it has no type information about the List foos and can't guarantee that every Object in the list is actually a Foo.

I think, you can write such a mapping
<mapping>
<class-a>Baz</class-a>
<class-b>Target</class-b>
<field>
<a>foos</a>
<b>fooStrings</b>
</field>
</mapping>
<custom-converters>
<converter type="CustomFooConverter">
<class-a>
Foo
</class-a>
<class-b>
String
</class-b>
</converter>
</custom-converters>
And implement CustomFooConverter to get string field of foo and return it as a String.
I think you can post a feature request to support mapping to primitives as
<mapping>
<class-a>Foo</class-a>
<class-b>String</class-b>
<field>
<a>string</a>
</field>
</mapping>
into Dozer GitHub

I think you can do it without custom converter.
Override the toString() method of Foo class like below:
#Override
public String toString(){
return this.getString(); //assuming string property has a getter method. if not,write this.string
And now the follwing mapping:
<mapping>
<class-a>fully qualified name of Baz(with package name)</class-a>
<class-b>same for Target</class-b>
<field>
<a>foos</a>
<b>fooStrings</b>
<a-hint>foo</a-hint>
<b-hint>java.lang.String</b-hint>
</field>
</mapping>

Related

Dozer mapping from parent field to nested/child field

I am struggling for dozer mapping for nested object. I want to map object field to field of this object child. for example I have these classes.
class Parent {
private Child child;
private Long childId;
// setter - getter
}
class Child {
private Long id;
// setter - getter
}
and my mapping is:
</mappings>
<configuration>
<map-null>false</map-null>
</configuration>
<mapping>
<class-a>com.indraep.Parent</class-a>
<class-b>com.indraep.Parent</class-b>
<field>
<a>childId</a>
<b>child.id</b>
</field>
</mapping>
</mappings>
By this setup, I can't map Parent.childId to Parent.child.id.
However It works if I try the opposite map from Parent.child.id to Parent.childId by using this mapping:
<field>
<a>childId</a>
<b>child.id</b>
</field>
Any idea how to solve this problem? or it's not possible to do it with dozer?
I found a solution by adding this field exclude config:
<field-exclude>
<a>child</a>
<b>child</b>
</field-exclude>
from the log, it seems dozer have mapped Parent.childId -> Parent.child.id, but in the next step it gets override by Parent.child -> Parent.child so the Parent.child becomes null.
Another problem is if Child class has some other fields and I need to mapped it as well (except for child.id which is mapped from Parent.childId), how to solve this?

Dozer - Mapping Collections

I have the a scenario that is similar to the following two classes:
public class Person {
private String name;
private Set<Person> familyMembers;
//constructors & getters and setters
}
The Person class is my source class. I'm trying to use Dover to map this class to the following target classes:
public class PersonPrime {
private String personName;
private FamilyMembers familyMembers;
//constructors & getters and setters
}
public class FamilyMembers {
private List<PersonPrime> familyMembers;
//constructors & getters and setters
}
The target classes in my actual scenario are generated by JAXB (using XSDs which I have created). The XSDs were prescribed and I can't really change them, therefore the target classes cannot be changed. I currently am able to map the primitives in my mappings XML file but I cannot maps the collection.
Any idea how I can use Dozer to map an object of Person to an object of type PersonPrime?
By default JaxB does not generate setters for the collections within the "FamilyMembers" type. This will result in a null pointer exeception deep within the guts of Dozer (org.dozer.util.ReflectionUtils.java:323 in Dozer 5.4.0) when Dozer tries to call the non-existent setter. To avoid this, you need to set is-accessible true on the collection field, which will cause it to set the familyMembers.familyMembers field directly. Thus, the following modified mapping who should work:
<mapping>
<class-a>Person</class-a>
<class-b>PersonPrime</class-b>
<field>
<a>name</a>
<b>personName</b>
</field>
<field>
<a>familyMembers</a>
<b is-accessible="true">familyMembers.familyMembers</b>
</field>
</mapping>
The following mapping works.
<mapping>
<class-a>Person</class-a>
<class-b>PersonPrime</class-b>
<field>
<a>name</a>
<b>personName</b>
</field>
<field>
<a>familyMembers</a>
<b>familyMembers.familyMembers</b>
</field>
</mapping>

Dozer custom converter - passing the whole object as field 'A'

I'd like to map a CustomConverter in dozer but I'd like to pass the whole current object as the source. All of the examples in the dozer CustomConverter documentation pass a field of the input object as the source and not the whole object.
I'd like to do something like this:
<mapping>
<class-a>foo.bar.InputObject</class-a>
<class-b>foo.bar.OutputObject</class-b>
<field custom-converter="foo.bar.MyConverter">
<a>this</a> <!-- how do I access the whole value and not just a field? -->
<b>custom</b>
</field>
<field>
<a>anotherField</a>
<b>anotherField</b>
</field>
</mapping>
And
public class MyConverter extends DozerConverter<InputObject, String> {
...
public String convertTo(InputObject input, String custom) {
// do some transformation
}
}
CustomConverter docs here:
http://dozer.sourceforge.net/documentation/customconverter.html
Try implementing the CustomConverter instead of DozerConverter and try passing it as:
<field custom-converter="my.custom.converter">
<a>this</a>
<b>myfield</b>
</field>
If you use the field mapping you want to identify the attribute by using "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. If for example you do not have a setter for a list value (like I had for whatever reason...) you are now able to manipulate the source object the way you need to.

Dozer deep mapping Set<ComplexObject> to Set<String>

Disclaimer: the same question has already been asked here Mapping deep properties with intermediate collections in dozer, but it has no accepted answer (and no proper answer for my case).
So the question. I have a realm composed by a ComplexObject like the following
public class ComplexObject {
private Set<AnotherComplexObject> inner;
... //other fields, setters and getters
}
public Class AnotherComplexObject {
private String property;
... //other fields, setters and getters
}
Now, I am mapping ComplexObject to Target, where Target has a Set<String> property.
public class Target {
private Set<String> targetString;
... //other fields, setters and getters
}
I want to map each ComplexObject inner.property onto one Target targetString. Something that semantically looks like (this does not work of course, property is not a member of Set and Dozer generates a MappingException):
<mapping>
<class-a>ComplexObject</class-a>
<class-b>Target</class-b>
<field>
<a>inner.property</a>
<b>targetString</b>
</field>
</mapping>
I can accomplish my goal if I modify the toString method of AnotherComplexObject to
public class AnotherComplexObject {
public String toString(){
return property;
}
}
Then, Dozer will detect the source Set is of "type" AnotherComplexObject while the target Set is of String and will use the method toString during the conversion. Unfortunately, this is not quite a solution since I will need a method in my POJO just to let Dozer doing the conversion.
What does work is to write a custom converter which overrides the convert method to check if source is a Set and then supposes the objects in the set are AnotherComplexObject and doing the conversion from this point on but somehow I feel this is not best nor the more elegant solution.
Any other idea about how to solve this problem?
Maybe my answer can be useful for you:
I think, you can write such a mapping
<mapping>
<class-a>Baz</class-a>
<class-b>Target</class-b>
<field>
<a>foos</a>
<b>fooStrings</b>
</field>
</mapping>
<custom-converters>
<converter type="CustomFooConverter">
<class-a>
Foo
</class-a>
<class-b>
String
</class-b>
</converter>
</custom-converters>
And implement CustomFooConverter to get string field of foo and return it as a String.
I think you can post a feature request to support mapping to primitives as
<mapping>
<class-a>Foo</class-a>
<class-b>String</class-b>
<field>
<a>string</a>
</field>
</mapping>
into Dozer GitHub

Dozer mapping non-Generic Collections to properties

I have some class structure as follows. These classes are hibernate classes so I cant change them.
//assume all getters & setters are present
public class Order{
private Customer customer;
}
public class Customer{
// non generics set
private Set nameParts;
}
public class NamePart{
private String id;
private String name;
}
// target class
public class OrderShippingDetail{
private String firstName;
}
mappying file
<mapping>
<class-a>Order</class-a>
<class-b>OrderShippingDetail</class-b>
<field>
<a>customer.nameParts[0].name</a>
<b>firstName</b>
</field>
</mapping>
But this mapping of customer.nameParts[0].name dosent work as the dozer dosent know the object in the set. is there any work around.
If this can only be done by custom converter, a sample code template hint is appreciated.
go one level deeper. like this
<mapping>
<class-a>Order</class-a>
<class-b>OrderShippingDetail</class-b>
<field>
<a>customer.nameParts[0]</a>
<b>this</b>
</field>
</mapping>
<mapping>
<class-a>{class of object # nameparts[0]}</class>
<class-b>OrderShippingDetail</class-b>
<field><a>name</a><b>firstname</b></field>
</mapping>
this works as a work-around. I've used this trick to make it work at some places.
I was going through the documentation and found that for non generic collections during deep mapping one can specify the objects using
<field>
<a>customer.nameParts[0].name</a>
<b>firstName</b>
<a-deep-index-hint>com.example.Customer, com.example.NamePart</a-deep-index-hint>
</field>

Categories

Resources