Skip to content

Move the repository to Java 25 - #3

Merged
gortazar merged 5 commits into
mainfrom
upgrade-jdk-25
Oct 29, 2026
Merged

gortazar merged 5 commits into
mainfrom
upgrade-jdk-25

Conversation

@gortazar

Copy link
Copy Markdown
Contributor

Moves the repository from Java 21 to Java 25, the current LTS. Spring Boot 4.0.5 supports it.

I have not run the tests locally. The matrix on this branch is the verification.

60a917f — querydsl-apt as an annotation processor path

bd_ejem17 relied on javac finding the processor on the compile classpath, which is how querydsl-apt was wired: a provided dependency and nothing else. From JDK 23 javac no longer runs processors discovered that way, so QPost silently stops being generated and the project fails with cannot find symbol. It is the only project in the repository with an annotation processor, and it is the reason this bump is not a one-line change.

annotationProcessorPaths states the processor explicitly. The path needs jakarta.persistence-api too, since the JPA processor resolves the persistence annotations from the processor path rather than the classpath. The provided dependency stays: Eclipse and IDEA still discover the processor through the classpath.

No behaviour change on Java 21, so this commit is safe on its own.

632e0c5 — Java 25 everywhere

  • java.version in all 86 poms, plus the maven.compiler.source/target pair in parte_4/tema_4.2/ejemplo-2, which has no Boot parent.
  • maven-build.yml sets up JDK 25.
  • The Docker samples: eclipse-temurin:25-jre at runtime, maven:3.9.11-eclipse-temurin-25 to build. There is no maven:3.9.9-eclipse-temurin-25 tag, so the pinned Maven version moves with it.

Three Dockerfiles were already behind their own pom and are consistent for the first time: parte_4/tema_4.2/ejer4 and parte_4/tema_4.3/ejercicio-1 built a java.version 21 project on a JDK 17 image, and parte_5/ejem4b-haproxy-ssl-passthrough ran the resulting jar on a 17.0.6 JRE. CI only runs Maven, so none of that is exercised here — it failed only for whoever built the images.

The defaults of update-springboot.yml said Boot 3.4.1 and Java 17, so dispatching that workflow with its own defaults would have downgraded the repository. They now match what it is on. Say the word if you would rather leave that file alone.

Left alone

The devcontainer in parte_4/tema_4.2/ejemplo-1 pins VARIANT to 17-bullseye on the deprecated mcr.microsoft.com/vscode/devcontainers/java image, whose :0- tag family has no 25. Fixing it means moving to mcr.microsoft.com/devcontainers/java, which is a different change and not covered by CI either way.

What to watch in this run

Java 25 enforces two things that were warnings on 21: sun.misc.Unsafe memory-access methods, and dynamic agent loading. If anything fails, Mockito and ByteBuddy inside spring-boot-starter-test are the first place to look, and the 21 Testcontainers projects the second.

gortazar and others added 2 commits October 29, 2026 10:23
bd_ejem17 relied on javac finding the processor on the compile classpath,
which is how querydsl-apt was wired: a provided dependency and nothing
else. From JDK 23 javac no longer runs processors discovered that way, so
QPost silently stops being generated and the project fails to compile
with "cannot find symbol". It is the only project in the repository with
an annotation processor.

annotationProcessorPaths states the processor explicitly, which is what
the compiler plugin reads regardless of the -proc default. The path needs
jakarta.persistence-api as well, since the JPA processor resolves the
persistence annotations from the processor path, not the classpath.

The provided dependency stays: IDEs still discover the processor through
the classpath, and removing it would break APT inside Eclipse and IDEA.

No behaviour change on Java 21, where implicit discovery still applies.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Java 25 is the current LTS and Spring Boot 4.0.5 supports it. Java 21 was
inherited from the Boot 4 upgrade, which targeted the LTS that was current
when that work started.

- java.version in all 86 poms, plus the maven.compiler.source/target pair
  in parte_4/tema_4.2/ejemplo-2, which has no Boot parent.
- maven-build.yml sets up JDK 25.
- The Docker samples: eclipse-temurin:25-jre at runtime and
  maven:3.9.11-eclipse-temurin-25 to build. There is no
  maven:3.9.9-eclipse-temurin-25 tag, so the pinned Maven version moves
  with it; maven:3-eclipse-temurin-25 where the tag was already floating.

Three Dockerfiles were already behind their own pom before this change
and are now consistent for the first time: parte_4/tema_4.2/ejer4 and
parte_4/tema_4.3/ejercicio-1 built a java.version 21 project on a JDK 17
image, and parte_5/ejem4b-haproxy-ssl-passthrough ran the resulting jar
on a 17.0.6 JRE. None of that is exercised by CI, which only runs Maven,
so it failed only for whoever built the images.

Left alone: the devcontainer in parte_4/tema_4.2/ejemplo-1 pins VARIANT
to 17-bullseye on the deprecated mcr.microsoft.com/vscode/devcontainers
image, whose tag family has no 25. Replacing it means moving to the
mcr.microsoft.com/devcontainers/java image, which is a separate change.

The defaults of update-springboot.yml said Boot 3.4.1 and Java 17, so
dispatching that workflow with its own defaults would have downgraded the
repository. They now match what the repository is on.

Not verified locally: the test run is on the CI matrix for this branch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 29, 2026 09:24

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

gortazar and others added 2 commits October 29, 2026 11:08
The first run on a branch has no cache, so all 86 build jobs start
downloading from Maven Central simultaneously and it answers HTTP 429.
That is what failed parte_4/tema_4.3/ejemplo-2 on the previous run: the
spring-boot-maven-plugin pom could not be transferred, with no fault in
the project. A rerun passed, which is the signature of throttling rather
than a build problem.

A warm-cache job now resolves every project once, and build depends on
it. The cache key setup-java derives from the hash of the pom files is
identical across the jobs of a run, so the 86 restore what that one job
saved and never reach Central. actions/cache only writes on a miss, so
they do not race to save it either.

Warming is an optimisation, not a gate: a project that fails to resolve
there produces a warning and the matrix still runs, because the verdict
belongs to the build jobs. dependency:go-offline also misses what is
resolved at test time, such as the surefire provider, so the build step
keeps a retry handler for the few requests that still go out.

Verified: the loop was run against a stub mvn to check that a failing
project warns, is counted, and does not abort the step.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The devcontainer pinned VARIANT to 17-bullseye on
mcr.microsoft.com/vscode/devcontainers/java, whose :0- tag family stops
at 17: there is no 25 to move to, so bumping the argument was not an
option. The repository is on Java 25 everywhere else, which left this as
the one place still asking for 17.

It now uses mcr.microsoft.com/devcontainers/java:3-25-bookworm, the image
that replaced it. Maven comes from the java feature with version: none,
so the feature adds Maven without installing a second JDK over the one
the image ships.

The Dockerfile is gone. It existed only to turn INSTALL_MAVEN,
INSTALL_GRADLE and NODE_VERSION arguments into sdkman and nvm calls,
which is what features do now, and its comments still described a choice
between Java 11 and 17.

Two more things the old file carried: settings and extensions sat at the
top level, which the spec moved under customizations.vscode, and
java.home pointed at /docker-java-home, a path the current images do not
have. A wrong java.home breaks the Java extension, so it is dropped
rather than updated; the extension reads JAVA_HOME.

Not verified: nothing in CI builds a devcontainer. The image tag and the
feature options were checked against the MCR tag list and the feature
definition, not by opening the container.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gortazar

Copy link
Copy Markdown
Contributor Author

Two follow-ups: cache reuse and the devcontainer

0697847 — fill the Maven cache once instead of 86 times at once

The first run on a branch has no cache, so all 86 build jobs started downloading from Maven Central at the same time and it answered HTTP 429. That is what failed parte_4/tema_4.3/ejemplo-2 on the previous attempt of this PR: spring-boot-maven-plugin:pom:4.0.5 could not be transferred, with nothing wrong in the project. A rerun passed, which is the signature of throttling rather than a build problem.

A warm-cache job now resolves every project once and build depends on it. The cache key setup-java derives from the hash of the pom files is identical across the jobs of a run, so the 86 restore what that one job saved. actions/cache only writes on a miss, so they do not race to save it either.

Warming is an optimisation, not a gate: a project that fails to resolve there produces a warning and the matrix still runs, because the verdict belongs to the build jobs. dependency:go-offline also misses what gets resolved at test time, such as the surefire provider, so the build step keeps a retry handler for the few requests that still go out.

Measured on this run:

Warm the Maven cache 6 min 16 s, once
A build job afterwards ~32 s, no downloads
Projects that failed to resolve 0

8b50f09 — a devcontainer image that still exists

parte_4/tema_4.2/ejemplo-1 pinned VARIANT to 17-bullseye on mcr.microsoft.com/vscode/devcontainers/java, whose :0- tag family stops at 17 — there is no 25 to move to, so bumping the argument was not an option. It now uses mcr.microsoft.com/devcontainers/java:3-25-bookworm, the image that replaced it, with Maven from the java feature at version: none so the feature adds Maven without installing a second JDK over the image's own.

The Dockerfile is gone: it existed only to turn INSTALL_MAVEN, INSTALL_GRADLE and NODE_VERSION into sdkman and nvm calls, which is what features do now.

Two more things it carried: settings and extensions sat at the top level, which the spec moved under customizations.vscode, and java.home pointed at /docker-java-home, a path the current images do not have. A wrong java.home breaks the Java extension, so it is dropped rather than updated — the extension reads JAVA_HOME.

Nothing in CI builds a devcontainer, so this part is unverified by the matrix. The image tag was checked against the MCR tag list and the feature options against the feature definition, not by opening the container.

Unrelated, flagged by this run

GitHub is warning that actions/setup-java@v4 is deprecated and that actions/checkout@v4 and setup-java@v4 target Node 20, which runners now force onto Node 24. Moving both to @v5 is a separate change.

The previous run annotated every job twice: setup-java v4 is deprecated
and will get no more updates, and both actions target Node 20, which the
runners now force onto Node 24.

GitHub's own notice says to migrate to setup-java v5, and that advice is
already stale: the current majors are setup-java v6 and checkout v7.
Going to v5 would mean doing this again shortly.

Checked against the release notes rather than assumed:

- setup-java v6 drops the legacy adopt and adopt-openj9 distributions.
  Both workflows ask for temurin, so nothing to change.
- v6 renamed jdkFile to jdk-file. Neither workflow uses it.
- The ESM rewrite in both v6 and checkout v7 is documented as not
  user-facing.
- checkout v7 blocks checking out a fork PR under pull_request_target and
  workflow_run. Neither workflow uses those events.

One consequence worth expecting: v6 adds .mvn/extensions.xml to the Maven
cache key and caches the wrapper distribution separately, so the existing
caches do not match the new key. The warm-cache job will download
everything once more on the first run after this, and be a hit again from
the second.

Two things come free with v6: a problem matcher that turns javac errors
into annotations on the diff, and a cache-primary-key output, which is a
way to assert that warm-cache and the build jobs really agree on the key
if that ever needs proving.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gortazar
gortazar merged commit 0a3ef43 into main Oct 29, 2026
178 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants