Mapstruct: Support for abstract class mapping or classes with base class

Created on 2 Dec 2014  路  7Comments  路  Source: mapstruct/mapstruct

For example (one abstract class and two concrete classes):

public abstract class Animal {
  private String name;

  ...
}

public class Cat extends Animal {
  private Boolean mouseCatcher;

  ...
}

public class Dog extends Animal {
  private Integer awardsCount;

  ...
}

DTO:

public abstract class AnimalDto {
  private String name;

  ...
}

public class CatDto extends AnimalDto {
  private Boolean mouseCatcher;

  ...
}

public class DogDto extends AnimalDto {
  private Integer awardsCount;

  ...
}

And mapper:

@Mapper
public interface AnimalMapper {
  public CatDto catToCatDto(Cat cat);
  public DogDto dogToDogDto(Dog dog);

  @AbstractMapping // special mark to generate abstract mapping method
  public AnimalDto animalToAnimalDto(Animal animal);

  public List<AnimalDto> animalsToAnimalDtos(List<Animal> animals);
}

Generated result:

public class AnimalMapperImpl implements AnimalMapper {
  public CatDto catToCatDto(Cat cat) {
    ...
  }

  public DogDto dogToDogDto(Dog dog) {
    ...
  }

  // example of generated method for abstract mapping
  public AnimalDto animalToAnimalDto(Animal animal) {
    if (animal instanceof Cat)
      return catToCatDto((Cat) animal);
    else if (animal instanceof Dog)
      return dogToDogDto((Dog) animal);
    return null;
  }

  public List<AnimalDto> animalsToAnimalDtos(List<Animal> animals) {
    if ( animals == null ) {
        return null;
    }

    List<AnimalDto> list = new ArrayList<AnimalDto>();

    for ( Animal animal : animals ) {
        list.add( animalToAnimalDto( animal ) );
    }

    return list;
  }
}

Most helpful comment

An example to illustrate what @agudian has said:

@Mapper
public interface UserMapper {

    default UserDTO toDto(User u) {
        if(u instanceof User1)
            return toDto1((User1) u);
        return toDto2((User2) u);
    }
    default User toEntity(UserDTO u) {
        if(u instanceof User1DTO)
            return toEntity1((User1DTO) u);
        return toEntity2((User2DTO) u);
    }

    User1DTO toDto1(User1 u);
    User1 toEntity1(User1DTO u);

    User2DTO toDto2(User2 u);
        User2 toEntity2(User2DTO u);
}

That would be right, isn't?

All 7 comments

This is basically a duplicate of #131. There's some stuff that we need to think about, but I also still find it worth exploring.

Yes, it's an interesting idea. I'm no huge fan of the instance-of calls, but I guess there is no way around them.

If such functionality is implemented, we could possibly drop #319 as well.

IIUC: what we actually try to implement is automatic generation of factory methods that @agudian implemented earlier (see org.mapstruct.ap.test.factories.GenericFactory). Can we use the 'forgedmethod' mechanism to achieve this? How would we establish which classes to include in the 'instance-of if statements'

Hi guys, is there any development on this issue (or the referenced #131 )? In case not, what would you recommend for an ad-hoc implementation of this looks like? The use case is exactly the one described here: converting between parallel class hierarchies of Entity/Dto objects:

  Person                 PersonDto
  /    \                  /    \
Man   Woman           ManDto   WomanDto

And the method I would like to implement is List<? extends PersonDto> peopleToDtos(List<? extends Person> people)?

Hi, as @milanov requested could you please provide how to do these>?
I also want to implement List<? extends BaseClass> but there does not seems to be a way to do this.
Alternately can you suggest how to do it currently?

The way you'd currently do this is to declare the mapping methods for cat/dog or man/woman to let them be generated and implement the method operating on the abstract classes with the instance-of dance manually.

For lists and such, MapStruct will then delegate to your manually created method.

An example to illustrate what @agudian has said:

@Mapper
public interface UserMapper {

    default UserDTO toDto(User u) {
        if(u instanceof User1)
            return toDto1((User1) u);
        return toDto2((User2) u);
    }
    default User toEntity(UserDTO u) {
        if(u instanceof User1DTO)
            return toEntity1((User1DTO) u);
        return toEntity2((User2DTO) u);
    }

    User1DTO toDto1(User1 u);
    User1 toEntity1(User1DTO u);

    User2DTO toDto2(User2 u);
        User2 toEntity2(User2DTO u);
}

That would be right, isn't?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

PFStruct picture PFStruct  路  5Comments

chriswill0w picture chriswill0w  路  3Comments

mowcixo picture mowcixo  路  6Comments

lordplagus02 picture lordplagus02  路  5Comments

jega-ms picture jega-ms  路  4Comments