I have an entity that needs to accept arbitrary fields from a client, let's call the entity a Blob. I've defined my entity using the @JsonAnyGetter/@JsonAnySetter annotations to capture any fields that aren't explicitly mapped:
@Document
public class Blob {
@Id
private ObjectId id;
private Map<String, Object> additionalFields = new HashMap<>();
Blob() {
}
public ObjectId getId() {
return id;
}
@JsonAnySetter
public void setAdditionalFields(final String key, final Object value) {
this.additionalFields.put(key, value);
}
@JsonAnyGetter
public Map<String, Object> getAdditionalFields() {
return additionalFields;
}
}
And then I have a rest repository to give me basic CRUD endpoints:
public interface BlobRepository extends CrudRepository<Blob, ObjectId> {
}
POST works as expected and the response gives me all of the fields back:
POST /blobs HTTP/1.1
Content-Type: application/json
Accept: application/json
{
"name": "bob",
"size": "small",
"color": "green"
}
HTTP/1.1 201
Location: http://localhost:8080/blobs/5919e2e292034b6765507cd4
Content-Type: application/json;charset=UTF-8
{
"name" : "bob",
"size" : "small",
"color": "green",
"_links" : {
"self" : {
"href" : "http://localhost:8080/blobs/5919e2e292034b6765507cd4"
},
"blob" : {
"href" : "http://localhost:8080/blobs/5919e2e292034b6765507cd4"
}
}
}
The problem is when I try to update an existing blob with a PUT request:
PUT /blobs/5919e2e292034b6765507cd4 HTTP/1.1
Content-Type: application/json
Accept: application/json
{
"name": "bobby",
"size": "large",
"color": "blue"
}
HTTP/1.1 200
Location: http://localhost:8080/blobs/5919e2e292034b6765507cd4
Content-Type: application/json;charset=UTF-8
{
"name" : "bob",
"size" : "small",
"color": "green",
"_links" : {
"self" : {
"href" : "http://localhost:8080/blobs/5919d09d92034b5b219802b3"
},
"blob" : {
"href" : "http://localhost:8080/blobs/5919d09d92034b5b219802b3"
}
}
}
None of the new fields are accepted, only the old value remain. Frustratingly though, PATCH requests work as expected:
PATCH /blobs/5919e2e292034b6765507cd4 HTTP/1.1
Content-Type: application/json
Accept: application/json
{
"name": "bobby",
"size": "large",
"color": "blue"
}
HTTP/1.1 200
Location: http://localhost:8080/blobs/5919e2e292034b6765507cd4
Content-Type: application/json;charset=UTF-8
{
"name" : "bobby",
"size" : "large",
"color": "blue",
"_links" : {
"self" : {
"href" : "http://localhost:8080/blobs/5919d09d92034b5b219802b3"
},
"blob" : {
"href" : "http://localhost:8080/blobs/5919d09d92034b5b219802b3"
}
}
}
I could be wrong, but I don't think that this is anything to do with the semtantics of PUT vs PATCH since I'm sending the full object will all of the fields I'd expect PUT to replace (or ideally merge) the existing entity with the new fields.
I've created a repo with a minimal spring project and some tests that show the problem. Any throughts would be appreciated.