mdzh
mdzh

Reputation: 1050

How do I map parent class DTO to parent class entity

I have the following class hierarchy:

public class BaseFaultType
{
    protected String faultId;
    protected String faultDescription;
    protected String faultDetail;

    ... -> setters and getters
}

public class PollingFaultType extends BaseFaultType
{
    protected Integer initiatedFiles;
    protected Integer failedFiles;
    ... -> getters and setters
}

public class StoreFaultType extends BaseFaultType
{
    protected String storePath;
    ... -> getters and setters
}

...

There is one BaseFaultType with some common properties (I left out most of them for simplicity) and then I have multiple types that extend the BaseFaultType with additional properties.

Please note that I have no control over these classes.

My application receives objects of these child types. Then I need to map these objects into different types of entities, i.e:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = EntityConstants.ERROR)
public class FaultMessage
{
    private String errorId;
    private String errorDescription;
    private String errorDetail;
    private Boolean retryable;
    ... -> getters and setters
}

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = EntityConstants.POLLING_MESSAGE)
public class PollingFaultMessage extends FaultMessage
{
    private Integer failed;
    private Integer initiated;
    ... -> getters and setters
}

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = EntityConstants.STORE_MESSAGE)
public class StoreFaultMessage 
{
    ...
}

I am using ModelMapper for this job. Note that the ModelMapper that I use is configured with disabled implicit mapping (for reasons that are not interesting for this question):

mapper.getConfiguration().setImplicitMappingEnabled(false);
mapper.addMappings(new PropertyMap<BaseFaultType, FaultMessage>()
        {
            @Override
            protected void configure()
            {
                map(source.getFaultId()).setErrorId(null);
                map(source.getFaultDescription()).setErrorDescription(null);
                ...
            }
        });
mapper.addMappings(new PropertyMap<PollingFaultType, PollingFaultMessage>()
    {
        @Override
        protected void configure()
        {
            map(source.getInitiatedFiles()).setInitiated(null);
            ...
        }

    });
PollingFaultType faultType = getPollingFaultType();
PollingFaultMessage faultMessage = mapper.map(faultType, PollingFaultMessage.class);

Unfortunately, this produces faultMessage that only has its initiated property mapped to a real value. The properties errorId, errorDetail etc are not being mapped (probably since they are configured into a completely separate TypeMap)

So my question is - how can I configure ModelMapper in a way that allows me to define TypeMaps/PropertyMaps that only map child-specific properties such as initiated and failed and have the common properties that come from the base type such as errorId and errorDetail automatically mapped? The main thing I want to achieve here is that I want to avoid having to explicitly specify the mapping of these common properties in each child's TypeMap, i.e. I want to avoid to:

mapper.addMappings(new PropertyMap<PollingFaultType, PollingFaultMessage>()
        {
            @Override
            protected void configure()
            {
                // I want to avoid to copy these lines around for each child mapping since they will be always the same
                map(source.getFaultId()).setErrorId(null);
                map(source.getFaultDescription()).setErrorDescription(null);


                map(source.getInitiatedFiles()).setInitiated(null);
                ...
            }

        });

Upvotes: 1

Views: 3047

Answers (1)

Andrew Nepogoda
Andrew Nepogoda

Reputation: 1895

Try to do next:

beans:

public class BaseType {
    protected String base;
    // getters/setters
}
public class Extended extends  BaseType {

    private String value ;
    // getters/setters
}

dto:

public class SimpleDTO {
    private String valueDTO;
    private String baseDTO;
    // getters/setters
}

configuration:

modelMapper.typeMap(SimpleDTO.class, BaseType.class)
                .addMapping(SimpleDTO::getBaseDTO, BaseType::setBase);
modelMapper.typeMap(SimpleDTO.class, Extended.class)
                .addMapping(SimpleDTO::getValueDTO, Extended::setValue)
                .includeBase(SimpleDTO.class, BaseType.class);

use:

SimpleDTO dto = new SimpleDTO();
dto.setBaseDTO("base");
dto.setValueDTO("value");
Extended ex = modelMapper.map(dto, Extended.class);

ModelMapper version: 1.1.0

Upvotes: 1

Related Questions