I have a class that has a field which in turn is an abstract class. I would like MapStruct to be able to map from the incoming DTO to the internal model including all the subfields of the abstract class, but I only get the empty object in return —rightfully so, since that's the way I've defined the mapping function—.
How can I make it so that MapStruct not only maps the top class, but also the field's classes? Do I have to create mappers for the Cat and Dog classes too, and then bring them in to the OwnerMapper class?
Thank you in advance!
Example setup
Mapper interface
@Mapper(componentModel = MappingConstants.ComponentModel.CDI)
public interface OwnerMapper {
@Mapping(source = "pet", target = "pet", qualifiedByName = "mapPet")
Owner toEntity(OwnerDTO owner);
@Named("mapPet")
default Pet mapPet(final PetDTO pet) {
if (pet instanceof CatDTO) {
return new Cat();
} else {
return new Dog();
}
}
}
Internal classes
public class Owner {
private String name;
private Pet pet;
public Owner() { }
// Omitting getters and setters.
}
public abstract class Pet {
public abstract String makeNoise();
}
public final class Dog extends Pet {
private UUID dogTag;
private String name;
public Dog() { }
@Override
public String makeNoise() {
return "Bark!";
}
// Omitting getters and setters.
}
public final class Cat extends Pet {
private boolean bell;
public Cat() { }
@Override
public String makeNoise() {
return "Meow!";
}
// Omitting getters and setters.
DTO classes
public class OwnerDTO {
private String name;
private PetDTO pet;
public OwnerDTO() { }
// Omitting getters and setters.
public abstract class PetDTO {
}
public final class CatDTO extends PetDTO {
private UUID catTag;
private boolean bell;
public CatDTO() { }
// Omitting getters and setters.
public final class DogDTO extends PetDTO {
private UUID dogTag;
private String name;
public DogDTO() { }
// Omitting getters and setters.
Well, I solved it by defining a few more mapping methods and calling them from the named mapper function: