Using ModelMapper on different data types with same attribute name
Asked Answered
R

1

2

I have two classes say Animal & AnimalDto
I want to use ModelMapper to convert Entity to DTO and vice verca.
But the classes are supposed to have different data types for a few attributes having similar name.
How do I achieve this?

Animal.java

public class Animal {    
    int category;    
    String color;    
    int age;
}    
 

AnimalDto.java

public class AnimalDto {    
    String category;    
    int color;    
    int age;
}

currently I'm manually transforming as such:

class AnimalTransformer {
    private static Category[] categories = Category.values();    
    private static Color[] colors = Color.values();    

    animalEntityToDto(Animal animal) {
          AnimalDto animalDto = new AnimalDto();    
          animalDto.setAge(animal.getAge());
          animalDto.setCategory(categories[animal.getCategory()].toString());
          animalDto.setColor(Color.valueOf(animal.getColor()).ordinal());
    }

    animalDtoToEntity(AnimalDto animalDto) {
          Animal animal = new Animal();    
          animal.setAge(animalDto.getAge());
          animal.setCategory(Category.valueOf(animalDto.getCategory()).ordinal());
          animal.setColor(colors[animalDto.getColor()].toString());
    }
}
Replicate answered 30/10, 2020 at 8:21 Comment(0)
A
2

The example you presented might not be the best part of model mapper in fluency especially because converting enums that have some special difficulties what comes to using generics.

Anyway this is possible with Converter or usually AbstractConverter.

You did not provide examples of your enums so I create most simple example enums:

enum Color {
    PINK;
}

and

enum Category {
    MAMMAL;
}

To convert Integer Animal.category to String AnimalDto.category, a converter could be like:

public class CategoryToStringConverter extends AbstractConverter<Integer, String> {
    @Override
    protected String convert(Integer source) {
        return Category.values()[source].toString();
    }
}

And to convert String Animal.color to Integer AnimalDto.category, a converter could be like:

public class ColorToOrdinalConverter extends AbstractConverter<String, Integer> {
    @Override
    protected Integer convert(String source) {
        return Color.valueOf(source).ordinal();
    }
}

Usage would be like:

mm.createTypeMap(Animal.class, AnimalDto.class).addMappings(mapper -> {
    mapper.using(new CategoryToStringConverter()).map(Animal::getCategory, 
        AnimalDto::setCategory);
    mapper.using(new ColorToOrdinalConverter()).map(Animal::getColor, 
        AnimalDto::setColor);
});

This is the part of converting from Animal to AnimalDto. Converting vice versa of course needs mappings of its own which I do not present here because I think the point came clear.

For one class the way you do it now might be better but if you need to convert Category & Color in many places like this then you should consider using converters that are reusable.

Auricula answered 31/10, 2020 at 21:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.