spring-projects / spring-projects/spring-data-rest
inconsistant behaviour of a HTTP PATCH request on a com.mongodb.BasicDBObject member [DATAREST-772]
@odrotbohm is already working on this.
Since Dec 31, 2020.
- Dominant language
- Java
- Stars
- 958
- Forks
- 568
- PR merge metrics
- No merged PRs in 30d
Description
Marc Tarin opened DATAREST-772 and commented
I've created a simple webservice with Spring Boot 1.3.2 (with dependencies on spring-boot-starter-data-rest and spring-boot-starter-data-mongodb) to read/write MongoDB documents describe by the following class (getters/setters omitted):
@Document(collection="items")
public class Item {
@Id
private String id;
private String name;
private BasicDBObject data;
}
Persisting a new object in the database works as expected. By POSTing:
{ "name" : "foo",
"data" : {}
}
I get the following answer (_links omitted for clarity purposes):
{
"name" : "foo",
"data" : { },
"_links" : ...
}
The purpose of the data field is to store data of variable complexity and depth.
Let's keep it simple for now... PATCHing with:
{ "data" :
{ "a" : 1,
"b" : 2,
"c" : 3
}
}
Returns:
{
"name" : "foo",
"data" : {
"a" : 1,
"b" : 2,
"c" : 3
},
"_links" : ...
}
Further PATCHing with:
{ "data" : {
"a" : 0,
"d" : 4
}
}
Returns:
{
"name" : "foo",
"data" : {
"a" : 0,
"d" : 4
},
"_links" : ...
}
}
Question one: is this result correct? I would have expected the following instead:
{
"name" : "foo",
"data" : {
"a" : 0,
"b" : 2,
"c" : 3
"d" : 4
},
"_links" : ...
}
Now, for the funny part...
As a foreword, let me just say that I know that PATCH is unsafe and non-idempotent and should be used with caution.
Let's say I have changed my mind about d, and I want to store a subdocument in it:
PATCHing with:
{ "data" : {
"a" : 2,
"d" : {}
}
}
Throws and exception:
{"cause":{"cause":null,"message":"Can not update object of type java.lang.Integer (by deserializer of type com.fasterxml.jackson.databind.deser.std.NumberDeserializers$IntegerDeserializer)"},"message":"Could not read payload!; nested exception is java.lang.UnsupportedOperationException: Can not update object of type java.lang.Integer (by deserializer of type com.fasterxml.jackson.databind.deser.std.NumberDeserializers$IntegerDeserializer)"}
There is a workaround, by simply PATCHing data with a only, then re-sending the PATCH above, I can get what I wan't, ie:
{
"name" : "foo",
"data" : {
"a" : 2,
"d" : { }
},
"_links" : ...
}
A bit awkward to me, since the exception above sometimes get thrown when I re-add d as subdocument, even if I PATCHed it away before!
Let's play a bit more (sorry for the long post, btw). The current data being:
{
"name" : "foo",
"data" : {
"a" : 0,
"d" : 4
},
"_links" : ...
}
}
With a new PATCH that goes:
{ "data" : {
"d" : {
"c" : 5
}
}
}
Consistently with what happened before, I should expect the following response:
{
"name" : "foo",
"data" : {
"d" : {
"c" : 5
}
},
"_links" : ...
}
}
Turns out I get:
{
"name" : "foo",
"data" : {
"a" : 2,
"d" : {
"c" : 5
}
},
"_links" : ...
}
Question two: is this result correct?
If it the expected behaviour, It seems kind of inconsistant with the result that led me to Question One.
Now for Question Three...
The current data being :
{
"name" : "foo",
"data" : {
"a" : 2,
"d" : {
"c" : 5
}
},
"_links" : ...
}
PATCHing an update for a and d:
{ "data" : {
"a" : 3,
"d" : {
"c" : 4
}
}
}
Here's what I get:
{
"name" : "foo",
"data" : {
"a" : 2
},
"_links" : ...
}
The payload for d just went down the toilet :(
If I re-send the PATCH, it will update d correctly.
And if I send it again, or even if I change the contents of d once more, d get flushed down again, and so on.
Question Three: what is happening?
I have been scratching my head for a few hours and I really don't have a clue about this strange behaviour (and I am confident there's are many more unexpected things that could happen).
The only thing clear is that right now, send PATCH request should be avoided when dealing with a data schema that is actually schema less, until the result can get somewhat predictable.
Regards
Affects: 2.4.2 (Gosling SR2)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.