问题:User DTO
的MapstructMap器未返回JSON中深度嵌套的DTO字段的空值(UserDto类具有PlaylistDto属性,而PlaylistDto类本身包含SongDto字段)。
**项目OVREVIEW:**我在使用mapstruct正确Map嵌套DTO字段时遇到了一些问题。我正在处理一个音乐流springBoot应用程序,它处理几个实体-User
、Playlist
和Song
。用户和播放列表(用户是拥有方)之间存在一对多关联,播放列表(拥有方)和歌曲实体之间存在多对多关联。这些实体如下:
用户实体
@Entity
@Table(name = "users")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id ;
private String username ;
private String password ;
private String email ;
private String firstname ;
private String lastname ;
@OneToMany(
mappedBy = "user" ,
cascade = {CascadeType.PERSIST , CascadeType.MERGE} ,
orphanRemoval = true
)
private List<Playlist> playlists = new ArrayList<>() ;
// getters, setters and constructors ...
}
播放列表实体
@Entity
@Table(name = "playlist")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class Playlist {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id ;
private String name ;
private String description ;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "user_id")
private User user ;
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(
name = "playlist_song" ,
joinColumns = {@JoinColumn(name = "playlist_id")} ,
inverseJoinColumns = {@JoinColumn(name = "song_id")}
)
private Set<Song> songs = new HashSet<>() ;
// getters, setters and constructors ...
}
歌曲实体
@Entity
@Table(name = "song")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class Song {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id ;
private String name ;
private String artist ;
private String album ;
private Integer year ;
private String genre ;
private Integer duration ;
@ManyToMany(mappedBy = "songs")
private Set<Playlist> playlists = new HashSet<>() ;
// getters, setters and constructors ...
上述实体的DTO如下:
用户DTO
public class UserDto {
private Long id ;
private String username ;
private String email ;
private String firstname ;
private String lastname ;
private List<PlaylistDto> playlistsDto ;
// constructors
public UserDto() {
}
public UserDto(Long id, String username, String email, String firstname, String lastname, List<PlaylistDto> playlistsDto) {
this.id = id;
this.username = username;
this.email = email;
this.firstname = firstname;
this.lastname = lastname;
this.playlistsDto = playlistsDto;
}
// getters and setters ...
}
播放列表DTO
public class PlaylistDto {
private Long id ;
private String name ;
private String description ;
private Set<SongDto> songsDto;
// constructors
public PlaylistDto() {
}
public PlaylistDto(Long id, String name, String description, Set<SongDto> songsDto) {
this.id = id;
this.name = name;
this.description = description;
this.songsDto = songsDto;
}
// getters & setters
}
歌曲DTO
public class SongDto {
private Long id ;
private String name ;
private String artist ;
private String album ;
// constructors
public SongDto() {
}
public SongDto(Long id, String name, String artist, String album) {
this.id = id;
this.name = name;
this.artist = artist;
this.album = album;
}
// getters & setters
}
最后,这里是Map器:
// User Mapper
@Mapper(componentModel = "spring" , uses = {PlaylistDto.class , SongDto.class})
@Component
public interface UserMapper {
UserMapper MAPPER = Mappers.getMapper(UserMapper.class);
@Mapping(source = "playlists", target = "playlistsDto")
UserDto usertoUserDto(User user) ;
@Mapping(source = "playlistsDto", target = "playlists")
User userDtoToCustomer(UserDto userDto) ;
}
// Playlist Mapper
@Mapper(componentModel = "spring" , uses = {SongDto.class})
@Component
public interface PlaylistMapper {
PlaylistMapper MAPPER = Mappers.getMapper(PlaylistMapper.class) ;
@Mapping(source = "songs" , target = "songsDto")
PlaylistDto playlistToDto (Playlist entity) ;
@Mapping(source = "songsDto" , target = "songs")
Playlist toEntity (PlaylistDto dto) ;
}
// Song Mapper
@Mapper(componentModel = "spring")
@Component
public interface SongMapper {
SongMapper MAPPER = Mappers.getMapper(SongMapper.class) ;
SongDto songToDto (Song entity) ;
Song toEntity (SongDto dto) ;
}
mapstruct生成的Mapper实现:
播放列表Map器实现
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2023-04-04T11:16:24+0530",
comments = "version: 1.5.3.Final, compiler: javac, environment: Java 19.0.2 (Oracle Corporation)"
)
@Component
public class PlaylistMapperImpl implements PlaylistMapper {
@Override
public PlaylistDto playlistToDto(Playlist entity) {
if ( entity == null ) {
return null;
}
PlaylistDto playlistDto = new PlaylistDto();
playlistDto.setSongsDto( songSetToSongDtoSet( entity.getSongs() ) );
playlistDto.setId( entity.getId() );
playlistDto.setName( entity.getName() );
playlistDto.setDescription( entity.getDescription() );
return playlistDto;
}
@Override
public Playlist toEntity(PlaylistDto dto) {
if ( dto == null ) {
return null;
}
Playlist playlist = new Playlist();
playlist.setSongs( songDtoSetToSongSet( dto.getSongsDto() ) );
playlist.setName( dto.getName() );
playlist.setDescription( dto.getDescription() );
return playlist;
}
protected SongDto songToSongDto(Song song) {
if ( song == null ) {
return null;
}
SongDto songDto = new SongDto();
songDto.setId( song.getId() );
songDto.setName( song.getName() );
songDto.setArtist( song.getArtist() );
songDto.setAlbum( song.getAlbum() );
return songDto;
}
protected Set<SongDto> songSetToSongDtoSet(Set<Song> set) {
if ( set == null ) {
return null;
}
Set<SongDto> set1 = new LinkedHashSet<SongDto>( Math.max( (int) ( set.size() / .75f ) + 1, 16 ) );
for ( Song song : set ) {
set1.add( songToSongDto( song ) );
}
return set1;
}
protected Song songDtoToSong(SongDto songDto) {
if ( songDto == null ) {
return null;
}
Song song = new Song();
song.setName( songDto.getName() );
song.setArtist( songDto.getArtist() );
song.setAlbum( songDto.getAlbum() );
return song;
}
protected Set<Song> songDtoSetToSongSet(Set<SongDto> set) {
if ( set == null ) {
return null;
}
Set<Song> set1 = new LinkedHashSet<Song>( Math.max( (int) ( set.size() / .75f ) + 1, 16 ) );
for ( SongDto songDto : set ) {
set1.add( songDtoToSong( songDto ) );
}
return set1;
}
}
User MapperImpl
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2023-04-04T11:16:25+0530",
comments = "version: 1.5.3.Final, compiler: javac, environment: Java 19.0.2 (Oracle Corporation)"
)
@Component
public class UserMapperImpl implements UserMapper {
@Override
public UserDto usertoUserDto(User user) {
if ( user == null ) {
return null;
}
UserDto userDto = new UserDto();
userDto.setPlaylistsDto( playlistListToPlaylistDtoList( user.getPlaylists() ) );
userDto.setId( user.getId() );
userDto.setUsername( user.getUsername() );
userDto.setEmail( user.getEmail() );
userDto.setFirstname( user.getFirstname() );
userDto.setLastname( user.getLastname() );
return userDto;
}
@Override
public User userDtoToCustomer(UserDto userDto) {
if ( userDto == null ) {
return null;
}
User user = new User();
user.setPlaylists( playlistDtoListToPlaylistList( userDto.getPlaylistsDto() ) );
user.setUsername( userDto.getUsername() );
user.setEmail( userDto.getEmail() );
user.setFirstname( userDto.getFirstname() );
user.setLastname( userDto.getLastname() );
return user;
}
protected PlaylistDto playlistToPlaylistDto(Playlist playlist) {
if ( playlist == null ) {
return null;
}
PlaylistDto playlistDto = new PlaylistDto();
playlistDto.setId( playlist.getId() );
playlistDto.setName( playlist.getName() );
playlistDto.setDescription( playlist.getDescription() );
return playlistDto;
}
protected List<PlaylistDto> playlistListToPlaylistDtoList(List<Playlist> list) {
if ( list == null ) {
return null;
}
List<PlaylistDto> list1 = new ArrayList<PlaylistDto>( list.size() );
for ( Playlist playlist : list ) {
list1.add( playlistToPlaylistDto( playlist ) );
}
return list1;
}
protected Playlist playlistDtoToPlaylist(PlaylistDto playlistDto) {
if ( playlistDto == null ) {
return null;
}
Playlist playlist = new Playlist();
playlist.setName( playlistDto.getName() );
playlist.setDescription( playlistDto.getDescription() );
return playlist;
}
protected List<Playlist> playlistDtoListToPlaylistList(List<PlaylistDto> list) {
if ( list == null ) {
return null;
}
List<Playlist> list1 = new ArrayList<Playlist>( list.size() );
for ( PlaylistDto playlistDto : list ) {
list1.add( playlistDtoToPlaylist( playlistDto ) );
}
return list1;
}
}
意外行为
我还设置了控制器,用于检索数据库中的播放列表和数据库中的用户的JSON对象。GET播放列表(DTO)
的端点给出了预期的JSON对象,因为嵌套的songDto字段不会为每个播放列表对象返回null,如下图所示:
相反,对于具有GET request to fetch all users (DTOs)
的端点,嵌套的playlistDto字段似乎工作正常,但内部嵌套的songsDto字段为每个userDto JSON对象返回null。此行为不应发生(因为存在与一些播放列表相关联的歌曲,这些歌曲可以在GET播放列表端点的输出中看到)。下面是GET用户请求的JSON对象的图像:
为什么只在获取所有UsersDto
时出现空值问题,而在获取所有playlistsDto
时不会出现空值问题,以及如何修复。
1条答案
按热度按时间y4ekin9u1#
您在Map器配置中使用了错误的
uses
字段。您引用的是DTO。根据文档,您需要引用另一个Map器,该Map器应该由已配置的Map器使用
您的解决方案应如下所示:
顺便说一句,你不必在你展示的类中调用
Mappers.get(
。这个引用从来没有使用过。它是用uses
配置引用的。