Harshal Patil
Harshal Patil

Reputation: 357

Spring boot JPA error : Cannot handle managed/back reference 'defaultReference': no back reference property found from type

I have below 3 domain model Objects where appuser have the rank and training status as below. Get call is working fine where it returns JSON object but while adding Model object in JPA getting error.

Cannot handle managed/back reference 'defaultReference': no back reference property found from type [simple type, class com.springboot.model.Rank

`

        package com.springboot.model;

    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.FetchType;
    import javax.persistence.GeneratedValue;
    import static javax.persistence.GenerationType.IDENTITY;
    import javax.persistence.Id;
    import javax.persistence.JoinColumn;
    import javax.persistence.ManyToOne;
    import javax.persistence.Table;

    import com.fasterxml.jackson.annotation.JsonBackReference;
    import com.fasterxml.jackson.annotation.JsonIgnore;
    import com.fasterxml.jackson.annotation.JsonManagedReference;

    @Entity
    @Table(name = "app_user", catalog = "testdb")
    public class AppUser implements java.io.Serializable {

        private Integer id;
        private Rank rank;
        private Trainingstatus trainingstatus;
        private String name;
        private int age;
        private double salary;

        public AppUser() {
        }

        public AppUser(Rank rank, Trainingstatus trainingstatus, String name, int age, double salary) {
            this.rank = rank;
            this.trainingstatus = trainingstatus;
            this.name = name;
            this.age = age;
            this.salary = salary;
        }

        @Id
        @GeneratedValue(strategy = IDENTITY)

        @Column(name = "id", unique = true, nullable = false)
        public Integer getId() {
            return this.id;
        }

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

        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "rankId", nullable = false)
        @JsonManagedReference
        public Rank getRank() {
            return this.rank;
        }

        public void setRank(Rank rank) {
            this.rank = rank;
        }

        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "trainingStatusId", nullable = false)
        @JsonManagedReference

        public Trainingstatus getTrainingstatus() {
            return this.trainingstatus;
        }

        public void setTrainingstatus(Trainingstatus trainingstatus) {
            this.trainingstatus = trainingstatus;
        }

        @Column(name = "name", nullable = false, length = 30)
        public String getName() {
            return this.name;
        }

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

        @Column(name = "age", nullable = false)
        public int getAge() {
            return this.age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        @Column(name = "salary", nullable = false, precision = 22, scale = 0)
        public double getSalary() {
            return this.salary;
        }

        public void setSalary(double salary) {
            this.salary = salary;
        }

    }

    package com.springboot.model;
// Generated 28 Apr, 2018 5:35:48 PM by Hibernate Tools 4.3.5.Final

import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonManagedReference;

/**
 * Trainingstatus generated by hbm2java
 */
@Entity
@Table(name = "trainingstatus", catalog = "testdb")
public class Trainingstatus implements java.io.Serializable {

    private Integer trainingStatusId;
    private String trainingStatus;
    private String lastUpdatedBy;
    private Date lastUpdatedDate;
    private Set<AppUser> appUsers = new HashSet<AppUser>(0);

    public Trainingstatus() {
    }

    public Trainingstatus(String trainingStatus, String lastUpdatedBy, Date lastUpdatedDate) {
        this.trainingStatus = trainingStatus;
        this.lastUpdatedBy = lastUpdatedBy;
        this.lastUpdatedDate = lastUpdatedDate;
    }

    public Trainingstatus(String trainingStatus, String lastUpdatedBy, Date lastUpdatedDate, Set<AppUser> appUsers) {
        this.trainingStatus = trainingStatus;
        this.lastUpdatedBy = lastUpdatedBy;
        this.lastUpdatedDate = lastUpdatedDate;
        this.appUsers = appUsers;
    }

    @Id
    @GeneratedValue(strategy = IDENTITY)

    @Column(name = "trainingStatusId", unique = true, nullable = false)
    public Integer getTrainingStatusId() {
        return this.trainingStatusId;
    }

    public void setTrainingStatusId(Integer trainingStatusId) {
        this.trainingStatusId = trainingStatusId;
    }

    @Column(name = "trainingStatus", nullable = false, length = 45)
    public String getTrainingStatus() {
        return this.trainingStatus;
    }

    public void setTrainingStatus(String trainingStatus) {
        this.trainingStatus = trainingStatus;
    }

    @Column(name = "lastUpdatedBy", nullable = false, length = 45)
    public String getLastUpdatedBy() {
        return this.lastUpdatedBy;
    }

    public void setLastUpdatedBy(String lastUpdatedBy) {
        this.lastUpdatedBy = lastUpdatedBy;
    }

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "lastUpdatedDate", nullable = false, length = 19)
    public Date getLastUpdatedDate() {
        return this.lastUpdatedDate;
    }

    public void setLastUpdatedDate(Date lastUpdatedDate) {
        this.lastUpdatedDate = lastUpdatedDate;
    }

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "trainingstatus")
    @JsonBackReference
    // @JsonIgnore
    public Set<AppUser> getAppUsers() {
        return this.appUsers;
    }

    public void setAppUsers(Set<AppUser> appUsers) {
        this.appUsers = appUsers;
    }

}

package com.springboot.model;
// Generated 28 Apr, 2018 5:35:48 PM by Hibernate Tools 4.3.5.Final

import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import com.fasterxml.jackson.annotation.JsonBackReference;

@Entity
@Table(name = "rank", catalog = "testdb")
public class Rank implements java.io.Serializable {

    private Integer rankId;
    private String rank;
    private String lastUpdatedBy;
    private Date lastUpdatedDate;
    private Set<AppUser> appUsers = new HashSet<AppUser>(0);

    public Rank() {
    }

    public Rank(String rank, String lastUpdatedBy, Date lastUpdatedDate) {
        this.rank = rank;
        this.lastUpdatedBy = lastUpdatedBy;
        this.lastUpdatedDate = lastUpdatedDate;
    }

    public Rank(String rank, String lastUpdatedBy, Date lastUpdatedDate, Set<AppUser> appUsers) {
        this.rank = rank;
        this.lastUpdatedBy = lastUpdatedBy;
        this.lastUpdatedDate = lastUpdatedDate;
        this.appUsers = appUsers;
    }

    @Id
    @GeneratedValue(strategy = IDENTITY)

    @Column(name = "rankId", unique = true, nullable = false)
    public Integer getRankId() {
        return this.rankId;
    }

    public void setRankId(Integer rankId) {
        this.rankId = rankId;
    }

    @Column(name = "rank", nullable = false, length = 45)
    public String getRank() {
        return this.rank;
    }

    public void setRank(String rank) {
        this.rank = rank;
    }

    @Column(name = "lastUpdatedBy", nullable = false, length = 45)
    public String getLastUpdatedBy() {
        return this.lastUpdatedBy;
    }

    public void setLastUpdatedBy(String lastUpdatedBy) {
        this.lastUpdatedBy = lastUpdatedBy;
    }

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "lastUpdatedDate", nullable = false, length = 19)
    public Date getLastUpdatedDate() {
        return this.lastUpdatedDate;
    }

    public void setLastUpdatedDate(Date lastUpdatedDate) {
        this.lastUpdatedDate = lastUpdatedDate;
    }

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "rank")
    @JsonBackReference
    // @JsonIgnore
    public Set<AppUser> getAppUsers() {
        return this.appUsers;
    }

    public void setAppUsers(Set<AppUser> appUsers) {
        this.appUsers = appUsers;
    }

}

From my rest application I am adding AppUser parent object as below:

@RequestMapping(value = "/user/", method = RequestMethod.POST)
    public ResponseEntity<?> createUser(@RequestBody AppUser user, UriComponentsBuilder ucBuilder) {
        logger.info("Creating AppUser : {}", user);

        if (userService.isUserExist(user)) {
            logger.error("Unable to create. A AppUser with name {} already exist", user.getName());
            return new ResponseEntity(new CustomErrorType("Unable to create. A AppUser with name " + 
            user.getName() + " already exist."),HttpStatus.CONFLICT);
        }
        userService.saveUser(user);

        HttpHeaders headers = new HttpHeaders();
        headers.setLocation(ucBuilder.path("/api/user/{id}").buildAndExpand(user.getId()).toUri());
        return new ResponseEntity<String>(headers, HttpStatus.CREATED);
    }

THis is is json object I am which is built from the UI create user operation.

{
    "age": 24,
    "name": "Amit",
    "salary": 15000,
    "rank": {
        "rank": "Clark"
    },
    "trainingstatus": {
        "trainingStatus": "Completed"
    }
}

But this is giving error in persisting object using JPA.

.MappingJackson2HttpMessageConverter : Failed to evaluate Jackson deserialization for type [simple type, class com.springboot.model.AppUser]

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot handle managed/back reference 'defaultReference': no back reference property found from type [simple type, class com.springboot.model.Rank]
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67) ~[jackson-databind-2.9.3.jar:2.9.3]
    at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1451) ~[jackson-databind-2.9.3.jar:2.9.3]
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase._resolveManagedReferenceProperty(BeanDeserializerBase.java:766) ~[jackson-databind-2.9.3.jar:2.9.3]
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.resolve(BeanDeserializerBase.java:474) ~[jackson-databind-2.9.3.jar:2.9.3]
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:293) ~[jackson-databind-2.9.3.jar:2.9.3]
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244) ~[jackson-databind-2.9.3.jar:2.9.3]
    at com.fasterxml.jackson.databind.deser.DeserializerCache.hasValueDeserializerFor(DeserializerCache.java:191) ~[jackson-databind-2.9.3.jar:2.9.3]
    at com.fasterxml.jackson.databind.DeserializationContext.hasValueDeserializerFor(DeserializationContext.java:422) ~[jackson-databind-2.9.3.jar:2.9.3]
    at com.fasterxml.jackson.databind.ObjectMapper.canDeserialize(ObjectMapper.java:2863) ~[jackson-databind-2.9.3.jar:2.9.3]

Upvotes: 0

Views: 5296

Answers (1)

Harshal Patil
Harshal Patil

Reputation: 357

I have solved this problem by removing annotation @JsonManagedReference from my parent class AppUser. Just kept @JsonBackReference in child classes and added JsonIdentityInfo annotation for all the 3 classes after that my rest getUser and create user operation working perfectly and its returning valid JSON for both of these operation.

 @JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")

Upvotes: 6

Related Questions