Creating relationships between objects using RestTemplate in Spring Rest Data (HATEOAS)

I am trying to manipulate objects (which are JPA objects) in a Spring Data Restore API through a RestTemplate.

I have a tree structure in which Genre has parents and children of other genres (this is the itunes genre tree )

Creating an object in the order:

URI selfLink = restTemplate.postForLocation(api+"/genre", genre, Collections.emptyMap()); 

Creating an association with her is not so simple. If I try to establish a parent association as follows:

 headers.setContentType(new MediaType("text", "uri-list")); ... restTemplate.put(selfLink.toString()+"/parent", entity, parentGenreURI ); 

I get an internal server 500 error on the client side, but the actual error is swallowed on the REST API side, and there is nothing in the logs.

If I try to execute PATCH the URI itself with the parent uri as follows:

 headers.setContentType(MediaType.APPLICATION_JSON); ... Map map = ImmutableMap.of("parent", parentGenreLink); restTemplate.exchange(selfLink.toString()+"/parent", HttpMethod.PATCH, entity, String.class, map); 

I get a 400 Bad Request error on the client, and on the server I get

org.springframework.http.converter.HttpMessageNotReadableException: Failed to read an object of type class Genre from the request !; org.springframework.http.converter.HttpMessageNotReadableException nested exception: Failed to read the payload !; nested exception com.fasterxml.jackson.databind.JsonMappingException: no content to display due to end of input

which makes me think that this is the right way to do it, but I'm just doing it wrong.

Can anyone give some recommendations on this? Every example I saw just uses curl, which doesn’t help me much :)

Somewhat similarly answered questions from SO, but most of them either point to documentation that no longer exists, or have such simple objects that all content is dumped onto the map.

+4
source share
2 answers

Looking at the small amount of code that you posted and the error you received, I think you are calling your service wrong.

As an example, I take the second call, but since I think you are making the same error in both calls, the solution to the first error should be similar.

If we look at the documentation for RestTemplate.exchange that you call, we see that it needs the following arguments:

  • Url to call
  • Method of use
  • HttpEntity to send as request
  • Response class
  • URL Values ​​for Substitution

Where I think you're wrong, these are arguments 3 and 5. It seems to me that you are trying to send a JSON payload

 { "parent": "someGenre" } 

But what you are actually doing is telling the pattern to replace any occurrence of the {parent} string (URL placeholder) in the URL with the value parentGenreLink.

What you probably want to do is set the map as a body on HttpEntity and not pass any URL parameters:

 // Create the body Map map = ImmutableMap.of("parent", parentGenreLink); // Create the headers Headers headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); // Create the HTTP Entity HttpEntity<?> entity = new HttpEntity<>(map, headers); // Make the call without any URL parameters restTemplate.exchange(selfLink.toString()+"/parent", HttpMethod.PATCH, entity, String.class); 

Note that for this you need to have a message converter capable of (de) serializing the JSON installed in the template:

 RestTemplate restTemplate = new RestTemplate(); List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>(); messageConverters.add(new MappingJacksonHttpMessageConverter()); restTemplate.setMessageConverters(messageConverters); 
+2
source

Besides what @Raniz suggested, another way to do this is:

 HttpHeaders reqHeaders = new HttpHeaders(); reqHeaders.add(HttpHeaders.CONTENT_TYPE, new MediaType("text", "uri-list").toString()); HttpEntity<String> reqEntity = new HttpEntity<String>(category0link.getHref(), reqHeaders); ResponseEntity<String> string = template.exchange(widget0link.getHref(), HttpMethod.PUT, reqEntity, String.class, ImmutableMap.of()); 
0
source

All Articles