2014-06-26 7 views
11

Sto provando a fare una semplice app di Spring. È necessario esporre gli endpoint REST e salvarlo in un database relazionale.Spring Data REST - Rilevato più collegamenti di associazione con lo stesso tipo di relazione

Ho preso il tuo progetto di esempio, http://spring.io/guides/gs/accessing-data-rest/. Sono in grado di eseguire tutte le operazioni (POST, PATCH, PUT, GET) come menzionato nella guida.

Tuttavia, ho provato a creare relazioni aggiuntive alla classe Persona Entity e le cose iniziano a cadere a pezzi.

@Entity 
public class Person { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 

    private String firstName; 
    private String lastName; 

    @OneToOne(cascade = {CascadeType.ALL}) 
    private PersonDetails personDetails; 

    @OneToOne(cascade = {CascadeType.ALL}) 
    private PersonChildren personChildren; 

    ///Getter and setters for everything except id. 
} 


@Entity 
public class PersonChildren { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 

    private String childFirstName; 
    private String childLastName; 

    @OneToOne(mappedBy="personChildren", optional=false) 
    private Person person; 

///Getter and setters for everything except id. 
} 


@Entity 
public class PersonDetails { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 

    private String email; 
    private String phoneNumber; 

    @OneToOne(mappedBy="personDetails",optional=false) 
    private Person person; 

///Getter and setters for everything except id. 
} 


@RepositoryRestResource(collectionResourceRel = "people", path = "people") 
public interface PersonRepository extends PagingAndSortingRepository<Person, Long> { 

    List<Person> findByLastName(@Param("name") String name); 

} 

build.gradle

buildscript { 
    repositories { 
     maven { url "http://repo.spring.io/libs-release" } 
     mavenLocal() 
     mavenCentral() 
    } 
    dependencies { 
     classpath("org.springframework.boot:spring-boot-gradle-plugin:1.1.1.RELEASE") 
    } 
} 

apply plugin: 'java' 
apply plugin: 'eclipse' 
apply plugin: 'idea' 
apply plugin: 'spring-boot' 

jar { 
    baseName = 'gs-accessing-data-rest' 
    version = '0.1.0' 
} 

repositories { 
    mavenLocal() 
    mavenCentral() 
    maven { url "http://repo.spring.io/libs-release" } 
} 

dependencies { 
    compile("org.springframework.boot:spring-boot-starter-web") 
    compile("org.springframework.boot:spring-boot-starter-data-jpa") 
    compile("com.h2database:h2") 
    compile("org.springframework.data:spring-data-rest-webmvc") 
} 

task wrapper(type: Wrapper) { 
    gradleVersion = '1.11' 
} 

chiamata:

$ curl -i -X POST -H "Content-Type:application/json" -d '{ "firstName":"John", "lastName": "Doe", "personDetails": { "email": "[email protected]", "phoneNumber": "001-002-0003" }, "personChildren": {"childFirstName": "Mary", "childLastName": "Martin" } }' <code> http://localhost:8080/people </code> 

Response: 
HTTP/1.1 201 Created 
Server: Apache-Coyote/1.1 
<code> 
Location: http://localhost:8080/people/1 
</code> 
Content-Length: 0 
Date: Thu, 26 Jun 2014 05:42:45 GMT 

$ curl http://localhost:8080/people 

{ 
    "timestamp" : 1403761371011, 
    "status" : 500, 
    "error" : "Internal Server Error", 
    "exception" : "org.springframework.http.converter.HttpMessageNotWritableException", 
    "message" : "Could not write JSON: Detected multiple association links with same relation type! Disambiguate association @javax.persistence.OneToOne(optional=false, targetEntity=void, cascade=[], fetch=EAGER, orphanRemoval=false, mappedBy=personChildren) private com.ds.dao.rest.Person com.ds.dao.rest.PersonChildren.person using @RestResource! (through reference chain: org.springframework.hateoas.PagedResources[\"_embedded\"]->java.util.UnmodifiableMap[\"people\"]->java.util.ArrayList[0]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Detected multiple association links with same relation type! Disambiguate association @javax.persistence.OneToOne(optional=false, targetEntity=void, cascade=[], fetch=EAGER, orphanRemoval=false, mappedBy=personChildren) private com.ds.dao.rest.Person com.ds.dao.rest.PersonChildren.person using @RestResource! (through reference chain: org.springframework.hateoas.PagedResources[\"_embedded\"]->java.util.UnmodifiableMap[\"people\"]->java.util.ArrayList[0])", 
    "path" : "/people" 
} 

Domanda 1: Sono in grado di fare un post ma il mio GET continua a fallire.

Domanda 2: Perché viene visualizzato questo errore quando Post ha esito positivo?

Domanda 3: Esiste una buona guida di primavera che aiuterà con REST e JPA? Se stai ancora lavorando su questi moduli, quali esempi posso guardare?

Domanda 4: È @RepositoryRestResource il problema? Non è riconosciuto a meno che non aggiungo spring-data-rest-webmvc come dipendenza.

Questo è simile alla domanda senza risposta Spring Data Rest Ambiguous Association Exception

Aggiornamento:

Si sta lavorando con un solo OneToOne mappatura Person classe. Se aggiungo entrambe le classi, personDetails e personChildren in Person con la mappatura OneToOne. Non funziona.

Ho anche provato ad aggiungere @JointColumn(name="person_details") e @JointColumn(name="person_children") a personDetails e personChildren. Non ha funzionato neanche.

risposta

14

Il motivo è piuttosto semplice: i nomi delle relazioni per le entità associate derivano dai nomi di proprietà della classe contenitore. Pertanto, sia PersonDetails sia PersonChildren desiderano creare un collegamento in uscita a personperson. Se lo rendessimo, sarebbe simile a questo

{ _links : { 
    person : { href : … }, <- the one from PersonDetails 
    person : { href : … } <- the one from PersonChildren 
} 

Questo naturalmente non è valido. Inoltre, allineando i due collegamenti in un array non permettono di distinguere tra i due collegamenti più (che si è venuta da PersonDetails e quale è venuta da PersonChildren

Quindi ci sono alcune opzioni qui:.

  1. citarne manualmente i rapporti di questi tipi. È possibile annotare i Person proprietà con @RestResource e configurare l'attributo rel dell'annotazione a qualcosa di diverso rispetto person.
  2. Si desidera che nessuno dei due venga esportato allo. È possibile utilizzare la stessa annotazione per impedire il rendering del collegamento. Impostare semplicemente il flag exported in @RestResource in false e il collegamento non verrà reso. Questo potrebbe essere utile se il puntatore ad es. da PersonDetails è pertinente solo all'interno del codice, ma in realtà non in una rappresentazione JSON.
+0

Oliver, questo ha funzionato come un fascino. Ho usato l'opzione 1. Grazie per tutto il tuo aiuto. – user827096

+3

Ho provato entrambe le opzioni, nessuno di loro sta funzionando da me. –