'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?
Solution 1:[1]
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.
Solution 2:[2]
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).
Solution 3:[3]
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":{
//...
}
},
// ...
]
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | |
Solution 3 | Leroy Dunn |