I am using ModelMapper Framework (http://modelmapper.org/) for mapping objects in Java. I have encountered a problem while mapping concrete classes (DTO to Entites) containing abstract classes.
Example:
Task has a list of AbstractItems.
AbstractItems are Question and Criteria.
public class TaskDTO {
...
private List<AbstractItemDTO> items;
}
Mapping method:
// task is an TaskDTO object
return getModelMapper().map(task, TaskEntity.class);
ModelMapper tries to create a new instance of AbstractItem, which throws an exception.
Is there a way to map the abstract classes during the runtime?
Like QuestionDTO -> Question, CriteriaDTO ->Criteria
I also had this problem and solved this with:
public void configure(ModelMapper modelMapper) {
modelMapper.typeMap(QuestionDto.class, AbstractItem.class)
.setConverter(converterWithDestinationSupplier(Question::new));
modelMapper.typeMap(CriteriaDto.class, AbstractItem.class)
.setConverter(converterWithDestinationSupplier(Criteria::new));
}
private <S, D> Converter<S, D> converterWithDestinationSupplier(Supplier<? extends D> supplier ) {
return ctx -> ctx.getMappingEngine().map(ctx.create(ctx.getSource(), supplier.get()));
}
Converter uses supplier to create required instance and then uses right typeMap (QuestionDto -> Question or CriteriaDto -> Criteria) to map all properties.
Where a kotlin solution with ModelMapper
DTOs (aka source class)
abstract class BaseRequirementDTO()
class AttributeRequirementDTO(
var attribute: Attribute = Attribute.STRENGTH,
var attributeValue: Long = 10
) : BaseRequirementDTO()
class LevelRequirementDTO(
var requiredLevel: Long = 1
) : BaseRequirementDTO()
My Models (aka destination class)
abstract class BaseRequirement() : Model()
class AttributeRequirement(
var attribute: Attribute = Attribute.STRENGTH,
var attributeValue: Long = 10
) : BaseRequirement()
class LevelRequirement(
var requiredLevel: Long = 1
) : BaseRequirement()
Mapper configuration
val mapper = ModelMapper()
mapper.configuration.matchingStrategy = MatchingStrategies.STRICT
mapper.createTypeMap(BaseRequirement::class.java, BaseRequirementDTO::class.java)
mapper.typeMap(AttributeRequirementDTO::class.java, BaseRequirement::class.java)
.setProvider { request -> mapper.map(request.source, AttributeRequirement::class.java) }
mapper.typeMap(LevelRequirementDTO::class.java, BaseRequirement::class.java)
.setProvider { request -> mapper.map(request.source, LevelRequirement::class.java) }
ModelMapper version: 2.3.7
https://github.com/modelmapper/modelmapper/issues/182#issuecomment-660965119
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With