Skip to content

Cover legacy Bouncy Castle artifacts and their API changes - #1189

Merged
timtebeek merged 3 commits into
mainfrom
tim/bouncycastle-jdk18on-recipes
Aug 10, 2026
Merged

Cover legacy Bouncy Castle artifacts and their API changes#1189
timtebeek merged 3 commits into
mainfrom
tim/bouncycastle-jdk18on-recipes

Conversation

@timtebeek

@timtebeek timtebeek commented Aug 10, 2026

Copy link
Copy Markdown
Member

What

BounceCastleFromJdk15OntoJdk18On only handled -jdk15on and -jdk15to18, and neither Bouncy Castle recipe touched code. Since the dependency change pins latest.release, users land on 1.85.2 in a single hop, where some of their code no longer compiles.

Dependency coordinates

Added every legacy suffix that has a published counterpart, to both the jdk18on recipe (Java 8+) and the jdk15to18 recipe (Java < 8):

suffix artifacts
-jdk16 bcprov, bcprov-ext, bcmail, bcpg
-jdk15+ bcprov, bcmail, bcpg
-jdk15 bcprov, bcprov-ext, bcmail, bcpg
-jdk14 bcprov, bcprov-ext, bcutil, bcpkix, bcmail, bcpg, bctls
-jdk12 bcprov, bcpg

Only pairs that actually exist on Maven Central are listed — there is no bcjmail-jdk14, and bcpkix/bcutil/bctls never shipped -jdk15/-jdk15+/-jdk16.

bctsp-* is frozen at 1.46 and was folded into bcpkix at 1.47, so all five surviving suffixes map onto bcpkix. This is not a suffix swap, so the concern was duplicate coordinates — but ChangeDependency already collapses those, verified end to end: a pom holding both bctsp-jdk15on:1.46 and bcpkix-jdk15on:1.70 comes out with a single bcpkix-jdk18on element. bctspAlongsideBcpkixCollapsesToASingleDependency asserts both the resolved model and that the raw XML contains the artifact exactly once.

bcprov-ext is also added to the pre-existing -jdk15on and -jdk15to18 sections in both recipes; migrating bcprov-jdk15on while leaving bcprov-ext-jdk15on behind was an oversight. Note bcprov-ext-jdk18on stops at 1.78.1 while bcprov-jdk18on is at 1.85.2 — still an upgrade, just not to current.

API changes

I diffed the public/protected API of bcprov/bcpg/bcpkix/bctls/bcutil/bcmail at jdk15on 1.70 against jdk18on 1.85.2 by parsing the class files. Two findings were worth automating:

BouncyCastleDerStringGetInstanceReturnType — 1.71 pulled getInstance(..) up from the 12 DER*String types to their ASN1*String supertypes. The call site still compiles, because static methods are inherited; what breaks is the return type:

ASN1IA5String s = DERIA5String.getInstance(o);   // fine in both
DERIA5String  s = DERIA5String.getInstance(o);   // compiles at 1.70, breaks at 1.85

So the recipe widens the declared type rather than retargeting the call. Both the DER* and ASN1* types exist with identical getInstance signatures at 1.70, so this compiles against either artifact and can be applied ahead of the upgrade. A blanket ChangeType is not an option — the ASN1*String types are all abstract, so new DERIA5String(..) has to stay.

BouncyCastleSphincsPlusToPqcLegacy — 1.78 moved org.bouncycastle.pqc.crypto.sphincsplus to org.bouncycastle.pqc.legacy.sphincsplus to free the original package for FIPS 205 SLH-DSA. All 19 types map 1:1, so it is a plain ChangePackage.

Not covered

Deliberate omissions, all verified against the same diff:

  • ASN1TaggedObject.getObject() / getObjectParser(int, boolean) — genuinely removed. Replacements (getBaseObject(), getExplicitBaseObject()) exist at 1.70, but the correct one depends on whether the tag is explicit or implicit, and guessing wrong is a silent parsing bug rather than a compile error. Better as a search recipe.
  • ASN1ApplicationSpecific family — deleted; the replacement is ASN1TaggedObject + BERTags.APPLICATION, a structural rework rather than a rename.
  • McEliece, GMSS, qTESLA, pqc.math.linearalgebra, oer.its — removed outright, nothing to migrate to.
  • TLS and OpenPGP operator SPI removals — protected extension points that only affect custom crypto provider implementations. The high-level org.bouncycastle.openpgp API and BouncyCastleProvider have zero public member removals across 1.70 → 1.85.

Testing

BouncyCastleTest goes from 21 to 76 cases; versions are pinned per suffix to one that actually resolves (1.70 for jdk14/jdk15on/jdk15to18, 1.46 for jdk15/jdk15+/jdk16/bctsp, 130 for jdk12), since the previously hardcoded 1.70 does not exist for the older artifacts. New BouncyCastleApiTest covers the two code recipes, including that constructors are left alone.

Full suite green: 1844 tests, 0 failures.

One wart worth flagging: alreadyDeclaredAsAsn1String needs expectedCyclesThatMakeChanges(1) even though the printed source is unchanged, because upstream ChangeMethodInvocationReturnType re-attributes the invocation type on every match. Harmless in a real run — no diff is produced — but it may be worth an upstream issue.

recipes.csv regenerated with ./gradlew rCG.

The `jdk18on` recipe only handled `-jdk15on` and `-jdk15to18`, and neither
recipe touched code, leaving callers on a dependency that no longer compiles.

Dependency coordinates:
- Migrate `-jdk12`, `-jdk14`, `-jdk15`, `-jdk15+` and `-jdk16` to `-jdk18on`,
  for every artifact where both sides are published.
- Add the `bcprov-ext` counterparts to the existing `-jdk15on` and
  `-jdk15to18` migrations.

API changes between 1.70 and 1.85:
- `BouncyCastleDerStringGetInstanceReturnType` widens declared types to
  `ASN1*String` where the value comes from `DER*String.getInstance(..)`,
  which 1.71 pulled up to the supertype.
- `BouncyCastleSphincsPlusToPqcLegacy` renames the SPHINCS+ package that
  1.78 moved to `pqc.legacy` to make room for SLH-DSA.
Both were called out as follow-ups on the PR; ChangeDependency already
collapses duplicate coordinates, so the bctsp mapping needs nothing extra.

- Map `bctsp-*` onto `bcpkix`, which absorbed the time stamp protocol
  support in 1.47, in both the `jdk18on` and `jdk15to18` recipes. A pom
  holding both `bctsp-jdk15on` and `bcpkix-jdk15on` collapses to a single
  `bcpkix-jdk18on` dependency, which is pinned by a test.
- Mirror the `-jdk12`, `-jdk14`, `-jdk15`, `-jdk15+` and `-jdk16` migrations
  onto `-jdk15to18` for the Java < 8 recipe.
@timtebeek
timtebeek marked this pull request as ready for review August 10, 2026 16:21
@timtebeek
timtebeek merged commit 33354b5 into main Aug 10, 2026
1 check passed
@timtebeek
timtebeek deleted the tim/bouncycastle-jdk18on-recipes branch August 10, 2026 16:30
@github-project-automation github-project-automation Bot moved this from In Progress to Done in OpenRewrite Aug 10, 2026
mergify Bot added a commit to robfrank/linklift that referenced this pull request Aug 20, 2026
…41.0 to 3.42.0 [skip ci]

Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.41.0 to 3.42.0.
Release notes

*Sourced from [org.openrewrite.recipe:rewrite-migrate-java's releases](https://github.com/openrewrite/rewrite-migrate-java/releases).*

> 3.42.0
> ------
>
> What's Changed
> --------------
>
> * Adopt upstream XML trailing-comment formatting by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-migrate-java#1180](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1180)
> * Add mapping for CheckForNull to JSpecify annotation by [`@​zbynek`](https://github.com/zbynek) in [openrewrite/rewrite-migrate-java#1179](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1179)
> * Skip `UseSetOf`/`UseListOf` for `HashSet`/`ArrayList` subclasses by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-migrate-java#1182](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1182)
> * Avoid hardcoded patch version in UpdateSdkManTest by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-migrate-java#1183](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1183)
> * Only add the Mockito surefire agent configuration when asked, and keep it minimal by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-migrate-java#1184](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1184)
> * Make subpackage recursion explicit in the Jackson JAX-RS JSON rename by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-migrate-java#1185](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1185)
> * Add the Mockito agent properties goal in its own execution by [`@​MBoegers`](https://github.com/MBoegers) in [openrewrite/rewrite-migrate-java#1186](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1186)
> * Derive SDKMAN test versions from the candidate list by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-migrate-java#1188](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1188)
> * Do not apply `var` when the generic return type needs the declared type by [`@​jevanlingen`](https://github.com/jevanlingen) in [openrewrite/rewrite-migrate-java#1187](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1187)
> * Cover legacy Bouncy Castle artifacts and their API changes by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-migrate-java#1189](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1189)
> * Add jakarta.validation-api dependency when migrating com.sun.istack.NotNull by [`@​steve-aom-elliott`](https://github.com/steve-aom-elliott) in [openrewrite/rewrite-migrate-java#1190](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1190)
>
> New Contributors
> ----------------
>
> * [`@​zbynek`](https://github.com/zbynek) made their first contribution in [openrewrite/rewrite-migrate-java#1179](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1179)
>
> **Full Changelog**: <openrewrite/rewrite-migrate-java@v3.41.0...v3.42.0>


Commits

* [`1238ceb`](openrewrite/rewrite-migrate-java@1238ceb) OpenRewrite recipe best practices
* [`01d0fe8`](openrewrite/rewrite-migrate-java@01d0fe8) Add `jakarta.validation-api` dependency when migrating `com.sun.istack.NotNul...
* [`33354b5`](openrewrite/rewrite-migrate-java@33354b5) Cover legacy Bouncy Castle artifacts and their API changes ([#1189](https://redirect.github.com/openrewrite/rewrite-migrate-java/issues/1189))
* [`6c648a5`](openrewrite/rewrite-migrate-java@6c648a5) Update Gradle wrapper to 9.7.0
* [`7099ad3`](openrewrite/rewrite-migrate-java@7099ad3) Do not apply `var` when the generic return type needs the declared type ([#1187](https://redirect.github.com/openrewrite/rewrite-migrate-java/issues/1187))
* [`ccfa7b0`](openrewrite/rewrite-migrate-java@ccfa7b0) Derive SDKMAN test versions from the candidate list ([#1188](https://redirect.github.com/openrewrite/rewrite-migrate-java/issues/1188))
* [`96e8647`](openrewrite/rewrite-migrate-java@96e8647) [Auto] SDKMAN! Java candidates as of 2026-08-10T1102
* [`26f898e`](openrewrite/rewrite-migrate-java@26f898e) Add the Mockito agent properties goal in its own execution ([#1186](https://redirect.github.com/openrewrite/rewrite-migrate-java/issues/1186))
* [`d82dd47`](openrewrite/rewrite-migrate-java@d82dd47) OpenRewrite recipe best practices
* [`55f2e93`](openrewrite/rewrite-migrate-java@55f2e93) Make subpackage recursion explicit in the Jackson JAX-RS JSON rename ([#1185](https://redirect.github.com/openrewrite/rewrite-migrate-java/issues/1185))
* Additional commits viewable in [compare view](openrewrite/rewrite-migrate-java@v3.41.0...v3.42.0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

1 participant