Solución de problemas de MapStruct con ManyToMany



Hola queridos lectores! Aquellos que desarrollan aplicaciones web Java utilizando el marco de Spring, aquellos que comentan sobre estas aplicaciones y simplemente están interesados.

En un artículo anterior, "Solución de problemas de arranque de primavera con ManyToMany"

Di un ejemplo de una aplicación de prueba en la que hay una relación bidireccional ManyToMany entre dos clases. El artículo dio un ejemplo de cómo resolver el problema de bucle al recibir una respuesta de descanso usando la clase DTO. Los lectores en los comentarios sugirieron usar la biblioteca MapStruct para resolver el problema del bucle.

Después de revisar la documentación, estaba convencido de que esto es realmente algo poderoso, con el que puede resolver tareas bastante complejas de mover datos entre objetos. MapStruct también resuelve el problema del bucle.

En este artículo, daré un ejemplo de cómo resolver el mismo problema que una aplicación Spring Boot usando la biblioteca MapStruct. Código fuente disponible en Github

Entity People y SongPlayers se mantuvieron sin cambios. Getters y setters bajados.

@Entity public class People { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; private String human; //      @ManyToOne(cascade = CascadeType.ALL) private RockGroups rockGroups; //     @ManyToMany(mappedBy = "songInstrumentalist",fetch = FetchType.EAGER) private List<SongPlayers> songItems; public People(){} public People(long id, String human){ this.id = id; this.human = human; } //. . . . . } 

 @Entity public class SongPlayers { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; private String song; //    private String composer; //     private String poet; //    private String album; //   //     @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) private List<People> songInstrumentalist; //. . . . . } 

También creamos interfaces de repositorio para las clases People y SongPlayers.

 @Repository public interface PeopleRepository extends JpaRepository<People, Long> { @Query("select h from People h where h.human=?1") List<People> searchByHuman(String human); List<People> findPeopleByHuman(String human); } 

 @Repository public interface SongPlayersRepository extends JpaRepository<SongPlayers, Long> { List<SongPlayers> findSongPlayersBySong(String song); List<SongPlayers> findSongPlayersByComposer(String composer); List<SongPlayers> findSongPlayersByPoet(String poet); } 

También creamos clases DTO para People y SongPlayers, que ahora no se ven tan voluminosas. Getters y setters bajo.

 public class PeopleDTO { private long id; private String human; private RockGroups rockGroups; private List<SongPlayersDTO> songPlayersList; // . . . . . } 

 public class SongPlayersDTO { private long id; private String song; private String composer; private String poet; private String album; // . . . . . } 

Para describir la regla de transferir datos desde el objeto fuente al objeto DTO y, si es necesario, de regreso, creamos interfaces de mapeador para cada clase para la que se requiere protección contra bucles. Aquí están PeopleMapper y SongPlayersMapper

 @Mapper(uses = SongPlayersMapper.class) public interface PeopleMapper { PeopleMapper PEOPLE_MAPPER = Mappers.getMapper(PeopleMapper.class); @Mapping(source = "songItems", target = "songPlayersList") PeopleDTO fromPeople(People people); } 

 @Mapper/*(uses = {PeopleMapper.class})*/ public interface SongPlayersMapper { SongPlayersMapper SONG_PLAYERS_MAPPER = Mappers.getMapper(SongPlayersMapper.class); SongPlayersDTO fromSongPlayers(SongPlayers songPlayers); @InheritInverseConfiguration SongPlayers toSongPlayers(SongPlayersDTO songPlayersDTO); } 

En la carpeta Servicio, cree las interfaces y la implementación de las clases de servicio, en las que colocamos los métodos de recepción de datos (lo daré para Personas).

 public interface PeopleService { List<PeopleDTO> getAllPeople(); PeopleDTO getPeopleById(long id); People addPeople(People people); void delPeople(long id); ResponseEntity<Object> updPeople(People people, long id); List<RockGroups> getByHuman(String human); List<String> getSongByHuman(String human); } 

 @Service("peopleservice") public class PeopleServiceImpl implements PeopleService { @Autowired private PeopleRepository repository; @Override public List<PeopleDTO> getAllPeople() { List<PeopleDTO> peopleDTOList = new ArrayList<>(); List<People> peopleList = repository.findAll(); for (People people : peopleList){ peopleDTOList.add(PeopleMapper.PEOPLE_MAPPER.fromPeople(people)); } return peopleDTOList; } // . . . . . } 

En los controladores, aplicaremos estos métodos en consecuencia (nuevamente solo para Personas)

 @RestController @RequestMapping("/people") public class PeopleController { @Autowired private PeopleServiceImpl service; @GetMapping("/all") public List<PeopleDTO> getAllPeople(){ return service.getAllPeople(); } // . . . . . } 

De la solución anterior del problema de bucle para la relación ManyToMany, puedo decir que la opción con las clases DTO del artículo anterior y la versión con la biblioteca MapStruct de este artículo también están funcionando. En comparación con la versión anterior, la clase DTO se ha simplificado enormemente, pero se han agregado interfaces Mapper. En general, se puede usar cualquier método, para casos simples me inclinaría por la primera opción.

Agradezco a todos los participantes en la discusión. Esperando sus comentarios.

Enlace al artículo anterior .

Enlace al proyecto en Github .

Literatura utilizada:

  • Bota de primavera Felipe Gutiérrez Pro
  • Craig Walls Spring en acción 5ª edición

Source: https://habr.com/ru/post/es433270/


All Articles