Search code examples
javamappingconvertersdozermapper

Dozer Mapper does not map despite fields having same names and XML mappings specified


Supposing I have:

  1. ObjectWithList, ListWrapper and ObjectWithWrapper classes like these:
//com.github.komidawi.ObjectWithList
public class ObjectWithList {
    private List<String> list;
    // ...
}

//com.github.komidawi.ListWrapper 
public class ListWrapper {
    private List<String> wrappedList;
    // ...
}

//com.github.komidawi.ObjectWithWrapper
public class ObjectWithWrapper {
    private ListWrapper list;
    // ...
}
  1. MyCustomConverter class to wrap/unwrap these lists.

  2. mapperConfiguration.xml configuration file

<!-- ... -->
<configuration>
    <stop-on-errors>true</stop-on-errors>
    <wildcard>true</wildcard>

    <custom-converters>
        <converter type="com.github.komidawi.MyCustomConverter">
            <class-a>com.github.komidawi.ListWrapper</class-a>
            <class-b>java.util.List</class-b>
        </converter>
    </custom-converters>
</converter>

<mapping>
        <class-a>com.github.komidawi.ObjectWithList</class-a>
        <class-b>com.github.komidawi.ObjectWithWrapper</class-b>
</mapping>

And I want to map ObjectWithWrapper to ObjectWithList:

// ... creating objects
ObjectWithList objectWithList = mapper.map(objectWithWrapper, ObjectWithList.class);
objectWithList.getList(); // This is null

Unfortunately, after mapping, list field of objectWithList is null. I used debugger and it Dozer doesn't even enter MyCustomConverter in this case.

Surprisingly, mapping in different direction works fine:

ObjectWithWrapper objecthWithWrapper = mapper.map(objectWithList, ObjectWithWrapper.class);
objecthWithWrapper.getList(); // This is not null

Summarizing:

  1. Field name is the same both in ObjectWithList and ObjectWithWrapper: list
  2. I have specified custom converter for Java's List and ListWrapper in xml file
  3. I have specified mapping between ObjectWithList and ObjectWithWrapper in xml file
  4. In both cases Dozer says: "Successfully loaded custom xml mappings from URL"
  5. When mapping from ObjectWithList to ObjectWithWrapper it works fine

And the problem is:

After mapping, objectWithList has null instead of actual list. I spotted that it doesn't even enter MyCustomConverter


Solution

  • Collections are special and the type erasure makes them more challenging. If all you want is for the items in wrappedList to be in the list in the resulting ObjectWithList instance, this can be accomplished without the converter. Dozer will handle nested property mapping, so you can describe the mapping in such a way that instructs Dozer to map the lists to each other.

    new BeanMappingBuilder() {
        configure() {
            mapping(ObjectWithList.class, ObjectWithWrapper.class,
                .fields("list.wrappedList", "list")
        }
    }
    

    or in XML

    <mapping>
            <class-a>com.github.komidawi.ObjectWithList</class-a>
            <class-b>com.github.komidawi.ObjectWithWrapper</class-b>
            <field>
                <a>list.wrappedList</a>
                <b>list</b>
            </field>
    </mapping>