I have such a simple class structure which has abstract classes and subclasses. I want them to be mapped to destination class structure using ModelMapper.
I have checked and none of the solutions in other questions related to mapping abstract classes fixes my problem. This comment and this comment are somehow closest to what I want to achieve but in the scenario below it still fails.
The validation message I get from ModelMapper
is:
org.modelmapper.MappingException: ModelMapper mapping errors:
1) Failed to instantiate instance of destination
com.mls.services.MapperTest$DestParent. Ensure that
com.mls.services.MapperTest$DestParent has a non-private no-argument
constructor.
...
What is clear for me as DestParent class is abstract and cannot be instantiated.
Is there any way to make this working?
Here is a test source code as JUnit test case. Assertion in the bottom fails or validation throws an exception if I make some tries to fix this:
public class MapperTest {
abstract static class SourceParent {}
static class SourceSubA extends SourceParent {}
static class SourceSubB extends SourceParent {}
abstract static class DestParent {}
static class DestSubA extends DestParent {}
static class DestSubB extends DestParent {}
static class Source {
SourceParent item;
public SourceParent getItem() {return item;}
public void setItem(SourceParent item) {this.item = item;}
}
static class Dest {
DestParent item;
public DestParent getItem() {return item;}
public void setItem(DestParent item) {this.item = item;}
}
@Test
public void test() {
ModelMapper modelMapper = new ModelMapper();
TypeMap<Source, Dest> typeMap = modelMapper.createTypeMap(Source.class, Dest.class);
// modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.LOOSE);
modelMapper
.createTypeMap(SourceSubA.class, DestParent.class)
.setConverter(
mappingContext -> modelMapper.map(mappingContext.getSource(), DestSubA.class));
modelMapper
.createTypeMap(SourceSubB.class, DestParent.class)
.setConverter(
mappingContext -> modelMapper.map(mappingContext.getSource(), DestSubB.class));
typeMap.addMapping(Source::getItem, Dest::setItem);
TypeMap<SourceParent, DestParent> itemTypeMap =
modelMapper.createTypeMap(SourceParent.class, DestParent.class);
itemTypeMap.include(SourceSubA.class, DestSubA.class);
itemTypeMap.include(SourceSubB.class, DestSubB.class);
Source source = new Source();
source.item = new SourceSubB();
Dest dest = modelMapper.map(source, Dest.class);
modelMapper.validate();
Assert.assertTrue(dest.item instanceof DestSubB);
}
}