Details

    • Type: New Feature New Feature
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: None
    • Fix Version/s: 1.1
    • Labels:
      None

      Description

      Consider adding support for JSON Patch. The RFC is at http://tools.ietf.org/html/rfc6902

      Perhaps, it can be used for transforming one JsonObject/JsonArray to another (works well since JsonObject/JsonArray are immutable)

        Activity

        Hide
        asotobu added a comment -

        Understood yes it has a lot of sense. I am going to merge the PR about JsonPointer and start working on that.

        Show
        asotobu added a comment - Understood yes it has a lot of sense. I am going to merge the PR about JsonPointer and start working on that.
        Hide
        kchung added a comment -

        Regarding 3, what I meant was:

        public class JsonPatch {
            JsonStructure apply(JsonStructure target);
            JsonArray apply(JsonArray target);
            JsonObject apply(JsonObject target);
        }
        

        So that you can write

        JsonArray result = jsonPatch.apply(target);
        

        If target is known to be a JsonArray, without having to use cast on the result.

        Show
        kchung added a comment - Regarding 3, what I meant was: public class JsonPatch { JsonStructure apply(JsonStructure target); JsonArray apply(JsonArray target); JsonObject apply(JsonObject target); } So that you can write JsonArray result = jsonPatch.apply(target); If target is known to be a JsonArray, without having to use cast on the result.
        Hide
        asotobu added a comment -

        1. Probably you were right, I was thinking more in creating a factory of merge methods (path or merge patch) but as I said we can remove it.
        2. Agreed
        3. Don't understand this. Why apply should be in JsonArray or JsonObject? I was having in mind using JsonPointer operations. For example in pseudocode:

        JsonArray patchOperations = ...
        target = ...
        foreach(JsonObject patch:patchOperations) {
          JsonPointer pointer = new JsonPointer(patch.get("path"));
          if(patch.get("op") is "add") {
            target = pointer.add(target, patch.get("value");
          }
        }
        

        4. Probably it is true but maybe we could wait for next iteration.

        Show
        asotobu added a comment - 1. Probably you were right, I was thinking more in creating a factory of merge methods (path or merge patch) but as I said we can remove it. 2. Agreed 3. Don't understand this. Why apply should be in JsonArray or JsonObject? I was having in mind using JsonPointer operations. For example in pseudocode: JsonArray patchOperations = ... target = ... foreach(JsonObject patch:patchOperations) { JsonPointer pointer = new JsonPointer(patch.get( "path" )); if (patch.get( "op" ) is "add" ) { target = pointer.add(target, patch.get( "value" ); } } 4. Probably it is true but maybe we could wait for next iteration.
        Hide
        kchung added a comment -

        @Alex Thanks. Several quick comments.

        1. Why do we need the interface Patch? Since 6902 and 7963 are totally different, there is nothing common except in names. It does not really make much sense to combine JsonPatch and JsonMergePatch into one interface.
        2. How about just have two concrete classes: JsonPatch and JsonMergePatch.
        3. We should include overloaded "apply" method for JsonArray and JsonObject.
        4. Maybe a static generatePatch (or just diff) method?
        Show
        kchung added a comment - @Alex Thanks. Several quick comments. Why do we need the interface Patch? Since 6902 and 7963 are totally different, there is nothing common except in names. It does not really make much sense to combine JsonPatch and JsonMergePatch into one interface. How about just have two concrete classes: JsonPatch and JsonMergePatch. We should include overloaded "apply" method for JsonArray and JsonObject. Maybe a static generatePatch (or just diff) method?
        Hide
        asotobu added a comment -

        I send you my first purpose for Json Patch API:

        /**
        * <p>{@code Patch} interface represents a common interface for applying patches on a {@link JsonStructure}.<p>
        * <p>A patch is a {@code JsonStructure} for expressing operations or modifications to a given JSON document.</p>
        **/
        public interface Patch {
        
          /**
          * <p>Apply this patch to a {@code JsonStructure}.</p>
          * @param target to apply the patch to.
          * @return the patched {@code JsonStructure}. Since a {@code JsonObject} or {@code JsonArray} is immutable,
          *         these operation returns a new JSON Object or array.
          */
          JsonStructure apply(JsonStructure target);
        
        }
        
        /**
        * <p>Implementation of JSON Patch described at <a href="https://tools.ietf.org/html/rfc6902">rfc 6902</a></p>
        * <p>JSON Patch is a format (identified by the media type "application/json-patch+json") for expressing a sequence of operations to apply to a target JSON document;
        * it is suitable for use with the HTTP PATCH method.</p>
        * <p>A JSON Patch document is a JSON document that represents an array of objects.
        * Each object represents a single operation to be applied to the target JSON document.</p>
        * <p>The following is an example JSON Patch document:</p>
        * <pre>
        *
        * [
        *  { "op": "test", "path": "/a/b/c", "value": "foo" },
        *  { "op": "remove", "path": "/a/b/c" },
        *  { "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] },
        *  { "op": "replace", "path": "/a/b/c", "value": 42 },
        *  { "op": "move", "from": "/a/b/c", "path": "/a/b/d" },
        *  { "op": "copy", "from": "/a/b/d", "path": "/a/b/e" }
        * ]
        * </pre>
        * <p> Operations are applied sequentially in the order they
        * appear in the array.  Each operation in the sequence is applied to
        * the target document; the resulting document becomes the target of the
        * next operation.  Evaluation continues until all operations are
        * successfully applied or until an error condition is encountered.
        * </p>
        **/
        public JsonPatch implements Patch {
        
          /**
          * <p>Creates a {@code JsonPatch} object.</p>
          * @param jsonPatch array structure expressing a sequence of operations to apply to a JSON document.
          *        This document follows <a href="https://tools.ietf.org/html/rfc6902">rfc6902</a> notation defined at <a href="https://tools.ietf.org/html/rfc6902#section-3">Section 3 Document Structure</a>.</p>
          **/
          public JsonPatch(JsonArray jsonPatch) {
        
          }
        
          /**
          * <p>Apply this json patch document to a {@code JsonStructure}.</p>
          * @param target to apply the patch to.
          * @return the patched {@code JsonStructure}. Since a {@code JsonObject} or {@code JsonArray} is immutable, these operation returns a new JSON Object or array.
          */
          public JsonStructure apply(JsonStructure target) {
        
          }
        
        }
        
        /**
        * <p>Implementation of JSON Merge Patch described at <a href="http://tools.ietf.org/html/rfc7386">rfc 7386</a></p>
        * <p>A JSON merge patch document describes changes to be made to a target
        * JSON document using a syntax that closely mimics the document being
        * modified.  Recipients of a merge patch document determine the exact
        * set of changes being requested by comparing the content of the
        * provided patch against the current content of the target document.
        * If the provided merge patch contains members that do not appear
        * within the target, those members are added.  If the target does
        * contain the member, the value is replaced.  Null values in the merge
        * patch are given special meaning to indicate the removal of existing
        * values in the target.
        * </p>
        **/
        public JsonMergePatch implements Patch {
        
          /**
          * <p>Creates a {@code JsonMergePatch} object</p>
          * @param jsonMergePatch JSON document that describes changes to be made to a target using syntax defined in <a href="http://tools.ietf.org/html/rfc7386">rfc7386.
          **/
          public JsonMergePatch(JsonObject jsonMergePatch) {
        
          }
        
          //...
        }
        
        Show
        asotobu added a comment - I send you my first purpose for Json Patch API: /** * <p>{@code Patch} interface represents a common interface for applying patches on a {@link JsonStructure}.<p> * <p>A patch is a {@code JsonStructure} for expressing operations or modifications to a given JSON document.</p> **/ public interface Patch { /** * <p>Apply this patch to a {@code JsonStructure}.</p> * @param target to apply the patch to. * @ return the patched {@code JsonStructure}. Since a {@code JsonObject} or {@code JsonArray} is immutable, * these operation returns a new JSON Object or array. */ JsonStructure apply(JsonStructure target); } /** * <p>Implementation of JSON Patch described at <a href= "https: //tools.ietf.org/html/rfc6902" >rfc 6902</a></p> * <p>JSON Patch is a format (identified by the media type "application/json-patch+json" ) for expressing a sequence of operations to apply to a target JSON document; * it is suitable for use with the HTTP PATCH method.</p> * <p>A JSON Patch document is a JSON document that represents an array of objects. * Each object represents a single operation to be applied to the target JSON document.</p> * <p>The following is an example JSON Patch document:</p> * <pre> * * [ * { "op" : "test" , "path" : "/a/b/c" , "value" : "foo" }, * { "op" : "remove" , "path" : "/a/b/c" }, * { "op" : "add" , "path" : "/a/b/c" , "value" : [ "foo" , "bar" ] }, * { "op" : "replace" , "path" : "/a/b/c" , "value" : 42 }, * { "op" : "move" , "from" : "/a/b/c" , "path" : "/a/b/d" }, * { "op" : "copy" , "from" : "/a/b/d" , "path" : "/a/b/e" } * ] * </pre> * <p> Operations are applied sequentially in the order they * appear in the array. Each operation in the sequence is applied to * the target document; the resulting document becomes the target of the * next operation. Evaluation continues until all operations are * successfully applied or until an error condition is encountered. * </p> **/ public JsonPatch implements Patch { /** * <p>Creates a {@code JsonPatch} object.</p> * @param jsonPatch array structure expressing a sequence of operations to apply to a JSON document. * This document follows <a href= "https: //tools.ietf.org/html/rfc6902" >rfc6902</a> notation defined at <a href= "https://tools.ietf.org/html/rfc6902#section-3" >Section 3 Document Structure</a>.</p> **/ public JsonPatch(JsonArray jsonPatch) { } /** * <p>Apply this json patch document to a {@code JsonStructure}.</p> * @param target to apply the patch to. * @ return the patched {@code JsonStructure}. Since a {@code JsonObject} or {@code JsonArray} is immutable, these operation returns a new JSON Object or array. */ public JsonStructure apply(JsonStructure target) { } } /** * <p>Implementation of JSON Merge Patch described at <a href= "http: //tools.ietf.org/html/rfc7386" >rfc 7386</a></p> * <p>A JSON merge patch document describes changes to be made to a target * JSON document using a syntax that closely mimics the document being * modified. Recipients of a merge patch document determine the exact * set of changes being requested by comparing the content of the * provided patch against the current content of the target document. * If the provided merge patch contains members that do not appear * within the target, those members are added. If the target does * contain the member, the value is replaced. Null values in the merge * patch are given special meaning to indicate the removal of existing * values in the target. * </p> **/ public JsonMergePatch implements Patch { /** * <p>Creates a {@code JsonMergePatch} object</p> * @param jsonMergePatch JSON document that describes changes to be made to a target using syntax defined in <a href= "http: //tools.ietf.org/html/rfc7386" >rfc7386. **/ public JsonMergePatch(JsonObject jsonMergePatch) { } //... }
        Hide
        kchung added a comment -

        Agreed that we should do both, at least we should not exclude either at first.

        In terms of implementation order, I also agree that JSON Pointer should be done first. In fact I believe we should tackle the editing or transformation operations first, because they are lower level operations that both JSON Pointer and JSON can build on. See https://java.net/jira/browse/JSON_PROCESSING_SPEC-67 for more details.

        Agreed also that JSON patch should include a diff function.

        Show
        kchung added a comment - Agreed that we should do both, at least we should not exclude either at first. In terms of implementation order, I also agree that JSON Pointer should be done first. In fact I believe we should tackle the editing or transformation operations first, because they are lower level operations that both JSON Pointer and JSON can build on. See https://java.net/jira/browse/JSON_PROCESSING_SPEC-67 for more details. Agreed also that JSON patch should include a diff function.
        Hide
        asotobu added a comment -

        As @mitemitreski said, having json pointer implemented, the hard work is done and we can offer support for both of them, maybe we can start with merge patch and then if we are on time we can implement patch as well, or we can define both at first.

        Show
        asotobu added a comment - As @mitemitreski said, having json pointer implemented, the hard work is done and we can offer support for both of them, maybe we can start with merge patch and then if we are on time we can implement patch as well, or we can define both at first.
        Hide
        mitemitreski added a comment -

        @kchung as you said https://tools.ietf.org/html/rfc7396 is the one that is a lot less verbose and it is more practical.
        In my book, this one should be given a higher priority.

        On the other hand, if we already have a JSON-Pointer as part of the spec they both make sense.

        Show
        mitemitreski added a comment - @kchung as you said https://tools.ietf.org/html/rfc7396 is the one that is a lot less verbose and it is more practical. In my book, this one should be given a higher priority. On the other hand, if we already have a JSON-Pointer as part of the spec they both make sense.
        Hide
        kchung added a comment - - edited

        Note there is another alternate spec for patching a JSON document: Json Merge Patch, rfc 7396

        This uses a diff patching, and is less verbose. There are some short-comings:

        1. It uses null for delete, so you cannot replace a value with null.
        2. It does not patch array entries, so you'll need to replace the whole array.

        Maybe we should consider supporting both.

        Show
        kchung added a comment - - edited Note there is another alternate spec for patching a JSON document: Json Merge Patch, rfc 7396 This uses a diff patching, and is less verbose. There are some short-comings: It uses null for delete, so you cannot replace a value with null. It does not patch array entries, so you'll need to replace the whole array. Maybe we should consider supporting both.

          People

          • Assignee:
            Unassigned
            Reporter:
            jitu
          • Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

            • Created:
              Updated: