Search code examples
java-8mappingdozer

Dozer Deep Property Mapping


public class Something{
   private string id;
   private SomethingElse somethingElse;
   private OtherProperties...
}
 public class SomethingElse{
   private string id;
   private OtherProperties...
}
public class SomethingDto{
   private string id;
   private string somethingElseId;
   private OtherProperties...
}

When mapping from something to SomethingDto I have to do

<mapping>
    <class-a>Something</class-a>
    <class-b>SomethingDto</class-b>
    <field>
        <a>somethingElse.id</a>
        <b>somethingElse</b>
    </field>
</mapping>

I'm not sure how to do the opposite what I want is "new SomethingElse" and then set the id like this

public class Something{
   private string id;
   private SomethingElse somethingElse;
   private OtherProperties...
   public void setSomethingElseById(String somethingElseId){
       somethingElse = new SomethingElse;
       somethingElse.setId(somethingElseId);
   }
}
<mapping>
    <class-a>SomethingDto</class-a>
    <class-b>Something</class-b>
    <field>
        <a>somethingElse</a>
        <b set-method='setSomethingElseById(SomethingElse)' >somethingElse</b>
    </field>
</mapping>

This really looks like a bad solution so I tried the custom converter

public class SomethingDtoToSomethingConverter extends DozerConverter<String, SomethingElse> {
  public SomethingDtoToSomethingConverter () {
    super(String.class, SomethingElse.class);
  }
  @Override
  public SomethingElse convertTo(String source, SomethingElse destination) {
    destination = new SomethingElse();
    destination.setId(source);
    return destination;
  }
  @Override
  public String convertFrom(SomethingElse source, String destination) {
    destination = source.getId();
    return destination ;
  }
}

This looks like a ridiculous amount of code for something really simple How can I achieve a cleaner solution?


Solution

  • What version of Dozer are you using? This should just work out of the box using the first mapping you defined as Dozer mappings are bi-directional by default.

    I've created an example based on your code with a unit test which passes:

    Something.java

    public class Something {
        private String id;
        private SomethingElse somethingElse;
        ...
    }
    

    SomethingElse.java

    public class SomethingElse {
        private String id;
        ...
    }
    

    SomethingDto.java

    public class SomethingDto {
        private String id;
        private String somethingElseId;
        ...
    }
    

    dozer.xml

    <mapping>
        <class-a>Something</class-a>
        <class-b>SomethingDto</class-b>
        <field>
            <a>somethingElse.id</a>
            <b>somethingElseId</b>
        </field>
    </mapping>
    

    Unit Test

    public class DozerMappingTest {
    
        private DozerBeanMapper beanMapper;
    
        @Test
        public void sourceToDestination() {
            List<String> mappingFiles = new ArrayList<String>();
            mappingFiles.add("dozer.xml");
            this.beanMapper = new DozerBeanMapper(mappingFiles);
    
            Something source = new Something();
            source.setId("A");
            SomethingElse somethingElse = new SomethingElse();
            somethingElse.setId("B");
            source.setSomethingElse(somethingElse);
    
            SomethingDto dest = beanMapper.map(source, SomethingDto.class);
            assertEquals("A", dest.getId());
            assertEquals("B", dest.getSomethingElseId());
        }
    
        @Test
        public void destinationToSource() {
            List<String> mappingFiles = new ArrayList<String>();
            mappingFiles.add("dozer.xml");
            this.beanMapper = new DozerBeanMapper(mappingFiles);
    
            SomethingDto source = new SomethingDto();
            source.setId("A");
            source.setSomethingElseId("B");
    
            Something dest = beanMapper.map(source, Something.class);
            assertEquals("A", dest.getId());
            assertEquals("B", dest.getSomethingElse().getId());
        }
    }