zjsonpatch

repository·master·Indexed 20 days ago

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

A Java implementation of RFC 6902 JSON Patch with support for extended JSON pointers. It enables developers to find differences between JSON documents and apply those transformations to reduce network bandwidth in HTTP PATCH operations. The library supports Jackson 2.x and 3.x, providing specific APIs (JsonDiff/JsonPatch and Jackson3JsonDiff/Jackson3JsonPatch) for each version. Features include standard patch operations (add, remove, replace, move, copy), in-place mutation, and key-based array element referencing.

Tokens
2.1K
Snippets
8
Records
10
Agent score
20%

What's inside zjsonpatch

  1. Use Extended JSON Pointers for array elements

    master

    The library supports extended JSON pointers that allow referencing array elements via a unique key instead of a numeric index. This is useful for targeting specific objects within an array.

    Syntax: /array/key=value/path (e.g., /a/id=2/data)

    Requirements & Warnings:

    • You must ensure the field used as a reference key is unique.
    • If multiple elements match the key-value pair, the first matching element is selected.
    • Key-based referencing can be slow for large arrays; use standard index-based pointers for performance in those cases.
    // Example: Accessing data in an array of objects via ID
    // JSON: {"a": [{"id": 1, "data": "abc"}, {"id": 2, "data": "def"}]}
    // Path: /a/id=2/data
    // Result: "def"
  2. How to select between Jackson 2.x and 3.x APIs

    master

    Because Jackson 2.x and 3.x use incompatible package structures, zjsonpatch provides two distinct sets of public APIs. You must use the class set that matches the Jackson version present on your classpath:

    • For Jackson 2.x: Use JsonDiff and JsonPatch.
    • For Jackson 3.x: Use Jackson3JsonDiff and Jackson3JsonPatch.

    The library internally detects the specific JsonNode types to ensure correct operation even in mixed-version scenarios.

  3. Migrate to zjsonpatch 0.6.0 or later

    master

    In version 0.6.0, Jackson dependencies were changed from transitive to optional. If your project relied on zjsonpatch to provide Jackson, you will encounter compilation errors. You must now explicitly add jackson-databind to your pom.xml to resolve this.

    <!-- Add this to your pom.xml dependencies -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.18.2</version>
    </dependency>
  4. Install zjsonpatch via Maven

    master

    Add the following dependencies to your pom.xml. Note that starting from version 0.6.0, Jackson dependencies are optional and must be explicitly declared. You must choose the configuration that matches your project's Jackson version.

    For Jackson 2.x support

    <dependency>
        <groupId>io.github.vishwakarma</groupId>
        <artifactId>zjsonpatch</artifactId>
        <version>{version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.18.2</version>
    </dependency>

    For Jackson 3.x support

    <dependency>
        <groupId>io.github.vishwakarma</groupId>
        <artifactId>zjsonpatch</artifactId>
        <version>{version}</version>
    </dependency>
    <dependency>
        <groupId>tools.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>3.0.0</version>
    </dependency>

    For both Jackson 2.x and 3.x support

    <dependency>
        <groupId>io.github.vishwakarma</groupId>
        <artifactId>zjsonpatch</artifactId>
        <version>{version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.18.2</version>
    </dependency>
    <dependency>
        <groupId>tools.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>3.0.0</version>
    </dependency>
    <!-- Example for Jackson 2.x -->
    <dependency>
        <groupId>io.github.vishwakarma</groupId>
        <artifactId>zjsonpatch</artifactId>
        <version>{version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.18.2</version>
    </dependency>
  5. Disable MOVE and COPY operations in diffs

    master

    By default, the library optimizes diffs by compacting move and remove operations into Move operations. To prevent this optimization and return standard operations, use DiffFlags.dontNormalizeOpIntoMoveAndCopy().

    ### Jackson 2.x API
    EnumSet<DiffFlags> flags = DiffFlags.dontNormalizeOpIntoMoveAndCopy().clone();
    JsonNode patch = JsonDiff.asJson(JsonNode source, JsonNode target, flags);
    
    ### Jackson 3.x API
    EnumSet<DiffFlags> flags = DiffFlags.dontNormalizeOpIntoMoveAndCopy().clone();
    JsonNode patch = Jackson3JsonDiff.asJson(JsonNode source, JsonNode target, flags);
  6. Apply a JSON Patch in-place

    master

    Mutate the source JSON document directly by applying the patch. This is more memory-efficient than .apply() but modifies the original object.

    Limitations: This is an extension to RFC 6902 and does not support operations that require the source document to be fully changed in place (due to Jackson mutability constraints). The following operations are not supported for in-place application:

    • remove with an empty or root path
    • replace with an empty or root path
    • move, add, or copy targeting an empty or root path
    ### Jackson 2.x API
    JsonPatch.applyInPlace(JsonNode patch, JsonNode source);
    
    ### Jackson 3.x API
    Jackson3JsonPatch.applyInPlace(JsonNode patch, JsonNode source);
  7. Apply a JSON Patch to a document

    master

    Apply a generated patch to a source JSON document to produce a target document.

    Note: The standard .apply() method performs the operation on a clone of the source, meaning the original source object remains unmodified.

    ### Jackson 2.x API
    JsonNode target = JsonPatch.apply(JsonNode patch, JsonNode source);
    
    ### Jackson 3.x API
    JsonNode target = Jackson3JsonPatch.apply(JsonNode patch, JsonNode source);
  8. Obtain a JSON Diff as a patch

    master

    Compute a JSON patch that, when applied to a source document, will transform it into the target document. Both source and target must be valid JSON objects, arrays, or values.

    Supported operations in the generated patch include add, remove, replace, move, and copy.

    ### Jackson 2.x API
    JsonNode patch = JsonDiff.asJson(JsonNode source, JsonNode target)
    
    ### Jackson 3.x API
    JsonNode patch = Jackson3JsonDiff.asJson(JsonNode source, JsonNode target)
  9. Generate a Diff using Diff.generateDiff()

    master

    The Diff class provides static factory methods to create individual JSON Patch operations. These operations represent changes like replace, add, remove, move, or copy as defined in RFC 6902. Note that while the class is package-private in this file, it is the primary structure used to represent a single patch operation within the library.

    // Example of generating a replace operation
    Diff diff = Diff.generateDiff(
        Operation.REPLACE, 
        path, 
        targetValue
    );
    
    // Example of generating a replace operation with source value
    Diff diffWithSource = Diff.generateDiff(
        Operation.REPLACE, 
        path, 
        sourceValue, 
        targetValue
    );
  10. Inspect Diff operation details

    master

    Once a Diff object is created, you can inspect the details of the patch operation using the following methods:

    • getOperation(): Returns the type of operation (e.g., add, remove, replace, move, copy).
    • getPath(): Returns the AbstractJsonPointer representing the location of the operation.
    • getValue(): Returns the JsonNodeWrapper containing the value associated with the operation (used for add and replace).
    • getSrcValue(): Returns the JsonNodeWrapper containing the original value (used specifically in replace operations).
    • getToPath(): Returns the AbstractJsonPointer destination (used specifically for move operations).