first question here so be gentle :)
I've got a JPA project which I want to expose as REST. I've done this so far:
My entity:
@Entity
public class SignUpSheet {
@Id
@GeneratedValue
private Long id;
@Column
private String name;
@Column
private String description;
@Column
@Temporal(TemporalType.TIMESTAMP)
private Date dateTime;
@ManyToOne
private User parent;
@OneToMany
private List<Volunteer> volunteers;
//getter and setters
}
All well and good, I call added spring-boot-starter-data-rest to my pom and now I get a service. Here's the JSON I get back.
http://localhost:8080/api-0.1.0/signUpSheets/1
{
"name": "Auction",
"description": "My First Sign Up Sheet",
"dateTime": "2015-04-22T03:47:12.000+0000",
"volunteers": [
{
"role": "Bringing stuff",
"comments": "I have comments!"
}
],
"endpoint": "/signUpSheets",
"_links": {
"self": {
"href": "http://localhost:8080/api-0.1.0/signUpSheets/1"
},
"parent": {
"href": "http://localhost:8080/api-0.1.0/signUpSheets/1/parent"
},
"user": {
"href": "http://localhost:8080/api-0.1.0/signUpSheets/1/user"
}
}
}
Super! Pretty much what I expected. Now I call my service using Spring's RestTemplate and here's where I'm stuck. When it marshals back into the SignUpSheet object it pulls in most of the object, but the ID field is null (which makes sense, because there is no ID field in the Json, just a self reference) and all the OneToMany and ManyToOne object are null (I assume for the same reason).
My question is: How do I tell either Spring Hateoas to add the ID to the json or tell Jackson how to marshal it the ID into the ID field? Furthermore how do I get the links? Should I not be marshaling back into the JPA entity and instead create another POJO for SignUpSheet (something I'd like to avoid for duplication purposes but could be talked into if it's necessary/desirable for some reason I'm missing). I have the Jackson2HalModule added to my ObjectMapper but that seems to make no difference whether it's there or not.
@Bean
@Primary
public ObjectMapper objectMapper() {
ObjectMapper o = new ObjectMapper();
o.registerModule(new Jackson2HalModule());
return o;
}
Thanks in advance for the help!
=======================================================
Solution:
First step, read the manual :)
So I found out I need to extend ResourceSupport on my newly created DTOs. Done and done. But I was getting no links back! It seems like I needed to add the Jackson2HalModule to the object mapper on the RestTemplate like this:
ObjectMapper o = new ObjectMapper();
o.registerModule(new Jackson2HalModule());
MappingJackson2HttpMessageConverter c = new MappingJackson2HttpMessageConverter();
c.setObjectMapper(o);
restTemplate.getMessageConverters().add(0, c);
So I figure I'll extend off of RestTemplate and @Component it and I should be good for any HATEOAS resource.
I don't think you should be trying to deserialise the JSON back into your JPA entity. The JPA entity is very closely tied to your application's database and should be considered an implementation detail of the server. Instead, I'd recommend mapping to a type that's specifically modelled on the REST API, not on the structure of your database and your usage of JPA.
You're using Spring Data REST which strongly embraces hypermedia. That means that clients should use URIs to identify resources and links to navigate between them. For example, on the client side, a sign up sheet already has an ID; it's the href
of the self
link in the response. Therefore, there's no need to expose the ID from your JPA entity. Indeed, doing so would expose an implementation detail of your application that clients need not know about.
Rather than trying to populate all of the properties in the response, Spring Data REST provides links instead. For example, to access a sign up sheet's parent, you should extract the href
of the parent
link from the response and perform a GET
request on the URI.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With