In my SpringBoot application, I have two entities User
and Role
with
public class User { private Long id; private String email; private String password; private Set<Role> roles; [...] } public class Role { private Long id; private String name; private Set<User> users; [...] }
My DTOs looked quite similar until I realized this could lead to a recursion problem, when a user
has a field role
which has a field of the same user
, which has a field of the same role
, etc.
Therefore I decided to hand only the id
s my DTOs, so they would look like this
public class UserDto { private Long id; private String email; private String password; private List<Long> roleIds; } public class RoleDto { private Long id; private String name; private List<Long> userIds; }
My mappers were quite simple and used to look like this
import org.mapstruct.Mapper; @Mapper public interface UserMapper { User userDtoToUser(UserDto userDto); UserDto userToUserDto(User user); List<UserDto> userListToUserDtoList(List<User> users); } import org.mapstruct.Mapper; @Mapper public interface RoleMapper { Role roleDtoToRole(RoleDto roleDto); RoleDto roleToRoleDto(Role Role); List<RoleDto> roleListToRoleDtoList(List<Role> roles); }
How would I change them so they would convert users
to/from userIds
and roles
to/from roleIds
?
Advertisement
Answer
The unidirectional mapping from roles
to rolesDtos
or users
to usersDtos
is quite simple
@Mapper public interface RoleMapper { List<RoleDto> roleListToRoleDtoList(List<Role> role); @Mapping(target = "userIds", source = "users", qualifiedByName = "userListToUserDtoList") RoleDto roleToRoleDto(Role role); @Named("userListToUserDtoList") default List<Long> userListToUserDtoList(Set<User> users) { return users.stream().map(User::getId).collect(Collectors.toList()); } } @Mapper public interface UserMapper { List<UserDto> userListToUserDtoList(List<User> users); @Mapping(target = "roleIds", source = "roles", qualifiedByName = "roleListToRoleDtoList") UserDto userToUserDto(User user); @Named("roleListToRoleDtoList") default List<Long> roleListToRoleDtoList(Set<Role> roles) { return roles.stream().map(Role::getId).collect(Collectors.toList()); } }
The real problem is to map
User userDtoToUser(UserDto userDto);
or
Role roleDtoToRole(RoleDto roleDto);
Because here MapStruct doesn’t know how to convert userIds
to users
you need some mechanism to fetch each userId and parse it to the whole object. If you are using Spring you can make your mappers as Spring beans – https://mapstruct.org/documentation/stable/reference/html/#using-dependency-injection or decorators https://mapstruct.org/documentation/stable/reference/html/#decorators-with-spring for a “fetching method” injecting somehow proper repository.
, but here I would consider if the effort is worth digging or implement some dedicate method to your recursion
case in directional mapping.