java-object-diff

repository·master·Indexed 21 days ago

https://github.com/sqisher/java-object-diff

A Java library for finding and applying differences between Java objects. It generates a traversable DiffNode tree structure representing changes in nested objects, collections, and maps, allowing developers to inspect changes or patch objects using canonicalSet and canonicalUnset methods. The library features a configurable engine via ObjectDifferBuilder for customizing introspection, circular reference detection, and inclusion rules.

Tokens
5.6K
Snippets
17
Records
29
Agent score
75%

What's inside java-object-diff

  1. What is java-object-diff?

    master
    java-object-diff is a library designed to find differences between two Java objects. It generates a tree structure representing the differences between the objects and their children (including nested objects, collections, and maps). This tree can be traversed to extract information or to apply changes back to the underlying data structures using provided accessors.
  2. Understand the DiffNode tree structure

    master

    When you compare two objects, the library returns a DiffNode representing the root of a tree.

    • Traversal: You can traverse the tree nodes to find specific changes.
    • Information: Each node tells you exactly if and how a value differs from the base version.
    • Read/Write Access: Nodes provide accessors to read, write, or remove values from the underlying object instances, allowing you to apply the diff as a patch.
  3. Merge objects using the ObjectDiffer node setter methods

    master

    The java-object-diff library allows you to merge differences back into an object instance using the nodes returned by an ObjectDiffer.

    Every node in the object graph returned by the ObjectDiffer provides setter methods. You can use these methods to change the state of an underlying object instance, provided that the instance is of the same type as the objects being compared.

    Because merging requirements vary, the library does not provide a single universal merger, but instead provides the mechanism (the setter methods on nodes) to make implementing custom merging logic straightforward.

  4. Understand DiffNode and the object graph

    master

    A DiffNode represents an element in the object graph (such as a bean property, collection item, or map entry).

    Key characteristics:

    • Tree Structure: Every node has exactly one parent, except for the root node returned by the ObjectDiffer.
    • Data Access: Nodes provide methods to read and write values from/to the base and working objects, which is useful for visualization or merging changes.
    • NodePath: Each node has a unique NodePath identifying its location in the graph, which can be used for querying or applying configuration rules.
  5. Identify node locations with NodePath

    master

    A NodePath is a unique identifier for a DiffNode, composed of a sequence of Elements. Each element describes a transition, such as accessing a map entry, a list item, or a property getter. Every path starts with a special root element that references the objects passed to the ObjectDiffer.

    NodePath objects can be created using various static builder methods and are used to precisely query nodes or attach metadata/inclusion rules via configuration.

  6. Initialize a diffing operation with ObjectDifferBuilder

    master
    The ObjectDifferBuilder is the entry point for all diffing operations. It acts as a factory to create an ObjectDiffer instance and provides a configuration API to customize how objects are compared, introspected, and traversed. Use the builder to set up rules for inclusion, comparison strategies, and circular reference detection before calling the method to obtain the ObjectDiffer.
  7. Install java-object-diff via Maven or Gradle

    master

    To use java-object-diff in your project, add the following dependency to your build configuration file.

    ### Using with Maven
    
    ```xml
    <dependency>
        <groupId>de.danielbechler</groupId>
        <artifactId>java-object-diff</artifactId>
        <version>0.95</version>
    </dependency>

    Using with Gradle

    compile 'de.danielbechler:java-object-diff:0.95'
  8. Compare two Java objects using ObjectDifferBuilder

    master

    The core functionality of the library is to find differences between two objects and return a tree structure (DiffNode). You can generate a default differ using ObjectDifferBuilder.buildDefault() and then call .compare(workingObject, baseObject).

    The resulting DiffNode tree can be traversed to extract information or to apply changes (patches) back to the objects. Each node in the tree represents a property or collection item and describes how it differs from the base version.

    DiffNode root = ObjectDifferBuilder.buildDefault().compare(workingObject, baseObject);
  9. Use java-object-diff with Maven

    master

    To integrate java-object-diff into your Maven project, add the following dependency to your pom.xml file. This makes the library available for use in your Java code.

    <dependency>
    	<groupId>de.danielbechler</groupId>
    	<artifactId>java-object-diff</artifactId>
    	<version>0.95</version>
    </dependency>
  10. Create a diff between two objects

    master

    To compare two objects, use the ObjectDifferBuilder.buildDefault() method to create an ObjectDiffer instance, then call .compare(working, base) where working is the new state and base is the original state. This returns a DiffNode representing the root of the object graph.

    Key DiffNode properties:

    • hasChanges(): Returns true if the node or its children have changed.
    • childCount(): Returns the number of immediate children in the graph.
    • getState(): Returns the DiffNode.State (e.g., CHANGED).
    • getPath(): Returns the NodePath representing the location in the object graph.
    Map<String, String> working = Collections.singletonMap("item", "foo");
    Map<String, String> base = Collections.singletonMap("item", "bar");
    DiffNode diff = ObjectDifferBuilder.buildDefault().compare(working, base);
  11. Control node inclusion using @ObjectDiffProperty

    master

    You can control whether specific properties are included or excluded from a diff by applying the @ObjectDiffProperty annotation to the property or its access method.

    The TypePropertyAnnotationInclusionResolver (used internally by the library) evaluates these annotations to determine the Inclusion status of a node.

    Key behaviors:

    • Explicit Inclusion/Exclusion: If @ObjectDiffProperty(inclusion = Inclusion.INCLUDED) or @ObjectDiffProperty(inclusion = Inclusion.EXCLUDED) is present, that setting is respected.
    • Implicit Exclusion: If @ObjectDiffProperty(excluded = true) is used, the property is excluded.
    • Sibling Logic: If a sibling property in the same object is explicitly marked as INCLUDED, other properties that do not have their own explicit inclusion/exclusion annotations will default to EXCLUDED to maintain a strict inclusion model.
  12. Caveats and limitations of java-object-diff

    master

    Before using the library, be aware of the following limitations:

    • Introspection: For non-primitive and non-collection types, the library uses standard JavaBean introspection. This requires your objects to have getters and setters. If you only need to read differences (not apply patches), setters are not required. You can implement custom introspectors via the configuration API if JavaBean introspection is insufficient.
    • Ordered Lists: Ordered lists (like ArrayList) are currently treated as Sets. This means the library may not properly handle differences in ordered collections or multiple occurrences of the same value. If your use case requires strict ordering or handling duplicate values in collections, you may need to implement custom logic.