Hello,
I have had a request for one of my projects to implement Jackson
serialization of my JSON Patch implementation; deserialization was
already working. All files in question are here:
https://github.com/fge/json-patch/tree/master/src/main/java/com/github/fge/jsonpatch
A JSON Patch is an array of individual operations; for instance:
[
{ "op": "add", "path": "/foo", "value": null },
{ "op", "remove", "path": "/bar" },
{ "op": "copy", "path": "/dst", "from": "/src"}
]
The JsonPatchOperation abstract class is the base class for all
operations; it reads:
----
@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "op")
@JsonSubTypes({
@Type(name = "add", value = AddOperation.class),
@Type(name = "copy", value = CopyOperation.class),
@Type(name = "move", value = MoveOperation.class),
@Type(name = "remove", value = RemoveOperation.class),
@Type(name = "replace", value = ReplaceOperation.class),
@Type(name = "test", value = TestOperation.class)
})
@JsonIgnoreProperties(ignoreUnknown = true)
public abstract class JsonPatchOperation
{
@JsonSerialize
protected final String op;
@JsonSerialize(using = JsonPointerSerializer.class)
protected final JsonPointer path;
protected JsonPatchOperation(final String op, final JsonPointer path)
{
this.op = op;
this.path = path;
}
----
Here there is one problem already: the needed @JsonSerialize
annotation; more on this later.
The JsonPatch class is, essentially, a List<JsonPatchOperation>:
----
public final class JsonPatch
{
private final List<JsonPatchOperation> operations;
@JsonValue
private List<JsonPatchOperation> getOperations()
{
return operations;
}
@JsonCreator
@VisibleForTesting
JsonPatch(final List<JsonPatchOperation> operations)
{
this.operations = ImmutableList.copyOf(operations);
}
----
Here is the second problem: I need the @JsonValue annotation...
The test program (link:
https://github.com/fge/json-patch/blob/master/src/test/java/com/github/fge/jsonpatch/Issue6.java)
shows strange behaviour for deserializing individual operations:
----
Deserialized patch: [op: add; path: "/foo/bar"; value: "baz"]
Serialized Json: [{"op":"add","path":"/foo/bar","value":"baz"}]
Deserialized op: op: add; path: "/foo/bar"; value: "baz"
Serialized Json:
{"op":"add","op":"add","path":"/foo/bar","value":"baz"} <--- PROBLEM
----
The "op" field is doubled. If I remove the @JsonSerialize annotation
from JsonPatchOperation then the output is as follows:
----
Deserialized patch: [op: add; path: "/foo/bar"; value: "baz"]
Serialized Json: [{"path":"/foo/bar","value":"baz"}] <--- PROBLEM
Deserialized op: op: add; path: "/foo/bar"; value: "baz"
Serialized Json: {"op":"add","path":"/foo/bar","value":"baz"}
----
Now the "op" field is no more doubled when deserializing an individual
operation... But it does not appear when serializing a full patch! And
I need it, of course... In fact, prior to having been asked to support
serialization, the JsonPatchOperation did not have the "op" field at
all, I had to add it.
Finally, I am dissatisfied with the fact that I had to add a (private)
getter for "operations" in JsonPatch; is there a cleaner way?
Sorry for the long read,
--
Francis Galiegue,
fgal...@gmail.com
JSON Schema in Java:
http://json-schema-validator.herokuapp.com