Hi,
I believe the problem is not in dozer, but in the hidden auto-unboxing in your getter:
public int getId()
{
return (Integer)get("id");
}
(Integer)get("id") is implicitely cast into an int because the return type of your method is "int".
This will work in most cases... EXCEPT when the result is null, in which case you get a NullPointerException because an int may never be null.
This results in hidden NullPointerExceptions... More info here: http://www.theserverside.com/blogs/thread.tss?thread_id=41731
To resolve this, you have multiple choices:
If Class1 and Class2 may in fact contain a null id, you want to modify your getters/setters to get/set Integers instead of primitive ints.
If both Class1 and Class2 should never contain a null id, and you consider this to be a class invariant, you may keep the primitive int type in the getter/setter and either:
- Make sure get("id") will never be null, by initializing it to some specific value (such as 0) in the constructor), and making sure that nothing can set it to null.
- Or decide that getId() will return a default value if null, and add a null check in the getter as you said.
If Class1 may have a null id, but Class2 may not, you should have Class1's getters and setters use an Integer type instead of an int primitive, and you should create a dozer CustomConverter that returns a default value when the source field is null.
Regards
[EDIT]
Here is the test code that shows that Dozer does ignore mapping nulls when asked to:
src/com/test/dozer/Class1.java :
package com.test.dozer;
import com.extjs.gxt.ui.client.data.BaseModelData;
public class Class1 extends BaseModelData {
// Notice the return type here: "Integer" and *not* int
// Returning int throws a NullPointerException when get("id") is null!
public Integer getId() {
return (Integer) get("id");
}
public void setId(Integer id) {
set("id", id);
}
}
src/com/test/dozer/Class2.java :
package com.test.dozer;
public class Class2 {
private int id;
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
}
src/dozerMappingFile.xml :
<?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>
<stop-on-errors>true</stop-on-errors>
<date-format>MM/dd/yyyy HH:mm</date-format><!-- default dateformat will apply to all class maps unless the class mapping explicitly overrides it -->
<wildcard>true</wildcard><!-- default wildcard policy that will apply to all class maps unless the class mapping explicitly overrides it -->
</configuration>
<mapping map-null="false">
<class-a>com.test.dozer.Class1</class-a>
<class-b>com.test.dozer.Class2</class-b>
</mapping>
</mappings>
src/com/test/dozer/DozerTest.java :
package com.test.dozer;
import java.util.Arrays;
import junit.framework.Assert;
import org.dozer.DozerBeanMapper;
import org.junit.Before;
import org.junit.Test;
public class DozerTest {
private DozerBeanMapper mapper;
@Before
public void setUp() {
mapper = new DozerBeanMapper(Arrays.asList("dozerMappingFile.xml"));
}
/**
* Verifies that class1's id is mapped into class2's id when not null.
*/
@Test
public void testMappingWhenIdNotNull() {
Class1 class1 = new Class1();
class1.setId(1);
Class2 class2 = new Class2();
class2.setId(2);
mapper.map(class1, class2);
Assert.assertEquals(1, class2.getId());
}
/**
* Verifies that class2's id is not set to null when class1's id is null.
*/
@Test
public void testMappingWhenIdIsNull() {
Class1 class1 = new Class1();
Class2 class2 = new Class2();
class2.setId(2);
mapper.map(class1, class2);
Assert.assertEquals(2, class2.getId());
}
}