Tengo una pregunta sobre mapStruct. Tengo un caso en el que extiendo la clase desde la entidad base y no estoy seguro de cómo mapearla. Este es mi caso.

BaseEntity:

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

UserDto:

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

Y el mapeador es así:

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

El problema es que no obtengo la propiedad de identificación asignada.

Gracias por su tiempo.

Editar:

No se muestra ningún error, en la implementación del mapeador (código generado) no hay mapeo para ese 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();
    }
3
laban007 23 ago. 2020 a las 14:39

1 respuesta

La mejor respuesta

Supongo (ya que no ha puesto el código buider) el problema es que su clase de constructor no incluye el campo de clase principal. MapStruct hace algunas suposiciones al generar código para mapeador. De la documentación -

La implementación predeterminada de BuilderProvider asume lo siguiente:

  1. El tipo tiene un método de creación de constructor estático público sin parámetros que devuelve un constructor. Entonces, por ejemplo, Person tiene un método estático público que devuelve PersonBuilder.
  2. El tipo de constructor tiene un método público sin parámetros (método de construcción) que devuelve el tipo que se está construyendo. En nuestro ejemplo, PersonBuilder tiene un método que devuelve Person.
  3. En caso de que haya varios métodos de compilación, MapStruct buscará un método llamado compilación, si tal método existe, entonces se usaría, de lo contrario se crearía un error de compilación.

Si está usando Lombok, puede resolver esto usando @SuperBuilder como -

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

Y el poder generado se parece a:

@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();
}
2
Pankaj 23 ago. 2020 a las 12:51