简体   繁体   中英

Spring Data Rest: Detected multiple association links with same relation type

Regarding this question, I checked out Spring Data Rest Ambiguous Association Exception but couldn't get it to work for me.

As you can see in my code below, I added @RestResource annotation with rel equal to some other value.

Similar to the question above, POST requests work, but GET requests throw exception about multiple association links with the same relation type:

"Could not write JSON: Detected multiple association links with same relation type! Disambiguate association @org.springframework.data.rest.core.annotation.RestResource(rel=createdBy, exported=true, path=, description=@org.springframework.data.rest.core.annotation.Description(value=)) @javax.persistence.ManyToOne(optional=true, targetEntity=void, cascade=[], fetch=EAGER) @javax.persistence.JoinColumn(referencedColumnName=ASSIGNABLE_ID, nullable=false, unique=false, name=CREATED_BY, updatable=true, columnDefinition=, foreignKey=@javax.persistence.ForeignKey(name=, value=CONSTRAINT, foreignKeyDefinition=), table=, insertable=true) private com.ag.persistence.domain.PersonEntity com.ag.persistence.domain.TeamEntity.createdBy using @RestResource! (through reference chain: org.springframework.hateoas.PagedResources[\\"_embedded\\"]->java.util.UnmodifiableMap[\\"persons\\"]->java.util.ArrayList[0]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Detected multiple associa tion links with same relation type! Disambiguate association @org.springframework.data.rest.core.annotation.RestResource(rel=createdBy, exported=true, path=, description=@org.springframework.data.rest.core.annotation.Description(value=)) @javax.persistence.ManyToOne(optional=true, targetEntity=void, cascade=[], fetch=EAGER) @javax.persistence.JoinColumn(referencedColumnName=ASSIGNABLE_ID, nullable=false, unique=false, name=CREATED_BY, updatable=true, columnDefinition=, foreignKey=@javax.persistence.ForeignKey(name=, value=CONSTRAINT, foreignKeyDefinition=), table=, insertable=true) private com.ag.persistence.domain.PersonEntity com.ag.persistence.domain.TeamEntity.createdBy using @RestResource! (through reference chain: org.springframework.hateoas.PagedResources[\\"_embedded\\"]->java.util.UnmodifiableMap[\\"persons\\"]->java.util.ArrayList[0])"

The error seems to be happening in this class:

@Entity
@Table(name = "team")
public class TeamEntity extends AssignableEntity {
    private String name;
    private LocalDateTime createdDate;
    private LocalDateTime modifiedDate;
    private Collection<MembershipEntity> memberships;
    private PersonEntity createdBy;
    private PersonEntity modifiedBy;

    @Basic
    @Column(name = "NAME")
    public String getName() {
        return name;
    }

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

    @Basic
    @Column(name = "CREATED_DATE")
    public LocalDateTime getCreatedDate() {
        return createdDate;
    }

    public void setCreatedDate(LocalDateTime createdDate) {
        this.createdDate = createdDate;
    }

    @Basic
    @Column(name = "MODIFIED_DATE")
    public LocalDateTime getModifiedDate() {
        return modifiedDate;
    }

    public void setModifiedDate(LocalDateTime modifiedDate) {
        this.modifiedDate = modifiedDate;
    }

    @OneToMany(mappedBy = "team")
    public Collection<MembershipEntity> getMemberships() {
        return memberships;
    }

    public void setMemberships(Collection<MembershipEntity> memberships) {
        this.memberships = memberships;
    }

    @RestResource(rel = "team_createdBy")
    @ManyToOne
    @JoinColumn(name = "CREATED_BY", referencedColumnName = "ASSIGNABLE_ID", nullable = false)
    public PersonEntity getCreatedBy() {
        return createdBy;
    }

    public void setCreatedBy(PersonEntity createdBy) {
        this.createdBy = createdBy;
    }

    @RestResource(rel = "team_modifiedBy")
    @ManyToOne
    @JoinColumn(name = "MODIFIED_BY", referencedColumnName = "ASSIGNABLE_ID", nullable = false)
    public PersonEntity getModifiedBy() {
        return modifiedBy;
    }

    public void setModifiedBy(PersonEntity modifiedBy) {
        this.modifiedBy = modifiedBy;
    }
}

Ironically, I am not accessing this specific resource. I also have other resources with createdBy and modifiedBy -- is it the one causing this issue?

I suspect that you might have exported = false on your PersonEntity object. Because of this, any references in PersonEntity will be added to the _links section of your TeamEntity . Because both PersonEntity objects have a createdBy reference, they are colliding with the TeamEntity.createdBy reference.

To understand what is happening this example might help:

class Answer {
   Question q; //JPA ManyToOne back-reference
}

class Question {
   List<Answer> as; // JPA OneToMany reference
}

class UserAnswer {
   Answer a;
   Question q;
}

In my case, because an Answer can only exist within a Question , we have the following on our AnswerResource , to prevent Answers from being exported:

@RestResource(exported = false)

This causes Answer objects to be serialized within the parent object, rather than as a reference in the _links section, and this ends up being the cause of the problem....

When UserAnswer is serialized, it renders something like this:

{
  "answer" : {
    "creationDate" : "2014-09-18T17:28:31.000+0000",
    "modificationDate" : "2014-09-18T17:28:31.000+0000",
    "answerText" : "Vendas",
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:9090/data/userAnswers/15"
    },
    "question" : {
      "href" : "http://localhost:9090/data/userAnswers/15/question"
    }
  }
}

Note that "_links.question" above is from the Answer !

So if you add a Question to UserAnswer , you will see the error you are asking about, because the UserAnswer itself also wants to include a _link reference to a Question .

In your case, I think your PersonEntity and your TeamEntity both have createdBy references.

I'm not 100% sure what the solution is yet, I don't know if you can specify hierarchical rel names.

Short answer: Add Spring Data repositories for ALL (or at least more of) your entities. (In this case, it sounds like you need to make a PersonRepository).

Long answer:

Spring Data Rest uses _links to avoid sending back the entire JSON tree, but it can only make _links to mapped entities that have Repositories.

If there isn't a repository for an entity, Spring can't use a link and will instead just put the whole JSON object in the response.

I THINK what's happening with this exception is that a lower, second level relationship is being put into a _link, and more than one of these have the same name.

I'm not 100% sure I understand it all, but I had the same exception when only had repositories for a few entities, and when I made a Repository for every single entity the problem vanished.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM