Я хотел бы правильно добавить сообщения в канал.
Каналы без сообщений добавляются в базу данных должным образом:
{
id: 1,
name: "Off-top",
messageDTOs: [ ],
participantDTOs: [
{
id: 1,
firstName: "Szef",
lastName: "Ceo",
email: "szef.ceo@company.com",
role: "ADMIN",
manager: true
}
}
Но если я добавляю одно сообщение в канал, я получаю ошибку HTTP 500 для GET: /channels.
Я использовал FetchType.EAGER
и соответствующие классы следующие:
Message.java:
@Entity
@Getter
@Setter
@NoArgsConstructor
public class Message {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(nullable = false)
private String content;
@OneToOne
private Employee author;
@Column(nullable = false)
private LocalDateTime creationTime;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "channel_id")
private Channel channel;
public Message(String content, Employee author, Channel channel) {
this.content = content;
this.author = author;
this.creationTime = LocalDateTime.now();
this.channel = channel;
}
public boolean checkIfDataEquals(Message message) {
return content.equals(message.getContent()) &&
author.checkIfDataEquals(message.getAuthor()) &&
channel.checkIfDataEquals(message.getChannel());
}
}
Channel.java
@Entity
@Getter
@Setter
@NoArgsConstructor
public class Channel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
@OneToMany(mappedBy = "channel", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<Message> messages;
@Column(nullable = false)
@ManyToMany
private List<Employee> participants;
public Channel(String name, List<Employee> participants) {
this.name = name;
this.messages = new ArrayList<>();
this.participants = participants;
}
public boolean checkIfDataEquals(Channel channel) {
return name.equals(channel.getName()) &&
compareParticipants(channel.getParticipants());
}
private boolean compareParticipants(List<Employee> participantList) {
if (participantList.isEmpty())
return true;
for (Employee employee : participants) {
if (participantList.stream().noneMatch(t -> t.checkIfDataEquals(employee)))
return false;
}
return true;
}
}
Существует проблема с установкой сообщений DTO в channelDTO, потому что я получаю: java.lang.StackOverflowError: null
at com.herokuapp.erpmesbackend.erpmesbackend.chat.ChannelDTO.<init>(ChannelDTO.java:24) ~[classes/:na]
at com.herokuapp.erpmesbackend.erpmesbackend.chat.MessageDTO.<init>(MessageDTO.java:23) ~[classes/:na]
Для занятий:
MessageDTO.java
@Data
@AllArgsConstructor
public class MessageDTO {
private long id;
private String content;
private EmployeeDTO authorDTO;
private ChannelDTO channelDTO;
private LocalDateTime creationTime;
public MessageDTO(Message message) {
this.id = message.getId();
this.content = message.getContent();
this.authorDTO = new EmployeeDTO(message.getAuthor());
this.channelDTO = new ChannelDTO(message.getChannel()); // PROBLEMATIC LINE
this.creationTime = message.getCreationTime();
}
public MessageDTO(String content, EmployeeDTO authorDTO, ChannelDTO channelDTO) {
this.content = content;
this.authorDTO = authorDTO;
this.channelDTO = channelDTO;
}
public boolean checkIfDataEquals(MessageDTO messageDTO) {
return content.equals(messageDTO.getContent()) &&
authorDTO.checkIfDataEquals(messageDTO.getAuthorDTO()) &&
channelDTO.checkIfDataEquals(messageDTO.getChannelDTO());
}
}
ChannelDTO.java
@Data
@AllArgsConstructor
public class ChannelDTO {
private long id;
private String name;
private List<MessageDTO> messageDTOs;
private List<EmployeeDTO> participantDTOs;
public ChannelDTO(Channel channel) {
this.id = channel.getId();
this.name = channel.getName();
this.messageDTOs = new ArrayList<>();
for (int i = 0; i < channel.getMessages().size(); i++)
messageDTOs.add(new MessageDTO(channel.getMessages().get(i))); // PROBLEMATIC LINE
this.participantDTOs = new ArrayList<>();
channel.getParticipants().forEach(participant -> this.participantDTOs.add(new EmployeeDTO(participant)));
}
public ChannelDTO(String name, List<EmployeeDTO> participantDTOs) {
this.name = name;
this.participantDTOs = participantDTOs;
}
public boolean checkIfDataEquals(ChannelDTO channelDTO) {
return name.equals(channelDTO.getName()) &&
compareParticipantDTOs(channelDTO.getParticipantDTOs());
}
private boolean compareMessageDTOs(List<MessageDTO> messageDTOList) {
if (messageDTOList.isEmpty())
return true;
for (MessageDTO messageDTO: messageDTOs) {
if (messageDTOList.stream().noneMatch(t -> t.checkIfDataEquals(messageDTO)))
return false;
}
return true;
}
private boolean compareParticipantDTOs(List<EmployeeDTO> participantDTOList) {
if (participantDTOList.isEmpty())
return true;
for (EmployeeDTO participantDTO : participantDTOs) {
if (participantDTOList.stream().noneMatch(t -> t.checkIfDataEquals(participantDTO)))
return false;
}
return true;
}
}
MessageController.java:
@RestController
@CrossOrigin(origins = "*")
public class MessageController {
private final MessageRepository messageRepository;
private final ChannelRepository channelRepository;
private final EmployeeRepository employeeRepository;
@Autowired
public MessageController(MessageRepository messageRepository, ChannelRepository channelRepository,
EmployeeRepository employeeRepository) {
this.messageRepository = messageRepository;
this.channelRepository = channelRepository;
this.employeeRepository = employeeRepository;
}
@PostMapping("/channels/{id}/messages")
@ResponseStatus(HttpStatus.CREATED)
public MessageDTO addOneMessage(@PathVariable Long id, @RequestBody MessageRequest messageRequest) {
checkIfChannelExists(1L);
String content = messageRequest.getContent();
Channel channel = channelRepository.findById(id).get();
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String username = ((UserDetails) principal).getUsername();
Employee author = employeeRepository.findByEmail(username).get();
Message message = new Message(content, author, channel);
messageRepository.save(message);
return new MessageDTO(message);
}
private void checkIfChannelExists(Long id) {
if (!channelRepository.findById(id).isPresent())
throw new NotFoundException("Such channel doesn't exist!");
}
}
ChannelController.java
@RestController
@CrossOrigin(origins = "*")
public class ChannelController {
private final ChannelRepository channelRepository;
private final EmployeeRepository employeeRepository;
@Autowired
public ChannelController(ChannelRepository channelRepository, EmployeeRepository employeeRepository) {
this.channelRepository = channelRepository;
this.employeeRepository = employeeRepository;
}
@GetMapping("/channels")
@ResponseStatus(HttpStatus.OK)
public List<ChannelDTO> getAllChannels() {
List<Channel> channels = channelRepository.findAll();
List<ChannelDTO> channelDTOs = new ArrayList<>();
channels.forEach(channel -> channelDTOs.add(new ChannelDTO(channel)));
return channelDTOs;
}
@GetMapping("/channels/{id}")
@ResponseStatus(HttpStatus.OK)
public ChannelDTO getOneChannel(@PathVariable("id") Long id) {
checkIfChannelExists(id);
return new ChannelDTO(channelRepository.findById(id).get());
}
@GetMapping("/employees/{id}/channels")
@ResponseStatus(HttpStatus.OK)
public List<ChannelDTO> getChannelsByParticipant(@PathVariable("id") Long id) {
checkIfParticipantExists(id);
if (!channelRepository.findByParticipantsId(id).isPresent())
return new ArrayList<>();
List<Channel> channels = channelRepository.findByParticipantsId(id).get();
List<ChannelDTO> channelDTOs = new ArrayList<>();
channels.forEach(channel -> channelDTOs.add(new ChannelDTO(channel)));
return channelDTOs;
}
@PostMapping("/channels")
@ResponseStatus(HttpStatus.CREATED)
public ChannelDTO addOneChannel(@RequestBody ChannelRequest channelRequest) {
String name = channelRequest.getName();
checkIfParticipantListIsEmpty(channelRequest.getParticipantIds());
List<Employee> participants = new ArrayList<>();
channelRequest.getParticipantIds().forEach(this::checkIfParticipantExists);
channelRequest.getParticipantIds().forEach(id -> participants.add(employeeRepository.findById(id).get()));
Channel channel = new Channel(name, participants);
channelRepository.save(channel);
return new ChannelDTO(channel);
}
@PutMapping("/channels/{id}")
public HttpStatus updateChannel(@PathVariable("id") Long id, @RequestBody ChannelRequest channelRequest) {
checkIfChannelExists(id);
Channel channel = channelRepository.findById(id).get();
channel.setName(channelRequest.getName());
checkIfParticipantListIsEmpty(channelRequest.getParticipantIds());
List<Employee> participants = new ArrayList<>();
if (channelRequest.getParticipantIds() != null) {
channelRequest.getParticipantIds().forEach(this::checkIfParticipantExists);
channelRequest.getParticipantIds().forEach(index -> participants.add(employeeRepository.findById(index).get()));
}
channel.setParticipants(participants);
channelRepository.save(channel);
return HttpStatus.NO_CONTENT;
}
@DeleteMapping("/channels/{id}")
public HttpStatus removeChannel(@PathVariable("id") Long id) {
checkIfChannelExists(id);
channelRepository.delete(channelRepository.findById(id).get());
return HttpStatus.OK;
}
private void checkIfChannelExists(Long id) {
if (!channelRepository.findById(id).isPresent())
throw new NotFoundException("Such channel doesn't exist!");
}
private void checkIfParticipantExists(Long id) {
if (!employeeRepository.findById(id).isPresent())
throw new NotFoundException("At least one of the participant doesn't exist!");
}
private void checkIfParticipantListIsEmpty(List<Long> participantIds) {
if (participantIds.isEmpty())
throw new InvalidRequestException("List of participants can't be empty!");
}
}
Может ли кто-нибудь помочь, пожалуйста?