Jardiff is a command-line tool for comparing the contents of JAR files and directories. It provides detailed, line-based diffs of class files and resources, making it easy to spot changes between builds, releases, or different versions of Java/Kotlin projects.
Note
This project is not affiliated with Lightbend or the original jardiff project.
While lightbend-labs/jardiff and this tool share the same name and similar goals, they have different features:
The lightbend-labs/jardiff focuses on Scala projects, and it has a some useful flags to tweak the bytecode output (ordering, suppress private members). This tool also has a mode to create a git repository to leverage git diff capabilities.
While this bric3/jardiff tool offers a more versatile tool to inspect class differences
- Additional to the usual diff output, it provides statistics (
--stat) and status (--status) modes similar to git diff/status - Supports class extension coalescing, in case classes are renamed to other extensions like
.bin,.clazz, etc. - Various text representation modes for class files
- Flexible glob pattern filtering for including/excluding files
- Offers limited support for non-binary text files
Example output in default mode:
--- foo/bar/qux/Baz.class
+++ foo/bar/qux/Baz.class
@@ -6,1548 +6,17 @@
// access flags 0x9
public static create()Lfoo/bar/ZuulMatcher;
NEW foo/bar/ZuulMatcher
DUP
- LDC 15
+ LDC 3
ANEWARRAY foo/bar/Zuul
DUP
LDC 0
NEW foo/bar/Zuul
DUP
- LDC 14
- ANEWARRAY java/lang/String
- DUP
LDC 0
- LDC "foo.bar.qux.T:18"
- AASTORE
- DUP
- LDC 1
- LDC "foo.bar.qux.U:33"
- AASTORE
- DUP
- LDC 2
- LDC "foo.bar.qux.V:49"
- AASTORE
- DUP
- LDC 3
- LDC "foo.bar.qux.W:68"
- AASTORE
- DUP
...
+ LDC 2
NEW foo/bar/Zuul
DUP
LDC 0
ANEWARRAY java/lang/StringOr with the --stat mode
D foo/bar/qux/Zuul.class
D foo/bar/qux/Zig.class
M foo/bar/qux/Baz.class
foo/bar/qux/Zorg.class
Or with the --status mode
foo/bar/qux/Zuul.class | 42 ++++++++++++++++++++++++++++++++----------
foo/bar/qux/Zig.class | 1 -
foo/bar/qux/Baz.class | 34 ++++++++++++++++++++++------------
foo/bar/qux/Zorg.class | 0
4 files changed, 54 insertions(+), 23 deletions(-)
When output piped to delta, it looks like this:
Other tools didn't have the feature I wanted, or they were impractical to use, so I made my own.
- Compare JARs and directories recursively
- Line-based diffs for each files
- Class file comparison using different strategy to produce text
- ASM's Textify (default)
- Class outline (version, is kotlin/groovy class, synthetic or bridge members)
- Class File Version only
- Binary diff as sha-1 hashes
- Include glob patterns (for the relative paths inside the jars/directories)
- Exclude glob patterns (for the relative paths inside the jars/directories)
- Supports
--exit-codefor CI/CD pipelines
Features planned for future releases... :
- Ignoring debug information in class files (like line numbers, local variable names, etc.)
- Append Koltin/Scala/Groovy detection to regular class text output
- Sort members alphabetically
- Replace ASM by the Class file API (Need JDK 24+)
- Better terminal integration, ideas: pager support, colors configuration, auto-detection of
delta, etc. (Might need FFM, need JDK 22+)
Caution
This tool needs a JDK11 to build and run. Example with mise
$ mise exec java@corretto-11 -- java -jar jardiff-0.1.0-SNAPSHOT.jarTip
The jar on the Github release is an executable jar, so you can run it directly with ./jardiff-0.1.0-SNAPSHOT.jar {left} {right} after downloading it (chmoding it executable as needed).
Build it ./gradlew build, then run it:
$ jardiff --help
Usage: jardiff [-hVv] [--exit-code] [--class-text-producer=<tool>]
[--color=<when>] [-c=<extension>[,<extension>...]]... [-e=<glob>
[,<glob>...]]... [-i=<glob>[,<glob>...]]... [--status | --stat]
<left> <right>
Compares two JAR files or directories and reports differences.
<left> The JAR file or directory to compare.
<right> The JAR file or directory to compare.
-c, --class-exts, --coalesce-classe-exts=<extension>[,<extension>...]
Coalesce class files with the given extensions, in
addition to the usual 'class', i.e. makes classes
named 'Foo.class' and 'Foo.bin' aliased to the same
file same entry. Also this enables the file to be
compared on bytecode level Takes a comma separated
list, e.g. 'classdata' or 'raw,bin,clazz'.
--class-text-producer=<tool>
Tool used to produce class text, possible values:
asm-textifier, class-file-version, class-outline
Default: 'asm-textifier'
--color=<when> Control when to use color output:
always, auto, never
Default: 'auto'
-e, --exclude=<glob>[,<glob>...]
Glob exclude patterns (comma separated), e.g.
'**/raw*/**', or '**/*.bin'.
--exit-code Make jardiff exit with codes similar to diff(1).
That is, it exits with 1 if there were differences
and 0 means no differences.
-h, --help Show this help message and exit.
-i, --include=<glob>[,<glob>...]
Glob include patterns (comma separated), e.g.
'**/raw*/**', or '**/*.bin'.
--stat Show statistics output (like 'git diff --stat').
Displays file-by-file statistics with
additions/deletions.
--status Show short status output (like 'git status --short').
Displays two-column XY status for each file.
-v Specify multiple -v options to increase verbosity.
For example, '-v -v' or '-vv'.
-V, --version Print version information and exit.Tip
Use shell features, e.g. in Bash, ZSH instead of typing twice long folders use the brace expansion :
$ java -jar jardiff-0.1.0-SNAPSHOT.jar /Users/brice.dutheil/path/to/repositories/project{-original,-with-changes}/submodule/submodule/submodule/build/classes/java/mainAlso, you can run it from Gradle:
$ ./gradlew run --args="{left} {right}"{left}and{right}can be paths to JAR files or directories.- The tool outputs a summary and detailed diff of all differing files.
To build the project:
$ ./gradlew build- Kotlin
- Picocli
- ASM
- java-diff-utils
- Byte Buddy
- Apache Tika (for charset detection)
Copyright 2025 Brice Dutheil
Unless otherwise noted, all components are licenced under the Mozilla Public License Version 2.0.
