Library / SDK
siom79/japicmp avatar
siom79/japicmp

japicmp compares two jar archives and tells you what broke

Comparison of two versions of a jar archive

779 stars115 forksJavaApache-2.0

At a glance

What is it?
japicmp reads two jar archives, works out what changed in the public API, and separates binary compatible changes from source incompatible ones. It ships as a command line tool, a Maven plugin, an Ant task, a library and now an MCP server, and it inspects class files with javassist so it does not need your dependencies on the classpath.
Who is it for?
japicmp suits a Java team that ships a library and needs to know whether a new release breaks its consumers, since it gives a class by class compatibility verdict and a semantic versioning recommendation without asking you to assemble a classpath. It is not a general artifact differ, and it deliberately does not compare configuration files or other artifact types, because the project says a generic implementation would compromise on performance and usability.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 7 days ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem it was built for

japicmp is a tool to compare two versions of a jar archive, and the motivation section states the problem plainly. Every time you release a new version of a library or a product, you have to tell your clients or customers what has changed compared to the last release, and without the right tooling that task is tedious and error-prone.

The tool works out the differences between the class files in two jar archives. That is a narrower job than it sounds, and the narrowness is the design. The project says the goal is to provide a fast and easy to use API comparison for Java, and that it does not aim to integrate change tracking of other artifact types such as configuration files, because a generic implementation would mean compromises in performance and ease of usage.

The performance figure the README gives is the argument for the restriction. japicmp compares two archives of about 1700 classes each in less than one second, which is what makes it cheap enough to run inside every build rather than as an occasional manual check.

The licence is Apache-2.0, the project is written in Java, and the topics are api-documentation, api-management, change-management, change-tracker and comparison. The last push was on 2026-10-16, with the newest releases being japicmp-base-0.26.5 on 2026-10-16, 0.26.3 on 2026-10-03 and 0.26.2 on 2026-09-03.

The command line, and the library underneath it

The tool is a jar with dependencies bundled, and the invocation names the two archives explicitly:

``` bash java -jar japicmp-0.26.5-jar-with-dependencies.jar -n new-version.jar -o old-version.jar

code

It can also be used as a library, which is the route for anything that needs to run inside another program:

java JarArchiveComparatorOptions comparatorOptions = new JarArchiveComparatorOptions(); JarArchiveComparator jarArchiveComparator = new JarArchiveComparator(comparatorOptions); List<JApiClass> jApiClasses = jarArchiveComparator.compare(oldArchives, newArchives); ```

The result type is a list of JApiClass objects, one per compared class, so a caller can walk the model programmatically rather than parse text output.

Differences are printed on the command line in a simple diff format by default, and can optionally be written as Markdown, XML or an HTML file. The three output formats matter for build integration, because the HTML one is what a release process can publish and the XML one is what a quality dashboard consumes.

The package is on Maven Central under the group com.github.siom79.japicmp and the artifact japicmp, and the dependency block in the README pins the same 0.26.5 version.

Javassist instead of reflection, and why that matters

The most interesting design decision in the project is stated in the motivation section and is easy to miss.

japicmp does not use the Java Reflection API to compute the differences, because using reflection makes it necessary to have all the classes the jar under investigation depends on available on the classpath. To avoid having to include all those dependencies, which can be a lot of work for bigger applications, the library uses javassist to inspect the class files instead.

The consequence is that you only have to provide the two jar archives on the command line, and eventually libraries that contain classes or interfaces you have extended or implemented. For a comparison tool whose job is to check whether release N is safe for people who depend on release N minus 1, that is the whole game: the dependencies are precisely what you do not want to resolve.

The approach also detects changes in instrumented and generated classes, and it can evaluate changes in class file attributes such as synthetic, or in annotations. The annotation support is what makes the tool suitable for annotation based APIs like JAXB, JPA and JAX-RS, where the behaviour of a method depends on annotations as much as on its signature.

The trade is that you are reading bytecode rather than a loaded model of the class, so anything that depends on runtime behaviour of the code is out of reach. What you get is the API surface, which is what the compatibility question is actually about.

Compatibility, semantic versioning and the serializable case

japicmp differentiates between source compatible and binary compatible changes, following the Java Language Specification and the OpenJDK wiki on kinds of compatibility, and all changes between all classes, methods and fields are compared.

Several defaults shape what you see, and they are worth knowing before you trust a clean result.

Private and package protected classes and class members are not compared by default. The access modifier of the classes and members to be compared can be set to public, protected, package or private, so if your library's API includes package protected types that consumers extend, the default configuration is hiding them from you.

All classes are tracked by default, and specific packages, classes, methods or fields can be excluded or explicitly included, with inclusion and exclusion also possible based on annotations. Synthetic classes and members, for instance bridge methods, are hidden by default and can be listed with the --include-synthetic option.

The --semantic-versioning option tells you which part of the version you have to increment to follow semantic versioning, which turns the report into a release decision rather than a diff. And if a class is serializable, the changes are evaluated against the Java Object Serialization Specification, so a serialVersionUID-adjacent change is flagged rather than missed.

The Maven plugin, the Ant task and the build integration

The Maven plugin is the route most teams take, because it compares the artifact you just built against an older version from the repository and runs as part of the verify phase.

``` xml <plugin> <groupId>com.github.siom79.japicmp</groupId> <artifactId>japicmp-maven-plugin</artifactId> <version>0.26.5</version> <configuration> <oldVersion> <dependency> <groupId>japicmp</groupId> <artifactId>japicmp-test-v1</artifactId> <version>${oldversion}</version> <type>jar</type> </dependency> </oldVersion> <newVersion> <file> <path>${project.build.directory}/${project.artifactId}-${project.version}.${project.packaging}</path> </file> </newVersion> <parameter> <!-- see documentation --> </parameter> </configuration> <executions> <execution> <phase>verify</phase> <goals> <goal>cmp</goal> </goals> </execution> </executions> </plugin>

code

The old version is a declared dependency and the new version is the file you just packaged, and the cmp goal is bound to the verify phase.

There is an Ant task as well, for builds that are not Maven based:

xml <taskdef resource="japicmp/ant/antlib.xml" classpathref="task.classpath"/> <japicmp oldjar="${project.build.directory}/guava-18.0.jar" newjar="${project.build.directory}/guava-19.0.jar" oldclasspathref="old.classpath" newclasspathref="new.classpath" onlybinaryincompatiblemodifications="false" onlyModifications="true" /> ```

A Gradle plugin has been developed by melix, and a SonarQube plugin, sonar-japicmp-plugin, feeds the comparison results into a code quality report. The repository also has an online version at japicmp.de where you can compare two artifacts from Maven Central without installing anything, which is the fastest way to try the tool on a library you depend on.

An MCP server for asking an assistant about compatibility

The newest addition is a Model Context Protocol server, and it is a different shape of integration from the rest of the project.

The japicmp MCP server exposes japicmp's API comparison capabilities as a tool for AI assistants that support the Model Context Protocol. It lets agents such as Claude compare two versions of a Maven artifact directly from a conversation, resolving both jars from Maven Central and returning a structured Markdown compatibility report. The report includes binary and source compatibility status, a semantic versioning verdict, and a detailed diff of every changed class, method, constructor and field.

The interesting part is what it reuses. The comparison itself is the same japicmp engine, the same javassist based inspection and the same compatibility rules as the command line tool. What changes is the transport, from a jar you run to a tool an assistant calls.

That makes the MCP server a natural fit for a release workflow where the decision of which version number to publish is made with an assistant in the loop, since the semantic versioning verdict is exactly the question such a workflow asks. The rest of the project is unchanged by it, and the online version at japicmp.de remains the quickest way to see what a report looks like.

Editorial conclusion

japicmp suits a Java team that ships a library and needs to know whether a new release breaks its consumers, since it gives a class by class compatibility verdict and a semantic versioning recommendation without asking you to assemble a classpath. It is not a general artifact differ, and it deliberately does not compare configuration files or other artifact types, because the project says a generic implementation would compromise on performance and usability. Before wiring it into a build, run the CLI once by hand on two real releases, set the access modifier to what your project actually exposes rather than the default, and read the --semantic-versioning output to decide whether the check should fail the build or only report.

Frequently asked questions

How do I compare two jar archives with japicmp?

Run the bundled jar with the two archives named, java -jar japicmp-0.26.5-jar-with-dependencies.jar -n new-version.jar -o old-version.jar. You only need the two jars, because japicmp inspects class files with javassist rather than loading them through reflection.

Can japicmp be used as a Maven plugin in a build?

Yes. The japicmp-maven-plugin takes an old version as a dependency and the new version as the packaged file, and the cmp goal is bound to the verify phase. There is also an Ant task, a Gradle plugin developed by melix and a SonarQube plugin.

Does japicmp compare configuration files as well as classes?

No. The project states that it does not aim to integrate change tracking of other artifact types such as configuration files, because a generic implementation would mean compromises in performance and ease of usage. It compares the class files in two jar archives.

Official sources

  1. License: Apache-2.0
  2. Project website
  3. README
  4. Releases
  5. siom79/japicmp on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/siom79-japicmp.svg)](https://hysenlabs.com/projects/siom79-japicmp)

Was this useful?