Не удалось написать JSON: не удалось лениво инициализировать коллекцию при возврате объекта сущности из метода удаления

Пока я практиковался в реализации двунаправленной ассоциации @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

}

Класс UserController

@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) ;
    }
}

Метод removeUser в классе UserService

@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 ;
    }
}

The Get request for user fetches me this response:
{
    "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": []
        }
    ]
}

Sadly, when I want to delete this same User, even though it gets deleted but I get this error in POSTMAN
{
    "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 при выполнении операции удаления (как показано в приведенном выше коде), это предупреждение появляется в трассировке стека.

Удалить конечную точку по соглашению ничего не должно возвращать. Вы не можете вернуть только что удаленного пользователя. Почему должен ты?

Mar-Z 02.04.2023 17:29

Это не ясно, вы хотите исправить исключение отложенной инициализации или избежать его?

Roman C 02.04.2023 18:51

@RomanC, какой бы вариант ни был лучшим, но я думаю, что хотел бы понять, как они исправляют, а также избегают этого. Также я не могу понять, почему любая другая конечная точка, такая как запросы POST/GET/PUT, работает нормально, но когда я пытаюсь вернуть объект только из конечной точки DELETE, тогда почему я получаю это исключение?

humbleCodes 02.04.2023 19:11

Зачем тебе это? Эти объекты также следует удалить перед удалением пользователя.

Roman C 02.04.2023 19:18

@RomanC, скорее всего, в реальном проекте я не буду его использовать, но после обучения я хотел бы знать реальную проблему, стоящую за этим, а также обходной путь для ее устранения.

humbleCodes 02.04.2023 19:21

Исправить легко, если вы понимаете, что я написал в ответе ниже.

Roman C 02.04.2023 19:41

спасибо за ответ, я тоже несколько наивно думал в подобном направлении

humbleCodes 02.04.2023 19:45

@RomanC Теперь я понимаю, что то, что я делаю, в идеале неправильно, но я хотел бы знать, нет ли другого выхода, чтобы получить то, чего я пытаюсь достичь, то есть вернуть объект из конечной точки DELETE, а также не получить это исключение ?

humbleCodes 02.04.2023 19:48

Объект объекта, который вы возвращаете, больше не находится ни в базе данных, ни в сеансе, а также имеет опцию удаления сирот. Какой список вы хотите получить? Вы сказали, что методы GET/POST/PUT работают, но не разместили код.

Roman C 02.04.2023 20:08
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
9
73
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

LazyInitializationException:

Указывает на попытку доступа к невыбранным данным вне контекста открытого сеанса с отслеживанием состояния. Например, это исключение возникает при доступе к неинициализированному прокси-серверу или коллекции после закрытия сеанса.

приходит, потому что вы используете прокси-объект, возвращаемый репозиторием. Прокси пытается инициализировать коллекцию, связанную с этим объектом, когда вы обращаетесь к нему. Но не удается инициализировать коллекцию, потому что этот объект больше не находится в сеансе с момента его удаления.

Другие вопросы по теме