diff --git a/.github/actions/integration-test-setup/action.yml b/.github/actions/integration-test-setup/action.yml
index 1a4a1521830..e955d583080 100644
--- a/.github/actions/integration-test-setup/action.yml
+++ b/.github/actions/integration-test-setup/action.yml
@@ -9,7 +9,7 @@ inputs:
jdk-version:
description: JDK version
required: false
- default: "21"
+ default: "25"
runs:
using: composite
diff --git a/.github/actions/java-setup/action.yml b/.github/actions/java-setup/action.yml
index 8f7f43e3c04..65331989826 100644
--- a/.github/actions/java-setup/action.yml
+++ b/.github/actions/java-setup/action.yml
@@ -9,14 +9,14 @@ inputs:
java-version:
description: The Java version that is going to be set up.
required: false
- default: "21"
+ default: "25"
runs:
using: composite
steps:
- id: setup-java
name: Setup Java
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
+ uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
distribution: ${{ inputs.distribution }}
java-version: ${{ inputs.java-version }}
diff --git a/.github/scripts/ansible/roles/keycloak_remote_installer/README.md b/.github/scripts/ansible/roles/keycloak_remote_installer/README.md
index 2083135bb63..b66b88cd84b 100644
--- a/.github/scripts/ansible/roles/keycloak_remote_installer/README.md
+++ b/.github/scripts/ansible/roles/keycloak_remote_installer/README.md
@@ -15,7 +15,7 @@ See `defaults/main.yml` for default values.
### Other
- `update_system_packages`: Whether to update the system packages. Defaults to `no`.
- `install_java`: Whether to install OpenJDK on the system. Defaults to `yes`.
-- `java_version`: Version of OpenJDK to be installed. Defaults to `21`.
+- `java_version`: Version of OpenJDK to be installed. Defaults to `25`.
## Example Playbook
diff --git a/.github/scripts/ansible/roles/keycloak_remote_installer/defaults/main.yml b/.github/scripts/ansible/roles/keycloak_remote_installer/defaults/main.yml
index a853d38849c..506d551c84b 100644
--- a/.github/scripts/ansible/roles/keycloak_remote_installer/defaults/main.yml
+++ b/.github/scripts/ansible/roles/keycloak_remote_installer/defaults/main.yml
@@ -3,4 +3,4 @@ kc_home: /opt/keycloak
m2_home: ~/.m2
update_system_packages: no
install_java: yes
-java_version: 21
+java_version: 25
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index f61009f6ea4..071e9ca4ca5 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -162,6 +162,8 @@ jobs:
- id: integration-test-setup
name: Integration test setup
uses: ./.github/actions/integration-test-setup
+ with:
+ jdk-version: '21'
- name: Build adapter distributions
run: ./mvnw install -DskipTests -f distribution/pom.xml
@@ -193,6 +195,8 @@ jobs:
- id: integration-test-setup
name: Integration test setup
uses: ./.github/actions/integration-test-setup
+ with:
+ jdk-version: '21'
- name: Build adapter distributions
run: ./mvnw install -DskipTests -f distribution/pom.xml
@@ -302,7 +306,7 @@ jobs:
matrix:
os: [ubuntu-latest, windows-latest]
dist: [temurin]
- version: [17, 25]
+ version: [17, 21]
fail-fast: false
runs-on: ${{ matrix.os }}
steps:
@@ -1103,6 +1107,8 @@ jobs:
- id: integration-test-setup
name: Integration test setup
uses: ./.github/actions/integration-test-setup
+ with:
+ jdk-version: 21 # Keycloak 24 is not compatible with Java 25+
- name: Run Migration Tests
run: |
diff --git a/distribution/maven-plugins/pom.xml b/distribution/maven-plugins/pom.xml
index 4eff4b908a6..0737369d598 100644
--- a/distribution/maven-plugins/pom.xml
+++ b/distribution/maven-plugins/pom.xml
@@ -32,7 +32,7 @@
org.codehaus.groovy
groovy-all
- 3.0.21
+ 3.0.25
pom
diff --git a/docs/documentation/README.md b/docs/documentation/README.md
index 4bc1768ad85..3c8686b798b 100644
--- a/docs/documentation/README.md
+++ b/docs/documentation/README.md
@@ -46,7 +46,7 @@ To build the REST API documentation and the Javadoc:
- Export the `JAVA_HOME` variable, for example:
```
- export JAVA_HOME=/usr/lib/jvm/java-21-openjdk
+ export JAVA_HOME=/usr/lib/jvm/java-25-openjdk
```
(without this, you may get the following error: `Unable to find javadoc command: The environment variable JAVA_HOME is not correctly set.`)
- Run:
diff --git a/docs/documentation/release_notes/topics/26_6_0.adoc b/docs/documentation/release_notes/topics/26_6_0.adoc
index bafa53a65ba..75645ee3f59 100644
--- a/docs/documentation/release_notes/topics/26_6_0.adoc
+++ b/docs/documentation/release_notes/topics/26_6_0.adoc
@@ -31,3 +31,7 @@ You can specify these headers via the general parent option `telemetry-header-` for OpenTelemetry Logs, or `telemetry-metrics-header-` for OpenTelemetry Metrics.
For more details, see the link:{telemetryguide_link}[{telemetryguide_name}] guide.
+
+= Java 25 support
+
+{project_name} now supports running with JRE 25.
diff --git a/docs/guides/getting-started/getting-started-zip.adoc b/docs/guides/getting-started/getting-started-zip.adoc
index b40e610205a..4db0685fde6 100644
--- a/docs/guides/getting-started/getting-started-zip.adoc
+++ b/docs/guides/getting-started/getting-started-zip.adoc
@@ -13,7 +13,7 @@ summary="Get started with {project_name} on a physical or virtual server.">
include::templates/hw-requirements.adoc[]
-Make sure you have https://openjdk.java.net/[OpenJDK 21] installed.
+Make sure you have https://openjdk.java.net/[OpenJDK 25] installed.
== Download {project_name}
diff --git a/docs/guides/observability/partials/jgrp_metrics.adoc b/docs/guides/observability/partials/jgrp_metrics.adoc
index e3e9b34d359..5adc33f4bdf 100644
--- a/docs/guides/observability/partials/jgrp_metrics.adoc
+++ b/docs/guides/observability/partials/jgrp_metrics.adoc
@@ -85,7 +85,7 @@ A retransmission mechanism ensures a reliable communication with an increase of
TIP: In a healthy cluster, the thread pool should never be closer to its maximum size (by default, `200` threads).
-NOTE: Thread pool metrics are not available with virtual threads. Virtual threads are enabled by default when running with OpenJDK 21.
+NOTE: Thread pool metrics are not available with virtual threads. Virtual threads are enabled by default when running with OpenJDK 21 and later.
IMPORTANT: The metric name depends on the JGroups transport protocol in use. The default transport protocol is TCP.
diff --git a/operator/pom.xml b/operator/pom.xml
index c7fe147977d..5519cebc5e2 100644
--- a/operator/pom.xml
+++ b/operator/pom.xml
@@ -271,6 +271,17 @@
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ -proc:full
+
+
+
+
maven-surefire-plugin
diff --git a/quarkus/dist/src/main/content/bin/kc.bat b/quarkus/dist/src/main/content/bin/kc.bat
index 2ed30178a4f..fed43b1b50a 100644
--- a/quarkus/dist/src/main/content/bin/kc.bat
+++ b/quarkus/dist/src/main/content/bin/kc.bat
@@ -129,10 +129,12 @@ if not "x%JAVA_OPTS%" == "x" (
)
@REM See also https://github.com/wildfly/wildfly-core/blob/7e5624cf92ebe4b64a4793a8c0b2a340c0d6d363/core-feature-pack/common/src/main/resources/content/bin/common.sh#L57-L60
+@REM java.base/java.lang=ALL-UNNAMED is required for JBoss Threads, see e.g. https://github.com/quarkusio/quarkus/pull/47637 and relevant https://github.com/quarkusio/quarkus/discussions/51041
+@REM --enable-native-access=ALL-UNNAMED is required for Infinispan: https://github.com/infinispan/infinispan/issues/15765#issuecomment-3839985807
if not "x%JAVA_ADD_OPENS%" == "x" (
echo "JAVA_ADD_OPENS already set in environment; overriding default settings"
) else (
- set "JAVA_ADD_OPENS=--add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED"
+ set "JAVA_ADD_OPENS=--add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --enable-native-access=ALL-UNNAMED"
)
set "JAVA_OPTS=%JAVA_OPTS% %JAVA_ADD_OPENS%"
diff --git a/quarkus/dist/src/main/content/bin/kc.sh b/quarkus/dist/src/main/content/bin/kc.sh
index 88a6fb58ab4..00f59dfac6e 100644
--- a/quarkus/dist/src/main/content/bin/kc.sh
+++ b/quarkus/dist/src/main/content/bin/kc.sh
@@ -112,8 +112,10 @@ else
fi
# See also https://github.com/wildfly/wildfly-core/blob/7e5624cf92ebe4b64a4793a8c0b2a340c0d6d363/core-feature-pack/common/src/main/resources/content/bin/common.sh#L57-L60
+# java.base/java.lang=ALL-UNNAMED is required for JBoss Threads, see e.g. https://github.com/quarkusio/quarkus/pull/47637 and relevant https://github.com/quarkusio/quarkus/discussions/51041
+# --enable-native-access=ALL-UNNAMED is required for Infinispan: https://github.com/infinispan/infinispan/issues/15765#issuecomment-3839985807
if [ -z "$JAVA_ADD_OPENS" ]; then
- JAVA_ADD_OPENS="--add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED"
+ JAVA_ADD_OPENS="--add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --enable-native-access=ALL-UNNAMED"
else
echo "JAVA_ADD_OPENS already set in environment; overriding default settings"
fi
diff --git a/testsuite/integration-arquillian/pom.xml b/testsuite/integration-arquillian/pom.xml
index 3a3cd66e6df..9b284661b63 100644
--- a/testsuite/integration-arquillian/pom.xml
+++ b/testsuite/integration-arquillian/pom.xml
@@ -56,7 +56,6 @@
2.0.3
2.2.3
1.8.0
- 1.14.13
1.9.8.Final
diff --git a/testsuite/integration-arquillian/tests/base/pom.xml b/testsuite/integration-arquillian/tests/base/pom.xml
index f4b86230b04..81a0badd8dc 100644
--- a/testsuite/integration-arquillian/tests/base/pom.xml
+++ b/testsuite/integration-arquillian/tests/base/pom.xml
@@ -755,7 +755,6 @@
net.bytebuddy
byte-buddy
- ${byte-buddy.version}
diff --git a/testsuite/integration-arquillian/tests/pom.xml b/testsuite/integration-arquillian/tests/pom.xml
index 840fe0becc4..e54b9b4a88b 100644
--- a/testsuite/integration-arquillian/tests/pom.xml
+++ b/testsuite/integration-arquillian/tests/pom.xml
@@ -1493,7 +1493,6 @@
net.bytebuddy
byte-buddy
- ${byte-buddy.version}
diff --git a/testsuite/model/src/test/java/org/keycloak/testsuite/model/infinispan/CacheExpirationTest.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/infinispan/CacheExpirationTest.java
index 93592831ae8..b6862cfac09 100644
--- a/testsuite/model/src/test/java/org/keycloak/testsuite/model/infinispan/CacheExpirationTest.java
+++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/infinispan/CacheExpirationTest.java
@@ -17,9 +17,10 @@
package org.keycloak.testsuite.model.infinispan;
import java.io.BufferedReader;
-import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.management.ManagementFactory;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.time.Instant;
import java.util.Collections;
import java.util.Objects;
@@ -143,12 +144,26 @@ public class CacheExpirationTest extends KeycloakModelTest {
// This is synchronized as it doesn't make sense to run this in parallel with multiple threads
// as each invocation will run a garbage collection anyway.
public synchronized Integer getNumberOfInstancesOfClass(Class> c, String pid) {
- Process proc;
+ log.debug("PID: " + pid);
+
+ Path tempFile = null;
try {
// running jmap command will also trigger a garbage collection on the VM, but that might be VM specific
// a test run with adding "-verbose:gc" showed the message "GC(23) Pause Full (Heap Inspection Initiated GC)" that
// indicates a full GC run
- proc = Runtime.getRuntime().exec("jmap -histo:live " + pid);
+
+ tempFile = Files.createTempFile("jmap-output", ".txt"); // not consuming the output directly to avoid potential deadlock
+
+ Process proc = new ProcessBuilder("jmap", "-histo:live", pid)
+ .redirectOutput(tempFile.toFile())
+ .redirectError(ProcessBuilder.Redirect.INHERIT)
+ .start();
+
+ boolean finished = proc.waitFor(30, TimeUnit.SECONDS);
+ if (!finished) {
+ proc.destroyForcibly();
+ throw new RuntimeException("jmap timed out!");
+ }
try (BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()))) {
AtomicInteger matchingLines = new AtomicInteger();
@@ -165,10 +180,18 @@ public class CacheExpirationTest extends KeycloakModelTest {
.map(m -> Integer.valueOf(m.group(1)))
.orElseGet(() -> matchingLines.get() == 0 ? null : 0);
}
- } catch (IOException ex) {
+ } catch (Exception ex) {
log.debug(ex);
- Assume.assumeTrue("jmap not found or unsupported", false);
+ Assume.assumeTrue("jmap not found, unsupported or failed", false);
return null;
+ } finally {
+ if (tempFile != null) {
+ try {
+ Files.deleteIfExists(tempFile);
+ } catch (Exception ex) {
+ log.debug(ex);
+ }
+ }
}
}
}