Search code examples
javamodelmapper

Use ModelMapper to flatten to list of ids


I am trying to use ModelMapper to map a collection of sub-objects to a list of id numbers.

public class Child {
    private int id;
    private String childName;
}

public class Parent {
    private Set<Child> children;
    private String parentName;
}

public class ParentDto {
    private int[] children; // Or use ArrayList<Integer>
    private String parentName;
}

How do I tell ModelMapper to flatten the set of Child objects to an array of id numbers?

My first attempt is this but does not seem correct:

    modelMapper.addMappings(new PropertyMap<Parent, ParentDto>() {
        @Override
        protected void configure() {
            using(ctx -> ctx.getSource().stream().map(Parent::getId).collect(Collectors.toList())
                .map().setChildren(source.getId()));
        };
    });


    Type listType = new TypeToken<ArrayList<ParentDto>>() {}.getType();
    ArrayList<ParentDto> parentDtos = new ArrayList<>();
    parentDtos = modelMapper.map(parents, listType);

The setChildren call seems like it needs to be map().add() but that does not work either.

Ideas are welcome.


Solution

  • One way of doing this is to create a Set<Child> to int[] converter and use it to map Parent.children to ParentDTO.children:

    ModelMapper mapper = new ModelMapper();
    
    Converter<Set<Child>, int[]> childSetToIntArrayConverter =
            ctx -> ctx.getSource()
                    .stream()
                    .mapToInt(Child::getId)
                    .toArray();
    
    mapper.createTypeMap(Parent.class, ParentDto.class)
            .addMappings(map -> map
                    .using(childSetToIntArrayConverter)
                    .map(
                            Parent::getChildren,
                            ParentDto::setChildren
                    )
            );
    

    Here is the complete demo (using lombok 1.18.10 and modelmapper 2.3.5):

    import lombok.AllArgsConstructor;
    import lombok.Data;
    import org.modelmapper.Converter;
    import org.modelmapper.ModelMapper;
    
    import java.util.Set;
    
    public class Main {
    
        public static void main(String[] args) {
    
            Parent parent = new Parent();
            parent.setParentName("Parent");
            parent.setChildren(Set.of(
                    new Child(1, "A"),
                    new Child(2, "B"),
                    new Child(3, "C")
            ));
    
            ModelMapper mapper = new ModelMapper();
    
            Converter<Set<Child>, int[]> childSetToIntArrayConverter =
                    ctx -> ctx.getSource()
                            .stream()
                            .mapToInt(Child::getId)
                            .toArray();
    
            mapper.createTypeMap(Parent.class, ParentDto.class)
                    .addMappings(map -> map
                            .using(childSetToIntArrayConverter)
                            .map(
                                    Parent::getChildren,
                                    ParentDto::setChildren
                            )
                    );
    
            ParentDto dto = mapper.map(parent, ParentDto.class);
    
            System.out.println(parent);
            System.out.println(dto);
        }
    
        @Data
        @AllArgsConstructor
        public static class Child {
            private int id;
            private String childName;
        }
    
        @Data
        public static class Parent {
            private Set<Child> children;
            private String parentName;
        }
    
        @Data
        public static class ParentDto {
            private int[] children;
            private String parentName;
        }
    }
    
    

    Output

    Main.Parent(children=[Main.Child(id=3, childName=C), Main.Child(id=2, childName=B), Main.Child(id=1, childName=A)], parentName=Parent)
    Main.ParentDto(children=[3, 2, 1], parentName=Parent)