Dozer Mapping HashMap<Key,Value> to List<Value>

Idcmp picture Idcmp · Dec 3, 2010 · Viewed 10.2k times · Source

I have a source object which has:

public class Source {
    public Map<String,DTO>getDTOs();
}

and a destination object:

public class Destination {
    public List<DTO> getDTOs();
    public void setDTOs(List<DTO> dtos);
}

I'm trying to use Dozer to do this mapping for me, but I'm sort of stumped. I've triaged the unit tests and only documents, but my challenge is that I'm not exactly sure what I'm looking for.

Answer

Jack Handy picture Jack Handy · Dec 20, 2010

In general, Dozer enjoys mapping like to like, especially as far as data structures go. This makes your problem a tricky one.

No doubt you have read up on mapping java.util.Map to java.util.Map. That does work great if you have Maps on both ends. Unfortunately, all the kings 'map-set-method's and all the kings men are not likely going to help you with doing a java.util.Map to java.util.List conversion. Dozer wants to Map.get(key) from the source and Map.put(key,value) into the destination. Since List doesn't play the put game, you're jammed (I wasn't able to successfully fake it out with an 'add()' ... maybe there is a way?).

At the bottom of http://dozer.sourceforge.net/documentation/customconverter.html there is a section on "Data Structure Conversions", which seems to resemble your problem. When the answer is "write a custom mapping", I'm probably not being a great help, but I got your code to work with the following setup.

Have you had any luck with doing this all in dozer xml?

 <mapping>
    <class-a>Source</class-a>
    <class-b>Destination</class-b>
    <field custom-converter="HashMapToListConverter">
      <a>dtos</a> <!-- This is a Map<String,DTO> -->
      <b>dtos</b> <!-- This is a List<DTOPrime> -->
      <a-hint>java.util.LinkedHashMap</a-hint>
      <b-hint>java.util.ArrayList</b-hint>
    </field>
  </mapping>



import org.dozer.*;
import java.util.*;

public class HashMapToListConverter extends DozerConverter<Map, List> implements MapperAware {

  private Mapper mapper;

  public HashMapToListConverter() {
    super(Map.class, List.class);
  }

  public List convertTo(Map source, List destination) {
    List<DTOPrime> convertedList = new ArrayList<DTOPrime>();
    for (Object object : source.values()) {
      DTO item = (DTO)object;
      DTOPrime mappedItem = mapper.map(item, DTOPrime.class);
      convertedList.add(mappedItem);
    }
    return convertedList;
  }

  public Map convertFrom(List source, Map destination) {
    Map<String, DTO> originalToMapped = new LinkedHashMap<String, DTO>();
    for (Object object : source) {
      DTOPrime item = (DTOPrime)object;
      DTO mappedItem = mapper.map(item, DTO.class);
      originalToMapped.put(mappedItem.getData(), mappedItem); // FIXME: Since the mapping is lossy, you can decide what the keys of your map are for the reverse mapping...
    }
    return originalToMapped;
  }

  public void setMapper(Mapper mapper) {
    this.mapper = mapper;
  }

}