Comment mapper des classes étendues dans MapStruct

Aug 23 2020

J'ai une question concernant mapStruct. J'ai un cas où j'étends la classe de l'entité de base et je ne sais pas comment la mapper. Voici mon cas.

Entité de base :

public class BaseEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    @Column(name = "id")
    private Long id;
}

BaseDto :

public class BaseDto {

    private Long id;
}

Entité utilisateur :

public class User extends BaseEntity {
    private String name;
    private String lastName;
    private String username;
    private String password;
    private String profilePicturePath;
}

UserDto :

public class UserDto extends BaseDto {
    private String name;
    private String lastName;
    private String username;
    private String password;
    private String profilePicturePath;
}

Et le mappeur est comme ça :

@Mapper(uses = {BaseMapper.class})
public interface UserMapper {

    User userDtoToUser(UserDto userDto);

    UserDto userToUserDto(User user);
}

Mapper de base :

@Mapper
public interface BaseMapper {

    BaseEntity dtoToEntity(BaseDto baseDto);

    BaseDto entityToDto(BaseEntity baseEntity);
}

Le problème est que je ne reçois pas la propriété ID mappée.

Merci pour votre temps.

ÉDITER:

Il n'y a pas d'erreur affichée, dans l'implémentation du mappeur (code généré), il n'y a pas de mappage pour cet ID :

 @Override
    public User userDtoToUser(UserDto userDto) {
        if ( userDto == null ) {
            return null;
        }

        UserBuilder user = User.builder();

        user.name( userDto.getName() );
        user.lastName( userDto.getLastName() );
        user.username( userDto.getUsername() );
        user.password( userDto.getPassword() );
        user.profilePicturePath( userDto.getProfilePicturePath() );

        return user.build();
    }

Réponses

2 Pankaj Aug 23 2020 at 19:51

Je suppose (comme vous n'avez pas mis buiderde code) que le problème est que votre classe de constructeur n'inclut pas le champ de classe parent. MapStruct fait une hypothèse lors de la génération de code pour le mappeur. De la documentation -

L'implémentation par défaut de BuilderProvider suppose ce qui suit :

  1. Le type a une méthode de création de générateur statique public sans paramètre qui renvoie un générateur. Ainsi, par exemple, Person a une méthode statique publique qui renvoie PersonBuilder.
  2. Le type de générateur a une méthode publique sans paramètre (méthode build) qui renvoie le type en cours de construction. Dans notre exemple, PersonBuilder a une méthode qui renvoie Person.
  3. Dans le cas où il existe plusieurs méthodes de construction, MapStruct recherchera une méthode appelée build, si une telle méthode existe, elle sera utilisée, sinon une erreur de compilation sera créée.

Si vous utilisez Lombok, vous pouvez résoudre ce problème en utilisant @SuperBuildercomme -

@SuperBuilder
@Getter
@ToString
public class UserDto extends BaseDto {
  private String name;
  private String lastName;
  private String username;
  private String password;
  private String profilePicturePath;
}

@Getter
@SuperBuilder
class BaseDto {
  private Long id;
}

@SuperBuilder
@Getter
@ToString
public class User extends BaseEntity {
  private String name;
  private String lastName;
  private String username;
  private String password;
  private String profilePicturePath;
}

@Setter
@Getter
@SuperBuilder
class BaseEntity {
  private Long id;
}

Et généré pourrait ressembler à -

@Override
public User userDtoToUser(UserDto userDto) {
    if ( userDto == null ) {
        return null;
    }

    UserBuilder<?, ?> user = User.builder();

    user.id( userDto.getId() );
    user.name( userDto.getName() );
    user.lastName( userDto.getLastName() );
    user.username( userDto.getUsername() );
    user.password( userDto.getPassword() );
    user.profilePicturePath( userDto.getProfilePicturePath() );

    return user.build();
}