37

I am using spring-data-rest to expose entities as (paged) rest resources. Everything works fine, but when I request data via RestTemplate, I get an useless HATEOAS JSON (which I didn't ask for). The JSON seems to be a PagedResources. I could live with that, but the JSON isn't converted into an object correctly. There is no content inside.

Repository:

@RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends PagingAndSortingRepository<Person, Long>
{
    List<Person> findByLastName(@Param("name") String name);
}

Client:

public List<Person> getPersons()
{
    RestTemplate rt = new RestTemplate();
    System.out.println(rt.getForObject(URL, PagedResources.class).getContent().size());
    System.out.println(rt.getForObject(URL, PagedResources.class).getLinks().size());
    System.out.println(rt.getForObject(URL, PagedResources.class).getMetadata().getTotalElements());
    return new ArrayList<Person>(rt.getForObject(URL, PagedResources.class).getContent()); // <-- empty
}

System.out:

0 // getContent().size()
4 // getLinks().size()
2 // getTotalElements()

curl:

C:\...>curl http://localhost:8080/spring-jsf-rest/rest/people
{
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/spring-jsf-rest/rest/people{?page,size,sort}",
      "templated" : true
    },
    "search" : {
      "href" : "http://localhost:8080/spring-jsf-rest/rest/people/search"
    }
  },
  "_embedded" : {
    "people" : [ {
      "firstName" : "John",
      "lastName" : "Rambo",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/spring-jsf-rest/rest/people/1"
        }
      }
    }, {
      "firstName" : "Chuck",
      "lastName" : "Norris",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/spring-jsf-rest/rest/people/2"
        }
      }
    } ]
  },
  "page" : {
    "size" : 20,
    "totalElements" : 2,
    "totalPages" : 1,
    "number" : 0
  }
}

It seems like _embedded is not mapped correctly to content?!

Oliver Drotbohm
  • 80,157
  • 18
  • 225
  • 211
user3563584
  • 403
  • 1
  • 4
  • 6
  • 7
    Going forward you might wanna rethink the way you're asking questions here. If stuff is useless to you, don't use it. Please don't claim, you didn't ask for things if you're clearly issuing a `GET` request. As usual with computers, you *exactly* get what you ask for. If you don't specify an `Accept` header, you get the default, which is `application/hal+json`. Generally speaking such negative tone, doesn't create incentives to answer. Nonetheless, I took the time. You're most welcome. PS: What is an HATEOAS JSON, btw? – Oliver Drotbohm Apr 24 '14 at 14:32
  • 2
    @Oliver: i admit, my tone is kind of negative. but those little obstacles get annoying. of course i tried other accept headers but the result is always the same. and im not the only one having trouble with this: http://stackoverflow.com/q/23264044/3563584 . also i didnt choose to use stuff, i have to. – user3563584 Apr 24 '14 at 15:05
  • 5
    Ahhhh so that's how you parse an _embedded list on the client, telling RestTemplate to expect one of the hateoas Resources classes. Very useful, the spring-data-rest documentation is rather sparse on the client side – dan carter Nov 20 '14 at 21:26

1 Answers1

55

As you've discovered correctly, PagedResources does not have an _embedded property, that's why you don't get the content property populated.

This dilemma can be solved in two different ways:

  1. Providing a type that matches the representation in the first place. Thus, craft a custom class and either stick to the property names of the representation or customize it using Jackson annotations etc.

  2. Set up a custom MappingJackson2HttpMessageConverter and customize the ObjectMapperto get the Jackson2HalModule configured that Spring HATEOAS ships out of the box.

    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    mapper.registerModule(new Jackson2HalModule());
    
    MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
    converter.setSupportedMediaTypes(MediaType.parseMediaTypes("application/hal+json"));
    converter.setObjectMapper(mapper);
    
    RestTemplate template = new RestTemplate(Collections.<HttpMessageConverter<?>> singletonList(converter));
    
Oliver Drotbohm
  • 80,157
  • 18
  • 225
  • 211
  • 2
    big thanks for your help. option 2 looks nice. but i get "Unrecognized field "templated" (class org.springframework.hateoas.Link), not marked as ignorable (one known property: "href"])". i guess i have to dig deeper. if i cant get it to work, i guess ill stick to option 1. – user3563584 Apr 25 '14 at 07:55
  • 3
    I think you can simply get rid off this by setting `objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);`. Jackson is quite strict by default. Updated the answer accordingly. – Oliver Drotbohm Apr 25 '14 at 08:02
  • Hm, if I do that [things break for me](https://stackoverflow.com/questions/49610391/pagedresources-content-array-is-empty) - any idea? – Stefan Falk Apr 02 '18 at 11:42
  • @OliverDrotbohm I am having the same issue, the difference is I am not using RestTemplate instead I am using FeignClient. What can I do? – Soumitri Pattnaik Dec 19 '18 at 11:58