spring-projects / spring-hateoas

Spring HATEOAS - Library to support implementing representations for hyper-text driven REST web services.
https://spring.io/projects/spring-hateoas
Apache License 2.0
1.03k stars 475 forks source link

Cannot convert input object to HAL when POSTing #404

Open RaySinnema opened 8 years ago

RaySinnema commented 8 years ago
java.lang.IllegalArgumentException: Class org.springframework.hateoas.hal.Jackson2HalModule$HalLinkListSerializer has no default (no arg) constructor
    at com.fasterxml.jackson.databind.util.ClassUtil.createInstance(ClassUtil.java:370)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializerInstance(DefaultSerializerProvider.java:488)
    at com.fasterxml.jackson.databind.ser.BasicSerializerFactory.findSerializerFromAnnotation(BasicSerializerFactory.java:461)
    at com.fasterxml.jackson.databind.ser.BeanSerializerFactory._constructWriter(BeanSerializerFactory.java:708)
    at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.findBeanProperties(BeanSerializerFactory.java:557)
    at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.constructBeanSerializer(BeanSerializerFactory.java:344)
    at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.findBeanSerializer(BeanSerializerFactory.java:263)
    at com.fasterxml.jackson.databind.ser.BeanSerializerFactory._createSerializer2(BeanSerializerFactory.java:222)
    at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.createSerializer(BeanSerializerFactory.java:152)
    at com.fasterxml.jackson.databind.SerializerProvider._createUntypedSerializer(SerializerProvider.java:1108)
    at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:1068)
    at com.fasterxml.jackson.databind.SerializerProvider._findExplicitUntypedSerializer(SerializerProvider.java:1049)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.hasSerializerFor(DefaultSerializerProvider.java:348)
    at com.fasterxml.jackson.databind.ObjectMapper.canSerialize(ObjectMapper.java:2072)
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.canWrite(AbstractJackson2HttpMessageConverter.java:173)
    at org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:787)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:594)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:557)
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:475)
odrotbohm commented 8 years ago

Would you mind elaborating on what the context of the problem is? HAL is not supposed to be received by the server but a reading format.

RaySinnema commented 8 years ago

Where does it say that HAL can only be used as input?

This post from Mike Kelly seems to imply that HAL can be used for sending data to the server: https://groups.google.com/d/msg/hal-discuss/54greBxUWLQ/Xurqipg36gEJ

gregturn commented 8 years ago

Well on the face of things, when you receive a HAL document as your input, what if the "self" link points to a different URI than was sent out? Would that mean to overwrite a different record? The same can be said for any other links.

I can imagine the following sequence:

  1. GET /api/orders/1 -> receive doc loaded with _links
  2. PUT doc /api/orders/2

What would you expect to happen? Replace the record's "id" (which is 2) with 1, which might generate a constraint violation? If order 2 was linked to a customer, should it remap it to a different customer? Every relationship in that resource could blasted in what might be a typo from the user. Could also be viewed as a security hole.

By instead requiring PUTs to actually rewrite the relationships directly, the user is forced to consciously update such links, not accidentally slipped through _links.

RaySinnema commented 8 years ago

This is a fairly common problem that we see in most of our APIs, whether they use HAL or not. There are several solutions to the problem; the easiest one is probably to declare _links as read-only and thus completely ignore it when processing requests.

We do that to allow clients to GET a representation, update something and then PUT it back without bothering to remove read-only properties. It's an application of the principle of "be conservative in what you send, be liberal in what you accept".