Search code examples
javamodelmapper

How to use a Converter and a PropertyMap in the same mapping?


I am trying to specify the mapping of the member list using a Converter but I would like to also use a PropertyMap to map the remaining fields (in the example below it is just the field 'a' that should be mapped to 'aa').

Is it possible to specify all the mappings in the Converter or just in a PropertyMap? If not, how can I use both in the same model mapper?

Thanks.

P.S. I followed this example http://bit.ly/10dqanw to make my Test class.

package org.me.modelmapper;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.modelmapper.Converter;
import org.modelmapper.ModelMapper;
import org.modelmapper.PropertyMap;
import org.modelmapper.TypeToken;
import org.modelmapper.config.Configuration;
import org.modelmapper.spi.MappingContext;
import static org.testng.Assert.*;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class ModelMapperTest {

    private ModelMapper modelMapper;

    public static class Foo {

        private String a;
        private List<Bar> b;

        public String getA() {
            return a;
        }

        public void setA(String a) {
            this.a = a;
        }

        public List<Bar> getB() {
            return b;
        }

        public void setB(List<Bar> b) {
            this.b = b;
        }

    }

    public static class Bar {

        private String c;

        public Bar(String c) {
            this.c = c;
        }

        public String getC() {
            return c;
        }

        public void setC(String c) {
            this.c = c;
        }

    }

    public static class FooDTO {

        private String aa;
        private List<BarDTO> bb;

        public String getAa() {
            return aa;
        }

        public void setAa(String aa) {
            this.aa = aa;
        }

        public List<BarDTO> getBb() {
            return bb;
        }

        public void setBb(List<BarDTO> bb) {
            this.bb = bb;
        }

    }

    public static class BarDTO {

        private String cc;              

        public String getCc() {
            return cc;
        }

        public void setCc(String cc) {
            this.cc = cc;
        }

    }

    public ModelMapperTest() {
    }

    @Test
    public void shouldMapFooToFooDTO() {
        Foo foo = new Foo();
        foo.setA("aaa");
        List<Bar> b = Arrays.asList(new Bar("ccc"), new Bar("ddd"));
        foo.setB(b);

        modelMapper.createTypeMap(Foo.class, FooDTO.class).setConverter(
                new Converter<Foo, FooDTO>() {

                    @Override
                    public FooDTO convert(MappingContext<Foo, FooDTO> context) {
                        List<BarDTO> barDTOs = new ArrayList<BarDTO>();

                        List<Bar> bars = context.getSource().getB();
                        TypeToken<List<BarDTO>> token = new TypeToken<List<BarDTO>>() {
                        };
                        MappingContext<List<Bar>, List<BarDTO>> c = context.create(bars, token.getType());
                        barDTOs.addAll(context.getMappingEngine().map(c));

                        FooDTO fooDTO = new FooDTO();
                        fooDTO.setBb(barDTOs);
                        return fooDTO;
                    }
                ;

    }                              
    );

        PropertyMap<Foo, FooDTO> map = new PropertyMap<Foo, FooDTO>() {

            @Override
            protected void configure() {
                map(source.getA(), destination.getAa());
            }

        };

        modelMapper.addMappings(map);

        FooDTO fooDTO = modelMapper.map(foo, FooDTO.class);

        assertEquals(fooDTO.getAa(), foo.getA());

        int i = 0;
        for(; i < fooDTO.getBb().size(); i++) {
            assertEquals(fooDTO.getBb().get(i), foo.getB().get(i));
        }
    }

    @BeforeMethod
    public void setUpMethod() throws Exception {
        modelMapper = new ModelMapper();
        modelMapper.getConfiguration()
                .setFieldMatchingEnabled(true)
                .setFieldAccessLevel(Configuration.AccessLevel.PRIVATE);               
    }

}

Solution

  • Yes it is possible. A Converter will always take precedence over any property mappings. You can certainly specify both, but the Converter is what will be used.