This library seems to do the trick: google-diff-match-patch. It can create a patch string from differences and allow to reapply the patch.

edit: Another solution might be to https://code.google.com/p/java-diff-utils/

Answer from bernardn on Stack Overflow
🌐
GitHub
github.com › java-diff-utils › java-diff-utils › wiki › Examples
Examples · java-diff-utils/java-diff-utils Wiki · GitHub
The difference computing part is generified. Therefore a List of objects could be used. Here is an example, that demonstrates a patch for an Integer List.
Author: java-diff-utils
🌐
Javers
javers.org › documentation › diff-examples
Diff Examples — JaVers Documentation
Diff: * changes in Employee/Manager One : - 'subordinates' collection changes : 0. 'Employee/Great Developer' removed * changes in Employee/Great Developer : - 'boss' reference changed: 'Employee/Manager One' -> 'Employee/Manager Second' * changes in Employee/Manager Second : - 'subordinates' collection changes : 0. 'Employee/Great Developer' added · This example shows how to find a diff between two objects of the Address class.
🌐
Baeldung
baeldung.com › home › java › guide to java diff utils
Guide to Java Diff Utils | Baeldung
November 12, 2025 - This tutorial demonstrates how to use the Java Diff Utils library to perform various tasks, including comparing text content line-by-line, generating unified diffs, applying patches to restore or modify content, and building side-by-side diff views.
🌐
DeepWiki
deepwiki.com › java-diff-utils › java-diff-utils › 2.2-quick-start-examples
Quick Start Examples | java-diff-utils/java-diff-utils | DeepWiki
May 30, 2025 - This page provides simple, practical examples demonstrating the core functionality of java-diff-utils. These examples show how to compute differences between sequences, apply patches, and work with va
Top answer
1 of 8
56

Might be a little late, but I was in the same situation like you and ended up creating my own library for exactly your use-case. Since I was forced to come up with a solution myself, I decided to release it on Github, to spare others the hard work. You can find it here: https://github.com/SQiShER/java-object-diff

--- Edit ---

Here is a little usage example based on the OPs code:

SomeClass a = new SomeClass();
SomeClass b = new SomeClass();

a.setProp1("A");
a.setProp2("X");

b.setProp1("B");
b.setProp2("X");

DiffNode diff = ObjectDifferBuilder.buildDefault().compare(a, b);

assert diff.hasChanges();
assert diff.childCount() == 1;
assert diff.getChild('prop1').getState() == DiffNode.State.CHANGED;
2 of 8
54

http://javers.org is library that does exacly what you need: has methods like compare(Object leftGraph, Object rightGraph) returning the Diff object. Diff contains a list of changes (ReferenceChange, ValueChange, PropertyChange) e.g.

given:
DummyUser user =  dummyUser("id").withSex(FEMALE).build();
DummyUser user2 = dummyUser("id").withSex(MALE).build();
Javers javers = JaversTestBuilder.newInstance()

when:
Diff diff = javers.compare(user, user2)

then:
diff.changes.size() == 1
ValueChange change = diff.changes[0]
change.leftValue == FEMALE
change.rightValue == MALE

It can handle cycles in graphs.

In addition you can get Snapshot of any graph object. Javers has JSON serializers and deserializers to snapshot, and changes so you can easily save them in database. With this library you can easily implement a module for auditing.

Find elsewhere
🌐
Google Code
code.google.com › archive › p › java-diff-utils
Google Code Archive - Long-term storage for Google Code Project Hosting.
Archive · Skip to content · The Google Code Archive requires JavaScript to be enabled in your browser · Google · About Google · Privacy · Terms
🌐
Readthedocs
java-object-diff.readthedocs.io › en › latest › getting-started
Getting Started - java-object-diff Documentation
That's the node representing the map entry with key "item". And since its value differs between the base and the working object, getState returns the state CHANGED. In this example we query the child node directly via NodePath, but in most cases you probably just want to iterate over all changes.
🌐
Java Code Geeks
javacodegeeks.com › home › core java
Getting Started with Java Diff Utils - Java Code Geeks
July 14, 2025 - The core class used is DiffUtils, which computes a Patch object consisting of a list of changes (also called deltas) between two lists. The example below compares two versions of a list of strings representing lines in a document.
🌐
Diffguru
diffguru.com › java
Compare Java Code Online | Java Diff Checker – Diff Guru
Compare Java source code online using our Java diff checker and highlight differences line by line. Easily review changes in classes, methods, or imports and merge Java code updates between versions. ... Paste code in both panels or click Load Example to see a Java diff in action.
🌐
Readthedocs
java-object-diff.readthedocs.io
java-object-diff Documentation
Sometimes you need to figure out, how one version of an object differs from another one. One of the simplest solutions that'll cross your mind is most certainly to use reflection to scan the object for fields or getters and use them to compare the values of the different object instances.
🌐
GitHub
github.com › jpace › java-diff
GitHub - jpace/java-diff: Diff algorithm in Java · GitHub
Diff algorithm in Java. Contribute to jpace/java-diff development by creating an account on GitHub.
Starred by 10 users
Forked by 5 users
Languages: Java
🌐
GitHub
github.com › SQiShER › java-object-diff
GitHub - SQiShER/java-object-diff: Library to diff and merge Java objects with ease · GitHub
Introspection of values other than primitives and collection types is curently done via standard JavaBean introspection, which requires your objects to provide getters and setters for their properties. However, you don't need to provide setters, if you don't need write access to the properties (e.g. you don't want to apply the diff as a patch.)
Starred by 970 users
Forked by 176 users
Languages: Java 53.4% | Groovy 46.6%
🌐
Bmsi
bmsi.com › java › Diff.java
/ $Log: Diff.java,v $ Revision 1.7 2009/01/19 03:05:26 stuart
Each element of the arrays is translated to an "equivalence number" based on the result of <code>equals</code>. The original Object arrays are no longer needed for computing the differences. They will be needed again later to print the results of the comparison as an edit script, if desired.
Top answer
1 of 2
4
private static final String NL = "\n";

I don't think that NL is a particularly good name. Generally it is not needed either. For a system utility, I'd go for System.lineSeparator().

public static void main(String[] args) {

There is a lot of duplicate code in the main method because reading the files is parallelized. Reading the files can be separated out into a a single method so that the duplicate code is not required (in this case just calling readLines would do the same thing I suppose).

if (args.length != 2) {
    return;
}

I'd at least return a message to the user what kind of arguments are required, and then use System.exit() with a return/status code. You do this later on, strangely enough, so symmetry is also missing.

    BufferedReader oldSourceBufferedReader = null;
    BufferedReader newSourceBufferedReader = null;

    try  {
        oldSourceBufferedReader = 
                new BufferedReader(new FileReader(oldSourceFile));

I'd expect try-with-resources to be used here, it would remove a lot of unnecessary code, and would avoid any null handling.

    return printDiff(matrix, oldSourceLines, newSourceLines);

printDiff is a bad name, as the method doesn't actually print anything.

    int[][] matrix = new int[oldSourceLines.size() + 1]
                            [newSourceLines.size() + 1];

Here you can see clearly what happens, but it is unclear from the code why the matrix has the calculated size. Whenever that happens you need code comments.

Furthermore, it seems your matrix is over-dimensioned in both directions by one, as you only index i - 1 and j - 1.

 for (int i = 1; i <= oldSourceLines.size(); ++i) {

Nah, you should always try and use zero based indexing. Whenever you need one more, you can add it when needed. Subtraction always confuses things.

The same goes for ++i. Sometimes people things that ++i is faster, but it is no different than i++ and less clear.

private static void printDiff(StringBuilder stringBuilder,
                              int[][] matrix,
                              List<String> oldSourceLines,
                              List<String> newSourceLines,
                              int i, 
                              int j) {

This is a recursive method, and recursive methods should always be documented. Furthermore, for recursive methods, it is pretty important to make it very clear when the end is reached. I would recommend to check for a negative i and j to quickly return. Also, to make the method more readable, you could simply change i and / or j and then perform the recursion at the end.


Design. Yes, you always need a specific class that you instantiate, so that you can use it from other code without having to use main.

Currently the used algorithm is not described. This is vital for maintainability. Always document the algorithm and / or provide a reference to the method used.

When creating a diff I would strongly suggest to make sure that you don't need to read entire files in memory. Files can be huge after all. Otherwise you may want to limit the file size

2 of 2
5

Rather than your readLine() loops prefer Files.readAllLines(). This has the side-effect of fixing a problem where your BufferedReader instances are not protected within a try-with-resources block (since no readers will be necessary).

Consider writing an error message if the number of CLI arguments is incorrect. You should probably also System.exit(1); rather than only return, as the latter will make it look like the program succeeded.

printDiff could be better-named as formatDiff since it doesn't actually print.

Otherwise seems fine (though I have not critically examined the inner diff algorithm).

🌐
Java Tips
javatips.net › api › javers-master › javers-core › src › main › java › org › javers › core › diff › Diff.java
Diff.java example
* <br><br> * * @author bartosz walacik */ public class Diff implements Serializable { private final List<Change> changes; Diff(List<Change> changes) { this.changes = changes; } /** * Selects new, removed or changed objects * * @throws JaversException AFFECTED_CDO_IS_NOT_AVAILABLE if diff is restored from a repository */ public <C extends Change> List getObjectsByChangeType(final Class<C> type) { argumentIsNotNull(type); return Lists.transform(getChangesByType(type), input -> input.getAffectedObject().<JaversException>orElseThrow(() -> new JaversException(AFFECTED_CDO_IS_NOT_AVAILABLE))); } /**