Java Diff Utils Guide: Compare Text, Generate Patches, and Visualize Changes

This tutorial introduces Java Diff Utils, a lightweight open-source library for computing text differences, showing how to set it up in a Spring Boot project, compare string lists, generate unified diffs, apply patches, and create side-by-side visualizations for robust version-control and change-tracking in Java applications.

Cognitive Technology Team
Cognitive Technology Team
Cognitive Technology Team
Java Diff Utils Guide: Compare Text, Generate Patches, and Visualize Changes

1. Overview

In modern software development, tracking and visualizing changes between file or content versions is essential. Java Diff Utils (https://java-diff-utils.github.io/java-diff-utils/) provides a popular way to achieve this in Java.

This tutorial demonstrates how to use the Java Diff Utils library to compare text line‑by‑line, generate unified diffs, apply patches, and build side‑by‑side diff views.

2. Understanding Java Diff Utils and Its Main Advantages

Java Diff Utils is a lightweight, powerful library for computing differences between text data. It supports character‑level and line‑level comparison and can generate unified diff output.

It is commonly used in version‑control systems and can convert one version of data to another via patches. The tool offers many classes and methods that simplify the comparison process.

Main advantages:

Simplicity : Clean, intuitive API with static utility methods.

Extensibility : Easy integration with Spring Boot services and controllers.

Cross‑platform : Works on any OS that supports Java.

Open source : Free to use and modify under the Apache license.

These capabilities make Java Diff Utils an ideal choice for reliable text comparison in Java applications.

3. Setting Up Diff Utils

First, create a simple Spring Boot Maven project using Spring Initializr.

Although you can use Java Diff Utils in a plain Java project by manually managing JARs, using Spring Boot and Maven handles dependencies automatically via pom.xml, reducing setup time and ensuring consistency across environments.

Add the Java Diff Utils dependency to pom.xml:

<dependency>
  <groupId>io.github.java-diff-utils</groupId>
  <artifactId>java-diff-utils</artifactId>
  <version>4.12</version>
</dependency>

After this configuration, Maven will provide the correct version of Java Diff Utils at compile and runtime.

You can now use core classes such as DiffUtils, Patch, and UnifiedDiffUtils, which are designed as static utility methods and require no explicit instantiation.

4. Using Diff Utils in Java

This section builds basic components to demonstrate core use cases: comparing lists, generating unified diffs, applying patches, and creating side‑by‑side views.

4.1 Comparing String Lists

We create a utility class TextComparatorUtil that compares two lists of strings and returns a Patch<String> representing the differences.

class TextComparatorUtil {
    public static Patch<String> compare(List<String> original, List<String> revised) {
        return DiffUtils.diff(original, revised);
    }
}

Unit test verifies that the utility detects changes correctly:

@Test
void givenDifferentLines_whenCompared_thenDetectsChanges() {
    var original = List.of("A", "B", "C");
    var revised = List.of("A", "B", "D");
    var patch = TextComparatorUtil.compare(original, revised);
    assertEquals(1, patch.getDeltas().size());
    assertEquals("C", patch.getDeltas().get(0).getSource().getLines().get(0));
    assertEquals("D", patch.getDeltas().get(0).getTarget().getLines().get(0));
}

4.2 Generating Unified Diffs

Class UnifiedDiffGeneratorUtil generates a unified diff (standard patch format) for two string lists.

class UnifiedDiffGeneratorUtil {
    public static List<String> generate(List<String> original, List<String> revised, String fileName) {
        var patch = DiffUtils.diff(original, revised);
        return UnifiedDiffUtils.generateUnifiedDiff(fileName, fileName + ".new", original, patch, 3);
    }
}

Unit test ensures the generated diff highlights modified lines:

@Test
void givenModifiedText_whenUnifiedDiffGenerated_thenContainsExpectedChanges() {
    var original = List.of("x", "y", "z");
    var revised = List.of("x", "y-modified", "z");
    var diff = UnifiedDiffGeneratorUtil.generate(original, revised, "test.txt");
    assertTrue(diff.stream().anyMatch(line -> line.contains("-y")));
    assertTrue(diff.stream().anyMatch(line -> line.contains("+y-modified")));
}

4.3 Applying Patches

Class PatchUtil computes a patch and applies it to the original list, returning the updated content.

class PatchUtil {
    public static List<String> apply(List<String> original, List<String> revised) throws PatchFailedException {
        var patch = DiffUtils.diff(original, revised);
        return DiffUtils.patch(original, patch);
    }
}

Unit test confirms that applying the patch yields the revised list:

@Test
void givenPatch_whenApplied_thenMatchesRevised() throws PatchFailedException {
    var original = List.of("alpha", "beta", "gamma");
    var revised = List.of("alpha", "beta-updated", "gamma");
    var result = PatchUtil.apply(original, revised);
    assertEquals(revised, result);
}

4.4 Building a Side‑by‑Side View

Class SideBySideViewUtil logs each delta’s type, original lines, and revised lines, providing a readable side‑by‑side comparison.

public class SideBySideViewUtil {
    private static final Logger logger = Logger.getLogger(SideBySideViewUtil.class.getName());
    public static void display(List<String> original, List<String> revised) {
        var patch = DiffUtils.diff(original, revised);
        patch.getDeltas().forEach(delta -> {
            logger.log(Level.INFO, "Change: " + delta.getType());
            logger.log(Level.INFO, "Original: " + delta.getSource().getLines());
            logger.log(Level.INFO, "Revised: " + delta.getTarget().getLines());
        });
    }
}

A test verifies that calling SideBySideViewUtil.display() with different lists does not throw an exception.

@Test
void givenDifferentLists_whenDisplayCalled_thenNoExceptionThrown() {
    List<String> original = List.of("line1", "line2", "line3");
    List<String> revised = List.of("line1", "line2-modified", "line3", "line4");
    SideBySideViewUtil.display(original, revised);
}

5. Conclusion

This article explored Java Diff Utils and its capabilities. It provides a flexible, open‑source solution for comparing text data in Java applications, from basic line differences to full unified diff generation and patch application, making it a foundational tool for building robust version‑control or change‑tracking systems.

With minimal configuration and readable output, Java Diff Utils is essential for developers working on versioned data, collaborative editing tools, or file‑monitoring systems.

unit testingPatchspring-bootdiff-utilstext comparison
Cognitive Technology Team
Written by

Cognitive Technology Team

Cognitive Technology Team regularly delivers the latest IT news, original content, programming tutorials and experience sharing, with daily perks awaiting you.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.