Como mapear classes estendidas no MapStruct
Tenho uma pergunta sobre mapStruct. Tenho um caso em que estendo a classe da entidade base e não tenho certeza de como mapeá-la. Aqui está o meu caso.
BaseEntidade:
public class BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "id")
private Long id;
}
BaseDto:
public class BaseDto {
private Long id;
}
UserEntity:
public class User extends BaseEntity {
private String name;
private String lastName;
private String username;
private String password;
private String profilePicturePath;
}
UsuárioDto:
public class UserDto extends BaseDto {
private String name;
private String lastName;
private String username;
private String password;
private String profilePicturePath;
}
E o mapper é assim:
@Mapper(uses = {BaseMapper.class})
public interface UserMapper {
User userDtoToUser(UserDto userDto);
UserDto userToUserDto(User user);
}
Base Mapper:
@Mapper
public interface BaseMapper {
BaseEntity dtoToEntity(BaseDto baseDto);
BaseDto entityToDto(BaseEntity baseEntity);
}
O problema é que não recebo a propriedade de ID mapeada.
Obrigado pelo seu tempo.
EDITAR:
Não há erro mostrado, na implementação do mapeador (código gerado) não há mapeamento para esse 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();
}
Respostas
Eu estou supondo (como você não colocou buidero código) o problema é que sua classe de construtor não inclui o campo de classe pai. O MapStruct faz algumas suposições ao gerar o código para o mapeador. Da documentação -
A implementação padrão do BuilderProvider assume o seguinte:
- O tipo tem um método de criação de construtor estático público sem parâmetros que retorna um construtor. Por exemplo, Person tem um método estático público que retorna PersonBuilder.
- O tipo construtor tem um método público sem parâmetros (método build) que retorna o tipo que está sendo construído. Em nosso exemplo, PersonBuilder tem um método que retorna Person.
- Caso existam vários métodos de compilação, o MapStruct procurará um método chamado build, se tal método existir, ele será usado, caso contrário, um erro de compilação será gerado.
Se você estiver usando o Lombok, poderá resolver isso usando @SuperBuildercomo -
@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 gerado pode parecer -
@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();
}