Search code examples
javaserializationmappingdozer

How can I map List<MyObject> to List<HashMap<String,Object>> with Dozer?


Let's say I have an object Foo which holds a list of references to object Bar:

public class Foo{
    String fooStr;
    List<Bar> barList;

    //get/set barList/someStr go here
}

public class Bar {
    String barStr;
}

Using Dozer, assuming Bar to java.util.HashMap is a trivial mapping, how do I map instances of Foo to instances of java.util.HashMap such that the referenced instances of Bar are mapped to java.util.HashMap as well? That is, I want the result of the mapping to be a HashMap with key "barList" which holds an instance of ArrayList>. Each HashMap in this list should be a mapping of Bar to HashMap.

For instance, if Foo held a single reference to Bar rather than a list, I'd do:

<mapping>
    <class-a>Foo</class-a>
    <class-b>java.util.Map</class-b>

    <field>
        <a>bar</a>
        <b key="bar">this</b>
        <a-hint>Bar</a-hint>
        <b-hint>java.util.Map</b-hint>
    </field>
</mapping>

And this would produce a hashmap that'd look like this (using JSON objects to represent HashMaps):

{
    "fooStr" : "value of fooStr",
    {
       "barStr" : "value of barStr"
    }
}

But I want to know how I can express the conversion to HashMap with a list of references to Bar such that I get this:

{
    "fooStr" : "value of fooStr",
    "barList" : [{ "barStr" : "bar1" }, { "barStr" : "bar2" }, ...]
}

Answers which do not use a custom mapper are preferred, but I understand if this is the only way of achieving this behavior.


Solution

  • You should be able to do this in a custom converter:

    public class Foo {
        String fooStr;
        List<Bar> barList;
        ...
    }
    
    public class Bar {
        String barStr;
    }
    
    public class Target {
        String fooStr;
        Map<String, Bar> barMap;   
    }
    
    
    public class TestCustomConverter implements CustomConverter {
    
      public Object convert(Object destination, Object source, Class destClass, Class sourceClass) {
        if (source == null) {
          return null;
        }
        if (source instanceof Foo) {
          Map<Bar> dest = null;
          // check to see if the object already exists
          if (destination == null) {
            dest = new Target();
          } else {
            dest = (Target) destination;
          }
          ((Target) dest).setFooStr(source.getFooStr());
          for(Bar : source.getBarList()) {
              ((Target) dest).getBarMap().put(bar.getBarStr(), bar);
          }
          return dest;
        } else if (source instanceof Target) {
          Foo dest = null;
          // check to see if the object already exists
          if (destination == null) {
            dest = new Foo ();
          } else {
            dest = (Foo) destination;
          }
          dest.getFoos().addAll(((Target)source).getBarMap().values());
          dest.setFooStr(((Target)source).getFooStr()):
          return dest;
        } else {
          throw new MappingException("Converter TestCustomConverter used incorrectly. Arguments passed in were:"
              + destination + " and " + source);
        }
      }
    

    Warning: Code may contain bugs, but should give you the idea.