Ошибка весенней загрузки JPA: не удается обработать управляемую / обратную ссылку 'defaultReference': не найдено свойство обратной ссылки из типа - PullRequest
0 голосов
/ 27 апреля 2018

У меня есть ниже 3 модели предметной области. Объекты, где appuser имеют ранг и статус обучения, как показано ниже. Вызов Get работает нормально, когда он возвращает объект JSON, но при добавлении объекта Model в JPA получается ошибка.

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

}

Из моего остального приложения я добавляю родительский объект AppUser, как показано ниже:

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

Это объект json, который я создаю из пользовательского интерфейса создания пользовательской операции.

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

Но это приводит к ошибке при сохранении объекта с использованием 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]

1 Ответ

0 голосов
/ 29 апреля 2018

Я решил эту проблему, удалив аннотацию @JsonManagedReference из моего родительского класса AppUser. Просто сохранил @JsonBackReference в дочерних классах и добавил Аннотация JsonIdentityInfo для всех 3 классов, после этого мой оставшийся getUser и пользовательская операция создания отлично работают и возвращают действительный JSON для обеих этих операций.

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