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": "chandahackett@gmail.com",
"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": "chandahackett@gmail.com",
"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:
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.
Advertisement
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);
}