Пока я практиковался в реализации двунаправленной ассоциации @OneToMany
, я застрял в реализации операции удаления для объекта User
, я получаю это предупреждение - Could not write JSON: failed to lazily initialize a collection, could not initialize proxy - no Session
Итак, у меня есть две сущности следующим образом:
@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.ALL ,
orphanRemoval = true
)
private List<Playlist> playlists = new ArrayList<>() ;
// getters and setters
}
@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;
// getters and setters
}
@RestController
@RequestMapping("/api/users")
public class userController {
@Autowired
UserService userService ;
// ... other controller mappings
@PostMapping("")
public User createUser(@RequestBody User reqUser){
return userService.createUser(reqUser) ;
}
@DeleteMapping("/{userID}")
public User removeUser (@PathVariable Long userID) {
return userService.removeUser(userID) ;
}
}
@Service
public class UserService {
@Autowired
UserRepo userRepo ;
public List<User> getAllUsers() {
List <User> users = new ArrayList<>() ;
userRepo.findAll().forEach(users::add);
return users ;
}
public User createUser(User reqUser) {
User newUser = new User() ;
newUser.setUsername(reqUser.getUsername());
newUser.setEmail(reqUser.getEmail());
newUser.setPassword(reqUser.getPassword());
newUser.setFirstname(reqUser.getFirstname());
newUser.setLastname(reqUser.getLastname());
// adding playlists
reqUser.getPlaylists().forEach( playlist -> {
newUser.addPlaylist(playlist);
});
userRepo.save(newUser) ;
return newUser ;
}
public User removeUser(Long userID) {
// check if user exists
User user = userRepo.findById(userID).orElseThrow(
() -> new EntityNotFoundException("User doesn't exists with userID " + userID)
);
userRepo.deleteById(userID) ;
return user ;
}
}
{
"id": 20,
"username": "poodie",
"password": "randomPasswrod",
"email": null,
"firstname": "Raj",
"lastname": "Bhushan",
"playlists": [
{
"id": 27,
"name": "playlist-01",
"description": "first playlist",
"user": 20,
"songs": []
},
{
"id": 28,
"name": "playlist-02",
"description": "first playlist",
"user": 20,
"songs": []
}
]
}
{
"timestamp": "2023-04-02T14:39:45.433+00:00",
"status": 500,
"error": "Internal Server Error",
"path": "/api/users/20"
}
Ниже вы можете увидеть предупреждение, полученное в трассировке стека:
2023-04-02 20:09:45.418 WARN 26500 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter
.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialize a collection, could not initialize proxy - no Session; nested exception is com.fasterxml
.jackson.databind.JsonMappingException: failed to lazily initialize a collection, could not initialize proxy - no Session (through reference chain: com.rudra.musicStreaming
.models.User["playlists"]->org.hibernate.collection.internal.PersistentBag[0]->com.rudra.musicStreaming.models.Playlist["songs"])]
Хотя этот пользователь удаляется из БД, но оставляет это предупреждение в трассировке стека. Как я могу избавиться от этой проблемы (Could not write JSON: failed to lazily initialize a collection, could not initialize proxy - no Session
) и в чем причина этой проблемы?
Примечание. Когда я изменяю метод удаления, чтобы он не возвращал объект User
, все работает нормально, но когда я пытаюсь вернуть объект объекта User
при выполнении операции удаления (как показано в приведенном выше коде), это предупреждение появляется в трассировке стека.
Это не ясно, вы хотите исправить исключение отложенной инициализации или избежать его?
@RomanC, какой бы вариант ни был лучшим, но я думаю, что хотел бы понять, как они исправляют, а также избегают этого. Также я не могу понять, почему любая другая конечная точка, такая как запросы POST/GET/PUT, работает нормально, но когда я пытаюсь вернуть объект только из конечной точки DELETE, тогда почему я получаю это исключение?
Зачем тебе это? Эти объекты также следует удалить перед удалением пользователя.
@RomanC, скорее всего, в реальном проекте я не буду его использовать, но после обучения я хотел бы знать реальную проблему, стоящую за этим, а также обходной путь для ее устранения.
Исправить легко, если вы понимаете, что я написал в ответе ниже.
спасибо за ответ, я тоже несколько наивно думал в подобном направлении
@RomanC Теперь я понимаю, что то, что я делаю, в идеале неправильно, но я хотел бы знать, нет ли другого выхода, чтобы получить то, чего я пытаюсь достичь, то есть вернуть объект из конечной точки DELETE, а также не получить это исключение ?
Объект объекта, который вы возвращаете, больше не находится ни в базе данных, ни в сеансе, а также имеет опцию удаления сирот. Какой список вы хотите получить? Вы сказали, что методы GET/POST/PUT работают, но не разместили код.
Указывает на попытку доступа к невыбранным данным вне контекста открытого сеанса с отслеживанием состояния. Например, это исключение возникает при доступе к неинициализированному прокси-серверу или коллекции после закрытия сеанса.
приходит, потому что вы используете прокси-объект, возвращаемый репозиторием. Прокси пытается инициализировать коллекцию, связанную с этим объектом, когда вы обращаетесь к нему. Но не удается инициализировать коллекцию, потому что этот объект больше не находится в сеансе с момента его удаления.
Удалить конечную точку по соглашению ничего не должно возвращать. Вы не можете вернуть только что удаленного пользователя. Почему должен ты?