Giter Site home page Giter Site logo

json-patch's Introduction

License LGPLv3 License ASL 2.0 Build Status Maven Central

Read me first

This project, as of version 1.4, is licensed under both LGPLv3 and ASL 2.0. See file LICENSE for more details. Versions 1.3 and lower are licensed under LGPLv3 only.

Note the "L" in "LGPL". LGPL AND GPL ARE QUITE DIFFERENT!

What this is

This is an implementation of RFC 6902 (JSON Patch) and RFC 7386 (JSON Merge Patch) written in Java, which uses Jackson (2.2.x) at its core.

Its features are:

  • {de,}serialization of JSON Patch and JSON Merge Patch instances with Jackson;
  • full support for RFC 6902 operations, including test;
  • JSON "diff" (RFC 6902 only) with operation factorization.

Versions

The current version is 1.13. See file RELEASE-NOTES.md for details of releases before 1.11.

Using it in your project

With Gradle:

dependencies {
    compile(group: "com.github.java-json-tools", name: "json-patch", version: "yourVersionHere");
}

With Maven:

<dependency>
    <groupId>com.github.java-json-tools</groupId>
    <artifactId>json-patch</artifactId>
    <version>yourVersionHere</version>
</dependency>

Versions before 1.10 are available at groupId com.github.fge.

JSON "diff" factorization

When computing the difference between two JSON texts (in the form of JsonNode instances), the diff will factorize value removals and additions as moves and copies.

For instance, given this node to patch:

{ "a": "b" }

in order to obtain:

{ "c": "b" }

the implementation will return the following patch:

[ { "op": "move", "from": "/a", "path": "/c" } ]

It is able to do even more than that. See the test files in the project.

Note about the test operation and numeric value equivalence

RFC 6902 mandates that when testing for numeric values, however deeply nested in the tested value, a test is successful if the numeric values are mathematically equal. That is, JSON texts:

1

and:

1.00

must be considered equal.

This implementation obeys the RFC; for this, it uses the numeric equivalence of jackson-coreutils.

Sample usage

JSON Patch

You have two choices to build a JsonPatch instance: use Jackson deserialization, or initialize one directly from a JsonNode. Examples:

// Using Jackson
final ObjectMapper mapper = new ObjectMapper();
final InputStream in = ...;
final JsonPatch patch = mapper.readValue(in, JsonPatch.class);
// From a JsonNode
final JsonPatch patch = JsonPatch.fromJson(node);

You can then apply the patch to your data:

// orig is also a JsonNode
final JsonNode patched = patch.apply(orig);

JSON diff

The main class is JsonDiff. It returns the patch as a JsonPatch or as a JsonNode. Sample usage:

final JsonPatch patch = JsonDiff.asJsonPatch(source, target);
final JsonNode patchNode = JsonDiff.asJson(source, target);

Important note: the API offers no guarantee at all about patch "reuse"; that is, the generated patch is only guaranteed to safely transform the given source to the given target. Do not expect it to give the result you expect on another source/target pair!

JSON Merge Patch

As for JsonPatch, you may use either Jackson or "direct" initialization:

// With Jackson
final JsonMergePatch patch = mapper.readValue(in, JsonMergePatch.class);
// With a JsonNode
final JsonMergePatch patch = JsonMergePatch.fromJson(node);

Applying a patch also uses an .apply() method:

// orig is also a JsonNode
final JsonNode patched = patch.apply(orig);

json-patch's People

Contributors

capstan avatar cstroe avatar fge avatar gavinf17 avatar huggsboson avatar joeltucci avatar jvitrifork avatar sullis avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

json-patch's Issues

Cannot create a patch from a json node

After successfully getting a JsonNode from a replace json representation, attempting to use JsonPatch.fromJson(JsonNode) explodes the following exception:

Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of FIELD_NAME token

The Json replace (as JsonNode): {"op":"replace","path":"/name","value":"Test"}

The code:

    final ObjectMapper mapper = new ObjectMapper();
    final JsonNode node = mapper.valueToTree(request);
    logger.debug("{}", node);
    JsonPatch patch = JsonPatch.fromJson(node);

copy and move

I do not want diff to contain any move nor copy operations.
Node.js and other Java libs have this option. Is it possible ? How ?

EnumSet flags = DiffFlags.dontNormalizeOpIntoMoveAndCopy().clone()
JsonNode patch = JsonDiff.asJson(JsonNode source, JsonNode target, flags)

https://github.com/flipkart-incubator/zjsonpatch

Maven URL in build-script needs to be updated to https

The maven URL in build.gradle for springsource needs to updated from http to https. Else while building the project from source, it fails to find the dependency.

Current value : http://repo.springsource.org/plugins-release
Value to be updated to : https://repo.spring.io/plugins-release/

Split project depending on API used

Currently project is only one project which depends on Jackson. Next version of Java EE (Java EE 8), will contain JsonPointers inside Json Processing API. For this reason I think that it would be great to split the project into different modules depending on underlying platform.

What I suggest is something like:

A module called core or api which will contain the common classes and interfaces to abstract from JsonPointer implementation.

Then a module for each implementation. For example we can have a jackson implementation or jsonp (the Java EE 8 ones) implementation. And of course everyone will be able to collaborate with their own library. Let's say for example a RestEasy implementation as well.

Of course this is not something to be done just now, but we can start a discussion and have it in mind.

change to apache or bsd license

Hi, I'm sure there's a reason you chose LGPL, and it isn't a terrible license by any means. However, coming out of the api-craft conference, it seems folks would be more interested in reusing your work, if it were apache licensed. Any chance you can change this?

Add context to JsonPatchException

I get an JsonPatchException "no such path in target JSON document". There is no context at all regarding what the path is that's missing. Can you please add that?

e.g.. In RemoveOperation, can the path be added to the exception message?

if (path.isEmpty())
        return MissingNode.getInstance();
if (path.path(node).isMissingNode())
        throw new JsonPatchException(BUNDLE.getMessage("jsonPatch.noSuchPath"));

Identifying move operations when computing JSON patches

This is more of an inquiry and not necessary a bug report. I was experimenting with the tool, and I saw that the resulting patch for certain inputs is not optimal in the sense that the patch uses insertion and deletion operations instead of moves. Consider these two JSON documents describing the syntax tree of some function. The second tree has an extra statement inserted in the beginning:

public static String SRC = "{\n" +
            "  \"name\": \"foo\",\n" +
            "  \"stmts\": [\n" +
            "    {\n" +
            "      \"kind\": \"VarDecl\",\n" +
            "      \"name\": \"a\",\n" +
            "      \"value\": {\n" +
            "        \"kind\": \"PlusExpr\",\n" +
            "        \"lhs\": \"1\",\n" +
            "        \"rhs\": \"2\"\n" +
            "      }\n" +
            "    },\n" +
            "    {\n" +
            "      \"kind\": \"Print\",\n" +
            "      \"exp\": {\n" +
            "        \"kind\": \"VarRef\",\n" +
            "        \"name\": \"a\"\n" +
            "      }\n" +
            "    }\n" +
            "  ]\n" +
            "}";

    public static String TRG = "{\n" +
            "  \"name\": \"foo\",\n" +
            "  \"stmts\": [\n" +
            "    {\n" +
            "      \"kind\": \"VarDecl\",\n" +
            "      \"name\": \"b\",\n" +
            "      \"value\": {\n" +
            "        \"kind\": \"NumLit\",\n" +
            "        \"value\": \"3\"\n" +
            "      }\n" +
            "    },\n" +
            "    {\n" +
            "      \"kind\": \"VarDecl\",\n" +
            "      \"name\": \"a\",\n" +
            "      \"value\": {\n" +
            "        \"kind\": \"PlusExpr\",\n" +
            "        \"lhs\": \"1\",\n" +
            "        \"rhs\": \"2\"\n" +
            "      }\n" +
            "    },\n" +
            "    {\n" +
            "      \"kind\": \"Print\",\n" +
            "      \"exp\": {\n" +
            "        \"kind\": \"VarRef\",\n" +
            "        \"name\": \"a\"\n" +
            "      }\n" +
            "    }\n" +
            "  ]\n" +
            "}";

I use the following code snippet to compute the patch between them:

        final ObjectMapper mapper = new ObjectMapper();
        final JsonNode n1 = mapper.readTree(SRC);
        final JsonNode n2 = mapper.readTree(TRG);
        final JsonPatch diff = JsonDiff.asJsonPatch(n1, n2);

The resulting patch is as follows:

op: replace; path: "/stmts/0/name"; value: "b", 
op: remove; path: "/stmts/0/value/lhs", 
op: remove; path: "/stmts/0/value/rhs", 
op: add; path: "/stmts/0/value/value"; value: "3", 
op: replace; path: "/stmts/0/value/kind"; value: "NumLit", 
op: remove; path: "/stmts/1/exp", 
op: add; path: "/stmts/1/name"; value: "a", 
op: add; path: "/stmts/1/value"; value: {"kind":"PlusExpr","lhs":"1","rhs":"2"}, 
op: replace; path: "/stmts/1/kind"; value: "VarDecl", 
op: add; path: "/stmts/-"; value: {"kind":"Print","exp":{"kind":"VarRef","name":"a"}}

Ideally, the shifting of the original two statements should be described with two moves and no change at all to the nodes in their subtrees. Can you please provide some insights on this scenario? Am I missing something or is the above patch the expected output?

What is the rational behind the "op" property ?

What if instead of

     [{ "op": "move", "from": "/a", "path": "/c" },
      { "op": "move", "from": "/a", "path": "/c" }]

It was

     { 
       "move": [{"from": "/a", "path": "/c"}] },
       "add": [..]
     }

I mean instead of having 1 array of all ops, its was 1 array per property type. Does it have to do with the order of operations ?

Unable to deserialize serialized JsonPatch

When trying to deserialize a JsonPatch using JsonPatch.fromJson(node) the following exception occurrs:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList` out of VALUE_STRING token
 at [Source: UNKNOWN; line: -1, column: -1]
        at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
        at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1342)
        at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1138)
        at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1092)
        at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.handleNonArray(CollectionDeserializer.java:332)
        at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:265)
        at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:245)
        at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:27)
        at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1365)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:171)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:161)
        at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1611)
        at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1295)
        at com.github.fge.jsonpatch.JsonPatch.fromJson(JsonPatch.java:129)

The json node was generated by using MAPPER.writeValueAsString(patch)

Unable to use json-patch in osgi with new guava version

json-patch requires jackson-coreutils. Manifest of jackson-coreutils contains import statements for guava with version [16.0,17). It means that coreutils requires specific guava to be successfully installed in osgi environment.

Supporting wildcard in path

Hello,
I was wondering if its possible to add support for wildcard in path.

{
"biscuits": [
{ "name": "Digestive" },
{ "name": "Choco Leibniz" }
]
}

In the example of:
{ "op": "replace", "path": "/biscuits/*/name", "value": { "name": "ChangeEverything" } }

would lead to:

{
"biscuits": [
{ "name": "ChangeEverything" },
{ "name": "ChangeEverything" }
]
}

In case we aren't sure the amount of entries in an array, supporting this could help generalize it and allow updates everywhere

Bug in replace operation and its proposed solution

Hi,
recently i have been using this library and found a bug in replace operation.
Example:
source json : ["a","b","c","d","e"]
target json : ["e","a","f","c","d","b"]
patch generated :
{op: add; path: "/0"; value: "e",
op: remove; path: "/2",
op: add; path: "/2"; value: "f",
op: replace; path: "/4"; value: "b" }
Now if we apply this patch to source json, resultant json would be:
["e","a","f","c","b","e"]

Now, why it happened:
-- path captured in replace operation is with respect to source json, which will always produce invalid-patch, since it is not taking into consideration the number of add/remove operations prior to it ( which may have caused change in path ).
--If path captured in replace operation, would have been relative path in new json, then it would have not caused the issue.

Possible solution:

  1. path captured in replace operation should reflect the relative path in final json, not infer from source json.
  2. If we let path to be captured from source json only, then we can apply all replace operation first and then apply rest of operations in sequence in which they are computed.

Please go through this case and let me know any concern about by bug reported or solution proposed.

Add validate method on JsonPatch

Because of the nature of patch (a list of operations to be applied), you need to validate that these operations are valid and you don't receive an unwanted operation.

For example suppose you are implementing a change password. This change password requires two things, the new password, the old password and the answer to a personal question. So json patch could be something like:

[
     { "op": "test", "path": "/password", "value": "myencryptedpassword" },
     { "op": "test", "path": "/answer", "value": "myanswer" }
     { "op": "replace", "path": "/password", "value": "newpassword" }
]

But of course nobody can avoid that someone send this:

[
     { "op": "replace", "path": "/username", "value": "hahaIhavechangedyourname" }
     { "op": "test", "path": "/password", "value": "myencryptedpassword" },
     { "op": "test", "path": "/answer", "value": "myanswer" }
     { "op": "replace", "path": "/password", "value": "newpassword" }
]

To avoid this a new method could me implemented called for example validate which can receive a "functional interface" to be implemented which have a method called validate with a parameter which is a list of operations to be done (list of { "op": "replace", "path": "/username", "value": "hahaIhavechangedyourname" }). In this way before applying the changes, the developer may be free to call validate or not. What I mean is that validate method could be executed automatically or not. Also we can overload JsonPatch.fromJson method setting the "functional interface" so then automatically validate method will be called automatically before executing apply.

I think it has a lot of sense allowing this kind of operations in sake of security.

WDYT?

Synchronization issue in using this library

Maybe I am missing something

but in using this library I am creating a sync issue

Thread = T

in the DB:
Class Foo {
int x = 1;
int y = 1;
}

T1 get Foo (x=1, y=1)
T2 get Foo and updates y=2 (x=1, y=2)
T1 update Foo to x=5 (x=5, y=1)

and partial update is not an option because there is not access to the Operation/Path/Value we update

for a server with multiple replica set i need to create a distributed lock in order to avoid sync issue

am i missing any thing?

Correct path syntax

Hello,

The library is being used in KNIME: https://www.knime.com/

Hope you don't mind me asking a question here. I'm trying to get an answer at the forum there, but can't get a response. Probably not too many people working with JSON files.

I'm trying to understand how to add a branch like this:
image

But it doesn't like "path": "/Conditions/Parameters/3"

I'm guessing the syntax is wrong, but can't figure it out...

Thanks in advance for a reply.

Restrict certain paths and operations

As far as I can tell, there is no built-in implementation to restrict combinations of paths and operations. Are there plans to implement this and maybe a RestrictedJsonPatchException to be thrown when restricted paths/operations are applied?

Generate test-and-set patch jsons

How I can add test operations before remove or replace operations ?
Looking for implementation of test (DiffProcessor) but I didnt find him, It can solve some problems called "lost update".

The lost update problem has been present in most distributed authoring environments using rudimentary HTTP/1.0 features. The lost update problem can be illustrated as follows:

  1. Ron accesses document X using HTTP GET and starts editing it.
  2. Shirley also accesses document X using HTTP GET and starts editing it.
  3. Ron saves his edits.
  4. Shirley saves her edits but as she didn't see Ron's edits, they are lost in the operation.

Using test on old properties it can be solved (or ETAG, but test is most effective).

A custom diffprocessor can solve this problem

Request for adding a block remove operation for arrays

Currently operations to remove elements in an array are hard to read/write by hand. You either need to list the indexes you want to delete in reverse order or recalculate the indices on the fly, since the operations are applied in a stream and each operation is dependent on the previous(for instance deleting the first 2 elements requires 2 /0's). I would like to propose a block_remove operation that takes an array of indexes(all corresponding to the same position in the original array) and deletes them all at once. This could not only make the resulting diffs more compact, it could also help people who create them by hand.

I have created an example implementation here: joeltucci@341eb02

I didn't want to do this as a pull request since it may need to be significantly reworked, but if possible I would like to see this feature implemented.

Let me know if you have any questions/issues.

Ability to generate diff as merge patch

Hi guys

I want to store a diffs between versions of a JSON. I can do it using collecting a diffs (RFC-6902). However with multiple changes I need to store big list of operations to be later applied. Since the library allows to apply merge patch to a JSON (RFC-7386) I think it would be very useful to be able to produce such merge patch having two JSONs. Is there a reason why it's not supported? Is it planned?

Thanks in advance

JsonPatch and Differential Synchronization algorithm

To allow implements the Differential Synchronization algorithm (https://neil.fraser.name/writing/sync/) in the use case 4:Guaranteed Delivery Method we need send with patch the client-server version.
Create a JsonVersionedPatch that extends JsonPatc is not possible since JsonPatch is declared as final.
I will like know if you have in consideration implements this great algoritm in the future roadmap.

Integrate project with travis.

Integrate project with travis so every time a PR or commit is sent, the whole project is tested in travis servers.

I can implement this as well.

Adding JSON Object Fails

When trying to perform an ADD operation with the value as a JSON object, I am getting an error. I have tried to perform the following patch:

[
{
"op":"add",
"path":"/new_field",
"value":{
"field1":"test1",
"field2": "test2"
}
}
]

The generated patch operation above was the result of running JsonDiff.

11:24:28,120 ERROR stderr com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of VALUE_STRING token
11:24:28,120 ERROR stderr at [Source: N/A; line: -1, column: -1]
11:24:28,121 ERROR stderr at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164)
11:24:28,121 ERROR stderr at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:599)
11:24:28,121 ERROR stderr at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:593)
11:24:28,121 ERROR stderr at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.handleNonArray(CollectionDeserializer.java:255)
11:24:28,122 ERROR stderr at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:213)
11:24:28,122 ERROR stderr at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:203)
11:24:28,122 ERROR stderr at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:23)
11:24:28,123 ERROR stderr at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromString(BeanDeserializer.java:417)
11:24:28,123 ERROR stderr at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:129)
11:24:28,123 ERROR stderr at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1206)
11:24:28,123 ERROR stderr at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:895)

Json Patch - attempt to update attribute of an nested object is not happening.

I am trying to assign new dept to Employee using deptNameusing JsonPatch but the update to DB is not happening. I noticed that my patched object has Dept object has new/updated name but no is still pointing to old deptNo. Looks like Patch is attempting to update dept.deptName instead of updating reference to entire dept entity (which I think should be the case). what am i missing here?

[{"op":"replace", "path":"/dept/name","value":"HR"} ]

@entity
public class EMP{
@manytoone(fetch = FetchType.LAZY)
@joincolumn(name = "deptNo", referencedColumnName = "deptNo")
private Dept dept;
}

@entity
public class Dept {
private String deptName;
private Integer deptNo;
}

Ignore specific fields while calculating JSON diff.

When I find the difference between two JsonNodes, I shall be able to ignore specific fields.

Example:

Foo.java has id and name fields and I have two different objects of this class say foo1 and foo2.

When I compare the diff using JsonDiff class, I shall be able to ignore id comparison and be able to find diff for name field only.

   JsonNode oldJsonNode = objectMapper.readTree(objectMapper.writeValueAsString(foo1));
    JsonNode newJsonNode = objectMapper.readTree(objectMapper.writeValueAsString(foo2));
    JsonNode jsonDiff = JsonDiff.asJson(oldJsonNode, newJsonNode);

I want to exclude id field in jsonDiff object.

Remove Guava dependency

I know that it could imply a bit of work, but currently we would discard using this library because of Guava dependency. Not because we have nothing against Guava (in fact it is a really good library), but because we don't want to get a 2MB library when in fact only 2% of the whole library is being used. IMHO no general library should use so big dependencies.

Can not deserialize instance of java.util.ArrayList out of FIELD_NAME token

I'm using json-patch-1.9, and the following simple code doesn't work:

        String origJson = "{\"id\":1}";
        String newJson =  "{\"id\":1}";
        ObjectMapper mapper = new ObjectMapper();
        JsonNode origNode = mapper.readTree(origJson);
        JsonNode newNode = mapper.readTree(newJson);
        JsonPatch patchNew = JsonPatch.fromJson(newNode);
        JsonNode diffs = patchNew.apply(origNode);

The call to JsonPatch.fromJson(newNode) throws the following exception:

com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of FIELD_NAME token

Any idea what is wrong?

json library modules in maven repos

Hi Francis,
I just came across your json-diff/patch libraries that look very promising for my purposes. But I also found a slight problem in your pom definitions:
pom

It is not a big problem, but your modules are hard to find on a common platform like mvnrepository.com unless someone knows your artifact names:
mvnrepository

Cheers
Ben

Revert an applied patch

I'm like to unapply a patch to restore a document to its original form.

I am executing transformation steps and checkpointing at each stage, where I store a JsonPatch of the changes. Each checkpoint I also update the visible entity, so that the user sees progressive results (e.g. images while OCR'ing takes place). The checkpoint patches make it easy to debug when new steps are added.

If this workflow fails and has to restart, e.g. the server is restarted during a deployment, the job would be rescheduled. Ideally it would resume at the checkpoint, but sometimes it might be preferred to restart the workflow (e.g. bug in a prior step). But instead of keeping the original json, I'd like to rollback by reverting the checkpoints. Then I'd store the accumulated patch for an audit trail and purge the checkpoint history periodically.

This could all be done today by computing the reverse patch and storing it as well. It seems fairly natural that JsonPatch.unapply or JsonPatch.reverse() should be provided, though. I'd expect it to be easily computable for the patch to change the direction of each operation.

Roadmap or planning for a the next release?

Do you have any plan to produce a 1.14 ou 1.2 release of the library with latest commits? The ones providing getters on attributes of JsonPatch, JsonPatchOperation and PathValueOperation are must-haves and I'm eagerly waiting for their release.

Jackson 2.5 released noguava time?

Hi Jackson 2.5 has been released with some changes required to use json-path without guava. There is a topic branch on the project, if you are still interested in that move we could finish it.

patch with multiple deletes causes unexpected results or exception

Consider the following source:

[{"name":"a"},{"name":"b"},{"name":"c"}]

And the following target:

[{"name":"b"}]

JsonDiff produces the following patch:

[{"op":"remove","path":"/0"},{"op":"remove","path":"/2"}]

However, if you apply that patch to the original source, you get an exception:

com.github.fge.jsonpatch.JsonPatchException: no such path in target JSON document
com.github.fge.jsonpatch.RemoveOperation.apply(RemoveOperation.java:58)
com.github.fge.jsonpatch.JsonPatch.apply(JsonPatch.java:155)
com.github.fge.jsonpatch.JsonPatch.apply(JsonPatch.java:145)

The issue appears to be that deletes are applied sequentially. The path at index 0 is deleted, but then the resulting array only has length 2. Operating on the shortened array means there is now no path at index 2 to delete. For example the following patch will not throw an exception, however the first and THIRD nodes are deleted, not the first two as might be expected.

[{"op":"remove","path":"/0"},{"op":"remove","path":"/1"}]

Support serialization

It would be nice if my client code and my server code can both use this lib. If I try to serialize a Operation, all I get is an empty object.

Cannot deserialize JsonPatch in @Controller SpringBoot.

When i recive a JsonPatch in a SpringBoot @controller i have this error.

"JSON parse error: Cannot deserialize instance of java.util.ArrayList<com.github.fge.jsonpatch.JsonPatchOperation> out of FIELD_NAME token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of java.util.ArrayList<com.github.fge.jsonpatch.JsonPatchOperation> out of FIELD_NAME token\n at [Source: (PushbackInputStream); line: 2, column: 5]",

But if i change JsonPatch for JsonMergePatch the deserialize works good.

I work work 1.12 versión in my project.

Do you have any idea?

Thanks.

Reduce `deepCopy` calls

When there are many operations to run successively and when the document is large performing deepCopy for each operation becomes extremely expensive.

Below is an example of the change I'm talking about with only 'replace':

diff --git a/src/main/java/com/github/fge/jsonpatch/JsonPatch.java b/src/main/java/com/github/fge/jsonpatch/JsonPatch.java
index 178ab86..9f0a3d4 100644
--- a/src/main/java/com/github/fge/jsonpatch/JsonPatch.java
+++ b/src/main/java/com/github/fge/jsonpatch/JsonPatch.java
@@ -142,7 +142,7 @@ public final class JsonPatch
         throws JsonPatchException
     {
         BUNDLE.checkNotNull(node, "jsonPatch.nullInput");
-        JsonNode ret = node;
+        JsonNode ret = node.deepCopy();
         for (final JsonPatchOperation operation: operations)
             ret = operation.apply(ret);
 
diff --git a/src/main/java/com/github/fge/jsonpatch/ReplaceOperation.java b/src/main/java/com/github/fge/jsonpatch/ReplaceOperation.java
index 72405a6..fca2fab 100644
--- a/src/main/java/com/github/fge/jsonpatch/ReplaceOperation.java
+++ b/src/main/java/com/github/fge/jsonpatch/ReplaceOperation.java
@@ -69,7 +69,7 @@ public final class ReplaceOperation
         final JsonNode replacement = value.deepCopy();
         if (path.isEmpty())
             return replacement;
-        final JsonNode ret = node.deepCopy();
+        final JsonNode ret = node;
         final JsonNode parent = path.parent().get(ret);
         final String rawToken = Iterables.getLast(path).getToken().getRaw();
         if (parent.isObject())

Instead of performing the copy in each operation it is performed once at the top level. The above will fail tests since they expect ReplaceOperation to copy the node. Beyond that are there any edge cases this type of change would break? Are there other ways to reduce copying? Thanks.

Getters for JsonPatch* class attributes

Was there a particular design reason no getters were provided in the JsonPatch classes? I'm deserializing json over the wire into instances of these classes and attempting to provide for a JSR303 validation implementation allowing me to limit patch operations, without public methods to access class attributes (i.e. path), it's seemingly impossible. I'd hate to convert to something that I can access the attributes, it seems cumbersome.

Thoughts?

Add old value in result

Hi , can we add old value also in the result i need this in my requirement
please help me to add old value in the result.

Provide more informative exception reports

Hi, please provide informative exception reports or at least logging staff to determine problems on patching process.
For example here will be better if you can return the given path to requested node
jsonPatch.noSuchPath=no such path (%s) in target JSON document
Thanks.

Add operation on array

Hi, using version 1.13 with Quarkus 2.2.3

I might be wrong since this isn't quite obvious in the RFC:

If the target location specifies an object member that does not
already exist, a new member is added to the object.

Shouldn't the add operation on an array, add the elements to it?

Currently I'm observing that the array is being replaced. For example, for a existing user with a role "administrator" I wanted to add another role:

Request method:	PATCH
Request URI:	http://localhost:9090/api/user/ZaHkxQxwuv
Body:
[
    {
        "op": "add",
        "path": "/roles",
        "value": [
            "User"
        ]
    }
]
HTTP/1.1 200 OK
Content-Length: 125
Content-Type: application/json

{
    "uuId": "f2e333cf-079e-4403-9051-3e347b7934b1",
    "lastLogin": null,
    "id": "ZaHkxQxwuv",
    "status": "ENABLED",
    "roles": [
        "User" // Admin is missing
    ]
}

Override Equals

In testing I want the ability to compare JsonPatch objects for equality. Unfortunately equals falls back on Object's implementation of it which is just a plain pointer comparison.

My workaround for the time being has been to convert the JsonPatch to JsonNode and compare those, like

JsonPatch expectedPatch = ...;
JsonNode expectedNode = objectMapper.valueToTree(expectedPatch);
JsonPatch observedPatch = methodWeAreTesting(...);
JsonNode observedNode = objectMapper.valueToTree(observedPatch);
assertThat(observedNode).isEqualTo(expectedNode);

I would like to do

JsonPatch expectedPatch = ...;
JsonPatch observedPatch = methodWeAreTesting(...);
assertThat(observedPatch).isEqualTo(expectedPatch);

Common interface for Patches

In my API I wish to support both "application/json-patch" and "application/merge-patch" for deeply related and large entities. An example in a Spring Controller:

 @RequestMapping(method = RequestMethod.PATCH, value = "/configurations/{id}", consumes = "application/merge-patch+json")
 public Configuration merge(@PathVariable Long id, @RequestBody ObjectNode request) {
   // Creates a JsonMergePatch from the ObjectNode and calls:
    return apply(id, mergePatch);
}

@RequestMapping(method = RequestMethod.PATCH, value = "/configurations/{id}", consumes = "application/json-patch+json")
public Configuration patch(@PathVariable Long id, @RequestBody ArrayNode request) {
    // Creates a JsonPatch from the ArrayNode and calls:
    return apply(id, jsonPatch);
}

private Configuration apply(Long id, Patch patch) {
    // Before Apply: Retrieves configuration from database using id, transforms it into a JsonNode
    JsonNode patchedNode = patch.apply(configurationNode);
    // After Apply: Transforms the patched node into a Configuration and saves to database.
    return patchedConfiguration;
}

In this case, the actions before and after patch application are the same independent of which patch I am applying and the apply method shouldn't really care which patch it is applying as long as it is a valid patch for JSON.

Problem with ObjectIds

Patching and deserializing object annotated with JsonIdentityInfo may fail when duplicate ids occur. For example, given a JSON source:

{
    "@id": 123,
    "name": "John",
    "dog": { "@id": 456, "name": "Buddy" },
    "cat": { "@id": 789, "name": "Rover" },
    "favoritePet": 456
}

applying

[ {
    "op": "replace",
    "path": "/favoritePet",
    "value": { "@id": 789, "name": "Rover" }
} ]

will result in

{
    "@id": 123,
    "name": "John",
    "dog": { "@id": 456, "name": "Buddy" },
    "cat": { "@id": 789, "name": "Rover" },
    "favoritePet": { "@id": 789, "name": "Rover" }
}

and deserializing with Jackson will fail with:

JsonMappingException: Already had POJO for id '789'

The patch is applied correctly, but it cannot be deserialized as a side effect of duplicated ObjectIds. Id would be useful to have JsonPatch recognize ObjectIds and use them if the patched JSON already contains one.

There is no possibility to set jsonNodeFactory when working with patches.

I would like to use the library withExactBigDecimals, i.e keeping 25.000 when patching a node.

@Test
void testDecimalsKeptAfterPatch() {

    ObjectMapper mapper = new ObjectMapper()
        .enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)
        .setNodeFactory(JsonNodeFactory.withExactBigDecimals(true));

    JsonNode newer = mapper.readTree("25.000");
    JsonNode older = mapper.readTree("24.444");
    JsonNode apply = JsonMergePatch.fromJson(newer).apply(older);

    assertEquals("25.000", apply.asText());
}
org.junit.ComparisonFailure: expected:<25[.000]> but was:<25[]>
Expected :25.000
Actual   :25

Is it possible to inject the behaviour I am after?
The JacksonUtils that JsonMergePatch is using sets the factory to JsonNodeFactory.instance and I cannot see a way around this. I would prefer to use the JsonNodeFactory.decimalsAsIs for my specific case.

This also applies to the JsonDiff.asJson(older, newer) with the same behaviour as the above example.

Unable to remove array elements in ascendent order

When you try to apply a remove operation inside an array, depending of the array size and the operations structure an exception can be thrown.

Let's imagine the following example: you have an object with an array of 2 elements. If you try to remove first the element at index 0 and then the element at index 1, the execution fails. Why? Because the operations are applied in a sequential order, so, first we remove the element of the index 0, and we get the array with just one element inside, then we try to remove the element at index 1 and there are not elements at that position.

I have created a github simple project to show this with unit test.

The easy way to avoid this is to create the deletion operations in descentent order: first the greatest index and last the smallest index. But it would be nice to take this into account inside the json-patch library.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.