Spring Data Rest - _links

13,469

Solution 1

Also with mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) use @JsonIgnoreProperties(ignoreUnknown = true) on every Entity:

@Entity
@JsonIgnoreProperties(ignoreUnknown = true)
public class User {
    ...

}

Solution 2

For Spring-boot 1.3.3 the method exchange() for List is working

public void test1() {

    RestTemplate restTemplate = restTemplate();

    ParameterizedTypeReference<PagedResources<User>> responseTypeRef = new ParameterizedTypeReference<PagedResources<User>>() {
    };

    String API_URL = "http://localhost:8080/api/v1/user"
    ResponseEntity<PagedResources<User>> responseEntity = restTemplate.exchange(API_URL, HttpMethod.GET,
            (HttpEntity<User>) null, responseTypeRef);

    PagedResources<User> resources = responseEntity.getBody();
    Collection<User> users = resources.getContent();
    List<User> userList = new ArrayList<User>(users);

    System.out.println(userList);

}

private RestTemplate restTemplate() {

    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);

    List<HttpMessageConverter<?>> converterList = new ArrayList<HttpMessageConverter<?>>();
    converterList.add(converter);
    RestTemplate restTemplate = new RestTemplate(converterList);

    return restTemplate;
}
Share:
13,469

Related videos on Youtube

APD
Author by

APD

Updated on June 04, 2022

Comments

  • APD
    APD almost 2 years

    Edit 14/08/14 13:29

    My next conclusion is that the hal+json format produced from my @RepositoryRestResource CrudRepository is incorrect.

    The tutorial (http://spring.io/guides/gs/accessing-data-rest/) shows the output of a hypermedia Rest JPA entity as: (please note there is no "rel" element, and "links" is not an array)

    {
       "_links" : {
           "people" : {
               "href" : "http://localhost:8080/people{?page,size,sort}"
           }
       }
     }
    

    However, the reference docs (http://docs.spring.io/spring-data/rest/docs/1.1.x/reference/html/intro-chapter.html) show that the output should be:

    {
        "links" : [ {
            "rel" : "customer",
            "href" : "http://localhost:8080/customer"
          }, {
             "rel" : "profile",
             "href" : "http://localhost:8080/profile"
          }
     }
    

    Does anyone know why this is?

    =====================================

    Edit 14/08/14: I have taken my debugging a step further. By providing my own implementation of a org.springframework.hateoas.ResourceSupport class, which inspects the json for "_links" rather than "links" I get a step further. The error is:

    "Can not deserialize instance of java.util.ArrayList out of START_OBJECT token ..... through reference chain: com.ebs.solas.admin.test.SolicitorDTO[\"_links\"]"

    This is because the org.springframework.hateoas.ResourceSupport class seems to require that the links attribute be a json array. And by default the json+hal output produced by Spring Data for a Rest Entity does not produce an array (there are no square brackets):

    "_links" : {
      "self" : {
        "href" : "http://localhost:9090/solas-admin-data-api/solicitorFirms/Fxxx"
      },
      "solicitors" : {
        "href" : "http://localhost:9090/solas-admin-data-api/solicitorFirms/Fxxx/solicitor
      }
    }
    

    Hopefully someone from the Spring forums could help me here.

    ==============================================

    please see an outline of my Spring Data repository code:

    @RepositoryRestResource
        public interface SolicitorFirmRepository extends CrudRepository<SolicitorFirm, String> {
    }
    
    @Entity
    @RestResource
    @Table(name="XXXX", schema = "XXX")
    public class SolicitorFirm implements Serializable {
    }
    

    This successfully generates the following hateoas resource:

    {
    "firmNumber" : "FXXXX",
    "solicitorType" : "r",
    "companyName" : "XXXX",
    "address1" : "XXXX",
    "address2" : "XXX",
    "address3" : "XXX",
    "address4" : null,
    "phoneNumber" : "XXXXX",
    "faxNumber" : "XXXXX",
    "county" : "OY",
    "_links" : {
        "self" : {
            "href" : "http://localhost:9090/solas-admin-data-api/solicitorFirms/XXXX"
        },
        "solicitors" : {
            "href" : "http://localhost:9090/solas-admin-data-api/solicitorFirms/XXXX/solicitors"
        }
     }
    

    HOWEVER, when i define a DTO for clientside/controller use:

    import org.springframework.hateoas.ResourceSupport;
    public class SolicitorFirmDTO extends ResourceSupport {
       .....
    }
    

    and use the following code

    RestTemplate rt = new RestTemplate();
    String uri = new String("//xxxxx:9090/solas-admin-data-api/solicitors/Sxxxxx");
    SolicitorFirmDTO u = rt.getForObject(uri, SolicitorFirmDTO.class, "SXXXX");
    

    I get the following error:

    com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "_links" (class com.ebs.solas.admin.test.SolicitorFirmDTO), not marked as ignorable (7 known properties: xx])

    For some reason the json produced by Spring Data Rest adds the entity links under _links while the HATEOAS resource superclass expects links?

    Can any one help? is this a version issue or do I need some extra configuration to map _links to links

    I have tried MappingJackson2HttpMessageConverter and various media types application/json+hal to no avail.

    • Chris DaMour
      Chris DaMour over 9 years
      The output is HAL+JSON but your input is expecting just Spring's JSON data type. Do you need to talk HAL? Do you have @enablehypermediasupport annotation somewhere?
    • Chris DaMour
      Chris DaMour over 9 years
      asking again..do you need to talk HAL? if you do..then your client parser needs to know how to deserialize it.
    • APD
      APD over 9 years
      Sorry I will be more specific. yes I do need HAL and obviously the client must be able to deserialize hal+json. If you look at the code I have posted then to the best of my knowledge I have configured/developed my client side code to do exactly that. It creates a Jackson2HalModule object mapper, a MappingJackson2HttpMessageConverter(with application/hal+json media type set) and configures both on the RestTemplate object. thanks
  • Leonard Brünings
    Leonard Brünings over 9 years
    You should edit your question instead of posting an answer which is just a reply to another answer/comment.
  • APD
    APD over 9 years
    sorry, my first question on stackoverflow. will do in future
  • Florian Schaetz
    Florian Schaetz almost 8 years
    Thanks. The Converter for application/hal+json seems to do the trick just fine, otherwise RestTemplate isn't able to parse the whole "_link" thing.