0

I have two object model of Muscle and Exercise. For one Muscle there will be many exercise and that is how they are mapped in the project. My Muscle object has a name property, How do I fetch it when I fetch the Exercise object? I have can somehow fetch for the first column in the database that is for the first Exercise does contain the muscle object with the name property but from the second it doesn't have any name property.

This is my Muscle Class

package com.fazla.exercise.model;

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

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;

import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;


@Entity
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="id")
public class Muscle {

    @Id
//  @Column(unique = true, nullable = false)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column
    private String name;

//  @JoinColumn(name="muscle")
//  @Column(nullable = true)
//  cascade is used so that for any changes in parent will change the child too 
    @OneToMany(mappedBy="muscle", orphanRemoval= false, fetch=FetchType.EAGER)

    private List<Exercise> exercises = new ArrayList<>();

    public Muscle() {

    }

    public Muscle(String name, List<Exercise> exercises) {
        super();
        this.name = name;
        this.exercises = exercises;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Exercise> getExercises() {
        return exercises;
    }

    public void setExercises(List<Exercise> exercises) {
        this.exercises = exercises;
    }

//  @Override
//  public String toString() {
//      return "Muscle [id=" + id + ", name=" + name + ", exercises=" + exercises + "]";
//  }



}

This is my Exercise Class

package com.fazla.exercise.model;

import javax.persistence.CascadeType;
import javax.persistence.Column;
//import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToOne;

import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;

@Entity
//@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="id")
public class Exercise {
    @Id
    @Column(unique = true, nullable = false)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column
    private String name;

    @Column
    private String description;


    //As there will be many exercise under one muscle that is why manytoone
    //object references an unsaved transient instance - save the transient instance before flushing 
    //that is why need to add the cascading dependencies
//  (cascade = CascadeType.ALL)
//  @JoinColumn(name="muscle_id")
//  @JsonIgnore
//  @JoinTable(name="muscle")
    @ManyToOne
    @JoinColumn(name="muscle_id")

    private Muscle muscle;

    public Exercise() {

    }

    public Exercise(String name, String description, Muscle muscle) {
        super();
        this.name = name;
        this.description = description;
        this.muscle = muscle;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Muscle getMuscle() {
        return muscle;
    }

    public void setMuscle(Muscle muscle) {
        this.muscle = muscle;
    }

//  @Override
//  public String toString() {
//      return "Exercise [id=" + id + ", name=" + name + ", description=" + description + ", muscle=" + muscle + "]";
//  }



}

This is how I am getting the JSON response from the API

[
    {
        "id": 1,
        "name": "Dumbbell Curl",
        "description": "Take a weight that let's you maintain the form",
        "muscle": {
            "id": 1,
            "name": "Biceps",
            "exercises": [
                {
                    "id": 1,
                    "name": "Dumbbell Curl",
                    "description": "Take a weight that let's you maintain the form",
                    "muscle": 1
                },
                {
                    "id": 2,
                    "name": "Barbell Curl",
                    "description": "Take a weight that let's you maintain the form",
                    "muscle": 1
                }
            ]
        }
    },
    {
        "id": 2,
        "name": "Barbell Curl",
        "description": "Take a weight that let's you maintain the form",
        "muscle": 1
    }
]

I want it to response back with the whole muscle object in the 2nd Exercise object rather than only "muscle": 1

Reactive_learner
  • 417
  • 1
  • 4
  • 21

1 Answers1

0

This behavior is caused by @JsonIdentityInfo

This question contains more insight. @JsonIdentityInfo is used to solve the circular reference problem. Without it you would get an infinite recursion, as every muscle will contain an exercise which will contain back a muscle and so on, you get the point. You can also have a look over other approaches for solving the circular reference problem.

Brad
  • 958
  • 8
  • 21
  • I am not having the infinite recursion problem, I did try the solution already by adding the @JsonIdentityInfo annotation but I still don't get the name property of the muscle object – Reactive_learner Oct 11 '18 at 08:13
  • That is what I am saying, @JsonIdentityInfo, will replace the object with its ID when an infinite recursion is about to happen, remove the annotation and check what happens. – Brad Oct 11 '18 at 08:34
  • By removing @JsonIdentityInfo I get the "ERROR 13798 java.lang.StackOverflowError: null" error – Reactive_learner Oct 11 '18 at 09:03
  • I do have the toString methods for the infinite recursion but still have the "ERROR 13798 java.lang.StackOverflowError: null" error – Reactive_learner Oct 11 '18 at 09:07
  • That is expected, as @JsonIdentityInfo is one of the solutions for this behavior. Take a look over [this](https://stackoverflow.com/questions/35225053/tostring-function-for-jpa-one-to-many-relations-raises-stackoverflowerror) and [this](https://stackoverflow.com/questions/3593893/why-im-getting-stackoverflowerror) – Brad Oct 11 '18 at 11:02