ModelMapper: mapping abstract classes during runtime
Asked Answered
G

3

8

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

Gelasius answered 23/1, 2015 at 14:17 Comment(0)
G
0

I couldn't solve this problem with ModelMapper. Thus, I switched over to Dozer.
Dozer is a great tool for object mapping in Java. And it is really easy to use as well. You can define the corresponding mapping classes in a XML-file.

Here's a link to the documentation. http://dozer.sourceforge.net/documentation/mappings.html

My Solution with Spring
dozer-bean.xml

<bean class="org.dozer.spring.DozerBeanMapperFactoryBean" lazy-init="false">
        <property name="mappingFiles">
            <list>
                <value>META-INF/mapping/dozer-config.xml</value>
            </list>
        </property>
</bean>

dozer-config.xml

<mapping>
            <class-a>com.packagename.dto.QuestionDTO</class-a>
            <class-b>com.packagename.entities.core.Question</class-b>
</mapping>
<mapping>
        <class-a>com.packagename.dto.CriteriaDTO</class-a>
        <class-b>com.packagename.entities.core.Criteria</class-b>
</mapping>
Gelasius answered 29/1, 2015 at 22:16 Comment(0)
E
4

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.

Electroencephalogram answered 14/11, 2018 at 19:34 Comment(0)
U
1

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

Ulises answered 20/7, 2020 at 14:21 Comment(0)
G
0

I couldn't solve this problem with ModelMapper. Thus, I switched over to Dozer.
Dozer is a great tool for object mapping in Java. And it is really easy to use as well. You can define the corresponding mapping classes in a XML-file.

Here's a link to the documentation. http://dozer.sourceforge.net/documentation/mappings.html

My Solution with Spring
dozer-bean.xml

<bean class="org.dozer.spring.DozerBeanMapperFactoryBean" lazy-init="false">
        <property name="mappingFiles">
            <list>
                <value>META-INF/mapping/dozer-config.xml</value>
            </list>
        </property>
</bean>

dozer-config.xml

<mapping>
            <class-a>com.packagename.dto.QuestionDTO</class-a>
            <class-b>com.packagename.entities.core.Question</class-b>
</mapping>
<mapping>
        <class-a>com.packagename.dto.CriteriaDTO</class-a>
        <class-b>com.packagename.entities.core.Criteria</class-b>
</mapping>
Gelasius answered 29/1, 2015 at 22:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.