Come mappare le classi estese in MapStruct

Aug 23 2020

Devo fare una domanda su mapStruct. Ho un caso in cui estendo la classe dall'entità di base e non sono sicuro di come mapparla. Ecco il mio caso.

BaseEntità:

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

BaseDto:

public class BaseDto {

    private Long id;
}

Entità utente:

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

UtenteDto:

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

E mapper è così:

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

    User userDtoToUser(UserDto userDto);

    UserDto userToUserDto(User user);
}

BaseMapper:

@Mapper
public interface BaseMapper {

    BaseEntity dtoToEntity(BaseDto baseDto);

    BaseDto entityToDto(BaseEntity baseEntity);
}

Il problema è che non riesco a mappare la proprietà ID.

Grazie per il tuo tempo.

MODIFICARE:

Non viene visualizzato alcun errore, nell'implementazione del mappatore (codice generato) non esiste alcuna mappatura per quell'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();
    }

Risposte

2 Pankaj Aug 23 2020 at 19:51

Immagino (poiché non hai inserito buideril codice) il problema è che la tua classe builder non include il campo della classe genitore. MapStruct fa alcune ipotesi durante la generazione del codice per mapper. Dalla documentazione -

L'implementazione predefinita di BuilderProvider presuppone quanto segue:

  1. Il tipo ha un metodo di creazione del generatore statico pubblico senza parametri che restituisce un generatore. Quindi, ad esempio, Person ha un metodo statico pubblico che restituisce PersonBuilder.
  2. Il tipo di builder ha un metodo pubblico senza parametri (metodo build) che restituisce il tipo da compilare Nel nostro esempio PersonBuilder ha un metodo che restituisce Person.
  3. Nel caso in cui ci siano più metodi di compilazione, MapStruct cercherà un metodo chiamato build, se tale metodo esiste allora questo verrebbe utilizzato, altrimenti verrebbe creato un errore di compilazione.

Se stai usando Lombok, puoi risolverlo usando @SuperBuilderas -

@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;
}

E potrebbe apparire come -

@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();
}