4

I have a class A which has a nested set of class B:

public class A {
    private Set<B> children;
}

public class B {
    private int value;
}

I also have a class C which has a nested set of class D:

public class C {
    private Set<D> children;
}

public class D {
    private int value;
}

Now given a List of A, how do I convert it to a List of C? Ideally I should not have to supply any mapping hints since I am using generics. For example:

List<A> src = new ArrayList<A>();
// ----- Add some A's to src -----
List<C> dst = mapper.map(src, List<C>.class);

Obviously, the syntax of last line is not correct. What should it be? Also how do I tell Dozer what type of a List or a Set to create?

Thanks.

Naresh

Daniel Kaplan
  • 62,768
  • 50
  • 234
  • 356
Naresh
  • 23,937
  • 33
  • 132
  • 204

2 Answers2

4

This is actually answered in their FAQ, but it's all the way down in the advanced section for some reason. I don't think this is an advanced topic, I think it's a common thing to want to do. You do it with a collection hint.

When mapping collections, how do I tell Dozer what type of data objects I want in the destination collection?

Hints are supported to handle this use case. Hints are not required if you are using JDK 1.5 Generics because the types can be auto detected by Dozer. But if you are not using generics, to convert a Collection/Array to a Collection/Array with different type objects you can specify a Hint to let Dozer know what type of objects you want created in the destination list. If a Hint is not specified for the destination field, then the destination Collection will be populated with objects that are the same type as the elements in the src Collection.

<field>
  <a>someList</a>
  <b>otherList</b> 
  <b-hint>org.dozer.vo.TheFirstSubClassPrime</b-hint> 
</field>

That answer shows you how to do it in xml. Here's how you can do it in java code with a Mapping:

import org.dozer.loader.api.BeanMappingBuilder;

import static org.dozer.loader.api.FieldsMappingOptions.hintB;

public class Mapping extends BeanMappingBuilder {
    @Override
    protected void configure() {
        mapping(Subject.class, JsonSubject.class)
                .fields("names", "names", hintB(JsonName.class));
    }
}

The hint tells dozer, "this list of A's should be converted to a list JsonName instances". Here's how you add this mapping to your mapper:

    mapper = new DozerBeanMapper();
    mapper.addMapping(new Mapping());
Community
  • 1
  • 1
Daniel Kaplan
  • 62,768
  • 50
  • 234
  • 356
  • Worked exactly as intended. I am using this in dropwizard to convert my domain POJOs to representations and have nested representations. You have be careful with your lazy + eager loading still, but dozer carries everything you need over and will use your nested representations with this hinting. – gspatel Apr 18 '14 at 02:57
0

You should simply expand this list convertion. Dozer convert JavaBeans and such objects, not collections. So, if you want to pass collections, you can create a wrapper like

public class EntityConverter {
    private Mapper mapper;

    public EntityConverter(Mapper mapper) {
        this.mapper = mapper;
    }

    public <F, T> List<T> convert(List<F> fromList, final Class<T> toClass) {
        return Lists.transform(fromList, new Function<F, T>() {
            @Override
            public T apply(F from) {
                return convert(from, toClass);
            }
        });
    }

    public <F, T> T convert(F from, final Class<T> toClass) {
        if (from == null) return null;
        return mapper.map(from, toClass);
    }
}

Note: This code use Guava.

Dmitry Spikhalskiy
  • 5,379
  • 1
  • 26
  • 40