Search code examples
jsonspring-boothibernatejpaone-to-many

Could not write JSON: failed to lazily initialize a collection of role. When I remove @JsonManagedReference and @JsonBackReference it works


I am having an error with the fetch type and I dont know how to fix it! I retried to solve with similar issue solutions, but didn't work. Using java 11, Spring boot 2.6.5, gradle

MenuController:

package com.magsad.msnav.controller;

import com.magsad.msnav.entity.Menu;
import com.magsad.msnav.service.MenuService;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@RestController
@RequestMapping("menu")
@RequiredArgsConstructor
@FieldDefaults(makeFinal = true,level = AccessLevel.PRIVATE)
public class MenuController {
    MenuService menuService;

    @GetMapping
    public List<Menu> getAllNodes(){
        return menuService.getAll();
    }

    @GetMapping("{nodeId}")
    public Menu getNodeById(@PathVariable Long nodeId){
        return menuService.getById(nodeId);
    }

    @GetMapping("query")
    public Menu getNodeByIdQuery(@RequestParam Long nodeId){
        return menuService.getById(nodeId);
    }

    @PostMapping
    public Menu create(@RequestBody Menu menu){
        return menuService.create(menu);
    }

    @PutMapping
    public Menu update(@RequestBody Menu menu){
        return menuService.update(menu);
    }

    @DeleteMapping("{id}")
    public void delete(@PathVariable Long nodeId){
        menuService.delete(nodeId);
    }
}

Menu entity

import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import lombok.*;

import javax.persistence.*;
import java.util.List;
import java.util.Set;


@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Menu implements Serializable {

    private static final long serialVersionUID = 1L;


    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(name = "url", nullable = false)
    private String url;

    @Column(name = "name")
    private String name;

    @JsonManagedReference
    @OneToMany(mappedBy="parent")
    private Set<Menu> children = new HashSet<>();

    @ManyToOne
    @JsonBackReference
    private Menu parent;
}

When I remove @JsonManagedReference and @JsonBackReference and add @JsonIgnore to private Set<Menu> children = new HashSet<>() it works.

//    @JsonManagedReference
    @OneToMany(mappedBy="parent")
    @JsonIgnore
    private Set<Menu> children = new HashSet<>();

    @ManyToOne
//    @JsonBackReference
    private Menu parent;

MenuRepository

import com.magsad.msnav.entity.Menu;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface MenuRepository extends JpaRepository<Menu,Long> {
}

MenuService

import com.magsad.msnav.entity.Menu;
import com.magsad.msnav.repository.MenuRepository;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Service
@RequiredArgsConstructor
@FieldDefaults(makeFinal = true,level = AccessLevel.PRIVATE)
@Transactional
public class MenuService {
    MenuRepository menuRepository;

    public List<Menu> getAll() {
        return menuRepository.findAll();
/*                .stream()
                .filter(menu-> Objects.isNull(menu.getParent()))
                .collect(Collectors.toList());*/
    }

    public Menu getById(Long nodeId){
        return menuRepository.findById(nodeId).get();
    }

    public Menu create(Menu menu){
        return menuRepository.save(menu);
    }

    public Menu update(Menu menu){
        Menu menuForUpdate = menuRepository.findById(menu.getId()).get();
        menuForUpdate.setId(menu.getId());
        menuForUpdate.setName(menu.getName());
        menuForUpdate.setUrl(menu.getUrl());
        return menuRepository.save(menuForUpdate);
    }

    public void delete(Long nodeId) {
        menuRepository.deleteById(nodeId);
    }

}

I tried similar issue solutions again and again but failed to solve.

entityGraph, Eager Lazy, config

Could not write JSON: failed to lazily initialize a collection of role:

https://www.netsurfingzone.com/hibernate/failed-to-lazily-initialize-a-collection-of-role-could-not-initialize-proxy-no-session/

https://github.com/FasterXML/jackson-core/issues/469


Solution

  • I just removed @Data annotation, instead of it I wrote @Getter @Setter @ToString @EqualsAndHashCode, added @OneToMany(mappedBy = "parent",fetch = FetchType.EAGER)and worked !