javamappingdozer

How to map HashMap with Array List of Objects (list is the value in the hash map) into another HashMap using DozerBeanMapper?


I have two classes and want to map the properties from Female object to Male object using org.dozer.Mapper(http://dozer.sourceforge.net/).

The first class is:

public class Male {
    private String name;
    private String surname;

    private Map<String, List<Contact>> contacts;
....

and the second class is :

public class Female {
    private String name;
    private String surname;
    private String mobile;
    private String dateOfBirth;

    private Map<String, List<Contact>> contacts;
...

and the third class is :

public class Contact {
    private String street;
    private String postcode;
    private String email;
...

The Map that i am using like object property is LinkedHashMap and the List which is a value in the Map is ArrayList. When I try to map them using the dozer, the array list which is the value in the hash map is not a list with objects and looks like in the picture:

        Map<String, List<Contact>> contact = new LinkedHashMap<>();
        List<Contact> listOfContacts = new ArrayList<>();
        Contact contactObj = new Contact();
        contactObj.setEmail("lala@gmail.com");
        contactObj.setPostcode("1233355");
        contactObj.setStreet("street");

        listOfContacts.add(contactObj);

        contact.put("2131323213", listOfContacts);
        femaleObj.setContact(contact);

        Mapper objectMapper = new DozerBeanMapper();
        Male maleObj = objectMapper.map(femaleObj, Male.class);

enter image description here

How can I get the list of objects in the List in the Male object?


Solution

  • At first, I've tried your code as-is and I got the same behavior.

    Then, I've explicit set the mapping configuration with b-hint (see documentation about this) as follow and I got what you need.

    First case - Java Configuration (create a class that extends BeanMappingBuilder):

    public class CustomMapper extends BeanMappingBuilder {
        @Override
        protected void configure() {
            mapping(Female.class, Male.class).fields("contacts", "contacts", FieldsMappingOptions.hintB(Contact.class));
        }
    }
    

    Second case - XML Configuration:

    <?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>
        <wildcard>true</wildcard>
      </configuration>
    
      <mapping>
        <class-a>blog.valerioemanuele.dozer.Female</class-a>
        <class-b>blog.valerioemanuele.dozer.Male</class-b>
    
          <field>
            <a>contacts</a>
            <b>contacts</b>
            <b-hint>blog.valerioemanuele.dozer.Contact</b-hint> 
          </field>
      </mapping> 
    
    
    </mappings>
    

    Here the unit tests I've executed:

    import org.dozer.DozerBeanMapper;
    import org.junit.Assert;
    import org.junit.jupiter.api.BeforeAll;
    import org.junit.jupiter.api.Test;
    
    class TestFemaleToMaleConversion {
    
        private static Female femaleObj;
    
        @BeforeAll
        private static void initData() {
            Map<String, List<Contact>> contact = new LinkedHashMap<>();
            List<Contact> listOfContacts = new ArrayList<>();
            Contact contactObj = new Contact();
            contactObj.setEmail("lala@gmail.com");
            contactObj.setPostcode("1233355");
            contactObj.setStreet("street");
    
            listOfContacts.add(contactObj);
    
            contact.put("2131323213", listOfContacts);
            femaleObj = new Female();
            femaleObj.setName("Elisabeth");
            femaleObj.setSurname("Chesny");
            femaleObj.setContacts(contact);
        }
    
        @Test
        void testWithXmlMapping() {
            DozerBeanMapper objectMapper = new DozerBeanMapper();
            objectMapper.setMappingFiles(Arrays.asList("dozer-mapping.xml"));
            Male maleObj = objectMapper.map(femaleObj, Male.class);
    
            Assert.assertEquals("lala@gmail.com", maleObj.getContacts().get("2131323213").get(0).getEmail());
        }
    
        @Test
        void testWithJavaMapping() {
            DozerBeanMapper objectMapper = new DozerBeanMapper();
            objectMapper.addMapping(new CustomMapper());
            Male maleObj = objectMapper.map(femaleObj, Male.class);
    
            Assert.assertEquals("street", maleObj.getContacts().get("2131323213").get(0).getStreet());
        }
    }
    

    Here the result:


    enter image description here

    You can get the complete code from my GitHub repository. The example was developed with Java8, Maven and Junit5.

    EDIT: I've added Java mapping configuration case. Taking inspiration from another post