Documentation menu

API diff for upgrades

Before bumping a dependency, ask what the new version breaks. jdx diff compares the public API of two artifacts — jars, class directories or Maven coordinates — and names every difference as a rule with a severity, with a gate for CI.

Compare two versions#

jdx diff com.google.code.gson:gson:2.11.0 com.google.code.gson:gson:2.14.0 --fetch
api diff com.google.code.gson:gson:2.11.0 -> com.google.code.gson:gson:2.14.0 (public surface)
info  TYPE_ADDED  com.google.gson.internal.GsonTypes
info  TYPE_ADDED  com.google.gson.internal.bind.JsonElementTypeAdapter
info  MEMBER_ADDED  com.google.gson.FieldNamingStrategy#alternateNames(java.lang.reflect.Field)
info  MEMBER_ADDED  com.google.gson.internal.ConstructorConstructor#get(com.google.gson.reflect.TypeToken, boolean)
info  MEMBER_ADDED  com.google.gson.internal.bind.TypeAdapters#BIG_DECIMAL_FACTORY
info  MEMBER_ADDED  com.google.gson.internal.bind.TypeAdapters#BIG_INTEGER_FACTORY
info  MEMBER_ADDED  com.google.gson.internal.bind.TypeAdapters#DOUBLE_STRICT
info  MEMBER_ADDED  com.google.gson.internal.bind.TypeAdapters#FLOAT_STRICT
info  MEMBER_ADDED  com.google.gson.internal.bind.TypeAdapters#LAZILY_PARSED_NUMBER_FACTORY
info  MEMBER_ADDED  com.google.gson.internal.bind.TypeAdapters#LONG_AS_STRING
info  MEMBER_ADDED  com.google.gson.internal.bind.TypeAdapters#atomicLongAdapter(com.google.gson.TypeAdapter)
info  MEMBER_ADDED  com.google.gson.internal.bind.TypeAdapters#atomicLongArrayAdapter(com.google.gson.TypeAdapter)
info  MEMBER_ADDED  com.google.gson.internal.bind.TypeAdapters#javaTimeTypeAdapterFactory()
info  MEMBER_ADDED  com.google.gson.internal.sql.SqlTypesSupport#SQL_TYPE_FACTORIES
info  MEMBER_ADDED  com.google.gson.stream.JsonReader#getNestingLimit()
info  MEMBER_ADDED  com.google.gson.stream.JsonReader#setNestingLimit(int)
info  FIELD_CONSTANT_VALUE_CHANGED  com.google.gson.internal.GsonBuildConfig#VERSION: "2.11.0" -> "2.14.0"
0 breaking · 0 suspicious · 17 informational · 2 types added · 0 types removed
warning MULTI_RELEASE_VARIANT: in com.google.code.gson:gson:2.11.0: multi-release gson-2.11.0.jar serves version-specific variants for this JDK (21)
… 9 more lines (run it yourself to see them all)

Real output — this example ran against the current jdx when the page was built.

Each side can be a jar file, a class directory, a glob or a group:artifact:version coordinate (with --fetch to download it). diff reads bytecode only — no sources, no decompilation, no workspace.

Rules and severities#

Every finding names exactly one rule, so tools can filter on the rule rather than the prose:

  • breaking — an already-compiled caller can fail to link or run: MEMBER_REMOVED, RETURN_TYPE_CHANGED, PARAMETER_TYPE_CHANGED, MEMBER_VISIBILITY_NARROWED, STATIC_TO_INSTANCE, INTERFACE_METHOD_ADDED, TYPE_REMOVED, …
  • suspicious — binary-compatible by the letter of the JLS, but recompiling, the Kotlin view or behaviour can still break: CHECKED_EXCEPTION_ADDED, GENERIC_SIGNATURE_CHANGED, MEMBER_MOVED_TO_SUPERTYPE, KOTLIN_NULLABILITY_CHANGED, KOTLIN_SUSPEND_CHANGED, …
  • info — additive or cosmetic: MEMBER_ADDED, TYPE_ADDED, DEPRECATED_ADDED, FIELD_CONSTANT_VALUE_CHANGED, …

A removed member paired with a matching added one is reported once as a retyped signature, not as a removal plus an addition — and an ambiguous pairing is never guessed.

The full rule set is in the design specification.

Useful flags:

Flag Effect
--severity breaking|suspicious|all how much to print (the tally always covers everything)
--visibility public|all public + protected surface (default), or every declared member
--include-synthetic also compare bridge and synthetic members
--limit N cap the findings shown (default 200; the cut tail is the least severe)

Gate a pull request#

--fail-on breaking (or --fail-on any) turns the report into an exit status: 1 when the gate trips, 0 otherwise. This is the one documented exception to the exit-code table: diff has no "not found" outcome, so 1 means "the gate tripped". The verdict is also in the JSON envelope as result.gate.

jdx diff com.google.code.gson:gson:2.11.0 com.google.code.gson:gson:2.14.0 --severity breaking --fail-on breaking
api diff com.google.code.gson:gson:2.11.0 -> com.google.code.gson:gson:2.14.0 (public surface)
17 findings below --severity breaking
0 breaking · 0 suspicious · 17 informational · 2 types added · 0 types removed
fail-on breaking: no breaking changes (exit 0)
warning MULTI_RELEASE_VARIANT: in com.google.code.gson:gson:2.11.0: multi-release gson-2.11.0.jar serves version-specific variants for this JDK (21)
warning MULTI_RELEASE_VARIANT: in com.google.code.gson:gson:2.14.0: multi-release gson-2.14.0.jar serves version-specific variants for this JDK (21)
… 7 more lines (run it yourself to see them all)

Real output — this example ran against the current jdx when the page was built.

In GitHub Actions:

- name: Public API must not break
  run: jdx diff "com.example:mylib:$(git describe --tags --abbrev=0 | tr -d v)" build/libs/mylib.jar --fetch --fail-on breaking

Edit this page on GitHub · View as Markdown · Updated