Hi,
I think I have found a bug with default behaviour for mapping null values and empty strings in DOZER.
From Dozer faq http://dozer.sourceforge.net/documentation/faq.html#bypass-null
There is written that: "we can bypass mapping of null values by specifing map-null="false". Ithis is specified,
the dest field mapping is bypassed (...)"
From this I can asume that default behaviour nullifies destValue when srcValue equals null, but it does not, at
least when dozer ist configured only from Java code.
In the following example "myClassMapping1" does not set null in destValue. Even though mapping null behaviour is
set twice: TypeMappingOptions.mapNull() and redundant TypeMappingOptions.mapNull(true).
After some code analyses it seems to me that .mapNull(true) setting does not work on "mapping" level.
In may test class:
private final DozerBeanMapper MAPPER = new DozerBeanMapper();
final BeanMappingBuilder mapping1 = new BeanMappingBuilder() {
@Override
protected void configure() {
mapping(MyClassDTO.class, MyClass.class, TypeMappingOptions.mapId("myClassMapping1"),
TypeMappingOptions.mapNull(), TypeMappingOptions.mapNull(true),
TypeMappingOptions.mapEmptyString(), TypeMappingOptions.mapEmptyString(true))
}
}
MAPPER.addMapping(mapping1 );
I found that it works well when the .mapNull(true) setting is set on "class" level. Next example:
"myclassMapping2" works well.
final BeanMappingBuilder mapping2 = new BeanMappingBuilder() {
@Override
protected void configure() {
mapping(
new TypeDefinition(MyClassDTO.class).mapNull().mapEmptyString()
, new TypeDefinition(MyClass.class).mapNull().mapEmptyString()
, TypeMappingOptions.mapId("myClassMapping2"))
}
}
MAPPER.addMapping(mapping );
From code it looks like DOZER should behave properly when only .mappNull() is set on "mapping" level.
package org.dozer.classmap;
private boolean mapNull = DozerConstants.DEFAULT_MAP_NULL_POLICY; //true
ClassMap{
public boolean isDestMapNull() {
return destClass.getMapNull() != null ? destClass.getMapNull().booleanValue() : mapNull;
}
I think that the problem are not initilized properties in TypeDefinition class, which it's method build() uses to
configure DozerClass object mapNull property.
package org.dozer.loader.api;
TypeDefinition{
private boolean mapNull;
private boolean mapEmptyString;
public void build(DozerBuilder.ClassDefinitionBuilder typeBuilder) {
typeBuilder.mapEmptyString(this.mapEmptyString);
typeBuilder.mapNull(this.mapNull);// --> dozerClass.setMapNull(value);
}
}
I think changing type mapNull and mapEmptyString to referential Boolean or initializing theses properties with
"true" can resolve problem.
View and moderate all "bugs Discussion" comments posted by this user
Mark all as spam, and block user from posting to "Bugs"
Hi,
I'm also encountering this bug: map-null at the mapping level just doesn't work via the API (but does via XML).
Here's a simple test to demonstrate (all tests pass, except 'testApiMapNullAtMappingLevel'):
Test class:
-------------------------------------------------------------------------------
package example;
import static org.junit.Assert.assertNull;
import java.util.Arrays;
import org.dozer.DozerBeanMapper;
import org.dozer.loader.api.BeanMappingBuilder;
import org.dozer.loader.api.TypeMappingOptions;
import org.junit.Before;
import org.junit.Test;
public class TestMapNull {
private ClassA classA;
private ClassB classB;
@Before
public void setUp() {
classA = new ClassA();
classA.setFieldA(null);
classB = new ClassB();
classB.setFieldB("not null!");
}
@Test
public void testXmlMapNullAtMappingLevel() {
DozerBeanMapper mapper = new DozerBeanMapper(Arrays.asList("mapNullMapping.xml"));
mapper.map(classA, classB, "mapNullAtMappingLevel");
assertNull(classB.getFieldB());
}
@Test
public void testXmlMapNullAtClassLevel() {
DozerBeanMapper mapper = new DozerBeanMapper(Arrays.asList("mapNullMapping.xml"));
mapper.map(classA, classB, "mapNullAtClassLevel");
assertNull(classB.getFieldB());
}
@Test
public void testApiMapNullAtMappingLevel() {
DozerBeanMapper mapper = new DozerBeanMapper();
mapper.addMapping(new BeanMappingBuilder() {
@Override
protected void configure() {
mapping(ClassA.class, ClassB.class,
TypeMappingOptions.mapNull(true), // map-null at mapping level
TypeMappingOptions.mapId("mapNullAtMappingLevel"))
.fields("fieldA", "fieldB");
}
});
mapper.map(classA, classB, "mapNullAtMappingLevel");
assertNull(classB.getFieldB()); // fails!!!
}
@Test
public void testApiMapNullAtClassLevel() {
DozerBeanMapper mapper = new DozerBeanMapper();
mapper.addMapping(new BeanMappingBuilder() {
@Override
protected void configure() {
mapping(ClassA.class, type(ClassB.class).mapNull(true), // map-null at class level
TypeMappingOptions.mapId("mapNullAtClassLevel"))
.fields("fieldA", "fieldB");
}
});
mapper.map(classA, classB, "mapNullAtClassLevel");
assertNull(classB.getFieldB());
}
}
-------------------------------------------------------------------------------
XML config (mapNullMapping.xml):
-------------------------------------------------------------------------------
<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">
<mapping map-null="true" map-id="mapNullAtMappingLevel">
<class-a>example.ClassA</class-a>
<class-b>example.ClassB</class-b>
<field>
<a>fieldA</a>
<b>fieldB</b>
</field>
</mapping>
<mapping map-id="mapNullAtClassLevel">
<class-a>example.ClassA</class-a>
<class-b map-null="true">example.ClassB</class-b>
<field>
<a>fieldA</a>
<b>fieldB</b>
</field>
</mapping>
</mappings>
-------------------------------------------------------------------------------
Regards,
James