Skip to content

Mapstruct: Returning null when trying to map a field inside an embedded object

We were given an assignment to recreate a simple version of the Twitter API in Spring using Mapstruct.

We are returning a List<UserDto> that should return the field username from the embedded object Credentials.

We mapped this as follows:

@Mapper(componentModel = "spring", uses = {ProfileMapper.class, CredentialMapper.class})
public interface UserMapper {

    User dtoToEntity(CreateUserDto createUserDto);

    @Mapping(target = "username", source = "credentials.username")
    List<UserDto> entitiesToDtos(List<User> users);

}

Our UserDto is specified like this:

@NoArgsConstructor
@Data
public class UserDto {

    private ProfileDto profile;
    private Timestamp joined;
    private String username;

}

Our User entity has an embedded object named credentials, where the username and password of the user are stored in String format (I know this is dumb, this is just an assignment).

@NoArgsConstructor
@Entity
@Data
@Table(name="users")
public class User {

    @Id
    @GeneratedValue
    private Long id;

    @CreationTimestamp
    private Timestamp joined;

    private boolean deleted;

    @Embedded
    private Credential credentials;

    @Embedded
    private Profile profile;

Long story short, when we GET all users, we should receive this (these are fake names and numbers):

{
    "profile": {
        "firstName": "Chanda",
        "lastName": "Hackett",
        "email": "[email protected]",
        "phone": "313-574-1401"
    },
    "joined": "2021-03-17T21:15:35.289+00:00",
    "username": "chandahackett"
}

But instead, we receive a null value for username:

{
    "profile": {
        "firstName": "Chanda",
        "lastName": "Hackett",
        "email": "[email protected]",
        "phone": "313-574-1401"
    },
    "joined": "2021-03-17T21:15:35.289+00:00",
    "username": null
}

I know the value username in credentials exists, as it exists in the table it is stored:

enter image description here

And it is accessible because other methods that call user.getCredentials().getUsername() return the right username.

I have tried pretty much everything. I have run mvn clean install, renamed variables. I’m out of ideas. Any help would be appreciated.

Answer

The way you’re trying to use @Mapping on a collection-mapping method isn’t supported at the moment. You need to declare an explicit mapping from User to UserDto, and apply the annotation on it instead:

@Mapper(componentModel = "spring", uses = {ProfileMapper.class, CredentialMapper.class})
public interface UserMapper {
    User dtoToEntity(CreateUserDto createUserDto);
    @Mapping(target = "username", source = "credentials.username")
    UserDto entityToDto(User user);
    List<UserDto> entitiesToDtos(List<User> users);
}