简体   繁体   中英

How to get relationship data with spring boot rest api?

I'm building a REST API with Spring Boot to retrieve boat information. I'm using Spring Data Rest and Spring Data JPA. When I get the data from the API, I don't know why the relationship data are not with the others informations.

Do I have to configure something in Spring to get the relationship with my data?

Here is my file.

Boat entity:

@Entity
@Table(name="boat")
@Data
public class Boat {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Column(name = "name")
    private String name;

    @Column(name = "description")
    private String description;

    @ManyToOne(cascade = CascadeType.PERSIST)
    @JoinColumn(name = "type_id", nullable = false)
    @JsonBackReference
    private BoatType type;

}

Boat type entity:

@Entity
@Table(name = "boat_type")
@Data
public class BoatType {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Column(name = "name")
    private String name;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "type")
    @JsonManagedReference
    private Set<Boat> boats;

}

Boat repository:

@CrossOrigin("http://localhost:4200")
public interface BoatRepository extends JpaRepository<Boat, Long> {
}

JSON response:

{
"_embedded": {
  "boats": [
    {
      "id": 1,
      "name": "Boat 1",
      "description": "A brief description of the boat 1",
      "_links": {
        "self": {
          "href": "http://localhost:8080/api/boats/1"
        },
        "boat": {
          "href": "http://localhost:8080/api/boats/1"
        },
        "type": {
          "href": "http://localhost:8080/api/boats/1/type"
        }
      }
    },
    ...
  ]

}

Result expected (with the type object too) :

{
"_embedded": {
  "boats": [
    {
      "id": 1,
      "name": "Boat 1",
      "description": "A brief description of the boat 1",
      "type": {
          "id": 1,
          "name": "Motorboats"
      },
      "_links": {
        "self": {
          "href": "http://localhost:8080/api/boats/1"
        },
        "boat": {
          "href": "http://localhost:8080/api/boats/1"
        },
        "type": {
          "href": "http://localhost:8080/api/boats/1/type"
        }
      }
    },
    ...
  ]

}

I think that the problem is related with Spring Data Rest because when i do the same app with my own controller and repository, i get the data I need.

Is there a way to "configure" spring data rest?

It seems like you've used @JsonBackReference and @JsonManagedReference the other way around, than you needed. You've put @JsonBackReference on the type field in your Boat class, whereas its documentation states:

[...] Linkage is handled such that the property annotated with this annotation is not serialized

So it seems like you need to put @JsonManagedReference annotation on it instead (see: JsonManagedReference documentation ) and put @JsonBackReference on boats in your BoatType class.

Alternatively, you could consider using @JsonIdentityInfo instead. See: the documentation .

Also, this article might be helpful. It explains various ways to handle bidirectional relationships using Jackson.

Change @JsonManagedReference and @JsonBackReference to @JsonIgnoreProperties .

In your case:

@OneToMany(cascade = CascadeType.ALL, mappedBy = "type")
@JsonIgnoreProperties(value = {"type"})
private Set<Boat> boats;

and

@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name = "type_id", nullable = false)
@JsonIgnoreProperties(value = {"boats"})
private BoatType type;

You will avoid the infinity loop in json result and get all reference objects (relationships).

The Boat response includes a uri to your BoatType resource by default since you defined a rest repository for your BoatType resource ( docs )

To override this behaviour, define a projection to expose the boat type data ( docs ):

@Projection(name = "boatDetail", types = { Boat.class }) 
interface BoatDetail { 

  // ... all other fields you want included in the response

  BoatType getType(); 

}

Then include the projection as a query parameter:

{apiUrl}boats/1?projection=boatDetail

The response should now include the boat type data:

{
    "id": 1,
    "name": "Boat 1",
    "description": "A brief description of the boat 1",
    "type": {
        "id": 1,
        "name": "Motorboats"
    },
    "_links": {
        // ...
    }
}

To automatically include the projection on a collection of resources, use an excerpt ( docs ):

@RepositoryRestResource(excerptProjection = BoatDetail.class)
interface BoatRepository extends JpaRepository<Boat, Long> {}

Then the http response:

{
    "_embedded":{
        "boats":[
            {
                "id":1,
                "name":"Boat 1",
                "description":"A brief description of the boat 1",
                "type":{
                    "id":1,
                    "name":"Motorboats"
                },
                "_links":{
                    //...
                }
            },
            // ...
        ]
    }
}

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