devYuraKim / spring

udemy EazyBytes
0 stars 0 forks source link

example41 - Handling Bidirectional Relationships in Jackson to Prevent Infinite Recursion #2

Open devYuraKim opened 1 month ago

devYuraKim commented 1 month ago

I wanted to check for myself what kind of information gets stored in HttpSession, so I added in SessionController.java.

@RestController
@RequestMapping("/session")
public class SessionController {

    private final HttpSession session;

    @Autowired
    public SessionController(HttpSession session) {
        this.session = session;
    }

    @RequestMapping(method = RequestMethod.GET)
    public Map<String, Object> getSessionAttributes() {
        Map<String, Object> attributes = new HashMap<>();
        Enumeration<String> attributeNames = session.getAttributeNames();
        while (attributeNames.hasMoreElements()) {
            String name = attributeNames.nextElement();
            attributes.put(name, session.getAttribute(name));
        }
        return attributes;
    }
}

The results were nice and pretty

before

up until session.setAttribute("eazyClass", eazyClass); from AdminController.java was executed. AdminController.java

@RequestMapping("/displayStudents")
    public String displayStudents(Model model, @RequestParam int classId, HttpSession session, @RequestParam(required=false) String error){
        Optional<EazyClass> eazyClassOptional = eazyClassRepository.findById(classId);
        EazyClass eazyClass = eazyClassOptional.get();
        model.addAttribute("eazyClass", eazyClass);
        session.setAttribute("eazyClass", eazyClass);
        model.addAttribute("person", new Person());

        String errorMessage = null;
        if(error != null) {
            errorMessage = "Invalid Email entered!!";
            model.addAttribute("errorMessage", errorMessage);
        }
        return "students.html";
    }

It seemed like the output kept repeating itself until it couldn't anymore and then just crashed.

trouble
devYuraKim commented 1 month ago

Then ChatGTP offered some great solution which worked like magic!


The @JsonManagedReference and @JsonBackReference annotations in Jackson are used to handle bidirectional relationships in JSON serialization, and they help to prevent infinite recursion and infinite loops that can occur with such relationships. Here's a detailed explanation of why these annotations fixed the problem:

The Problem with Bidirectional Relationships When you have a bidirectional relationship between entities (e.g., EazyClass and Person), serializing these entities to JSON can create a loop:

If you try to serialize this bidirectional relationship, Jackson will keep following the references back and forth between EazyClass and Person, leading to infinite recursion. This can result in errors like StackOverflowError, or excessively large JSON outputs that can cause performance issues or crashes.


Person.java

@ManyToOne(fetch = FetchType.LAZY, optional = true)
@JoinColumn(name = "class_id", referencedColumnName = "classId", nullable = true)
@JsonBackReference
private EazyClass eazyClass;

EazyClass.java

@OneToMany(mappedBy = "eazyClass", cascade = CascadeType.PERSIST,targetEntity = Person.class)
@JsonManagedReference
private Set<Person> persons;
fixed

But I definitely need to learn more about this issue.

devYuraKim commented 1 month ago

[[JPA]쏘아올린 JPA의 순환 참조, @JsonManagedReference에서 볼까, DTO로 볼까] https://velog.io/@power0080/JPA쏘아올린-JPA의-순환-참조-JsonManagedReference에서-볼까-DTO로-볼까

[JPA] 순환참조와 해결 방법 @JsonIgnore, @JsonManagedReference, @JsonBackReference https://m.blog.naver.com/writer0713/221587351970

Jackson – Bidirectional Relationships https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion