Java 27 and 26: runnable demos and captured output for every JEP, plus version lanes
Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01B38FGKKam5SCGgwgduVAh3
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
# 1. What shipped, and what to believe
|
||||
|
||||
Next: [2. G1 becomes the default](02-g1-default.md)
|
||||
|
||||
Java 27 reached General Availability on 2026-09-15. It is **not** an LTS: Oracle's support roadmap lists Premier support for 27 until March 2027,
|
||||
and names Java 29 (September 2027) as the next LTS after 25. Everything in this repository was run on real JDK binaries; where a claim comes from
|
||||
prose rather than from a run, the chapter says so.
|
||||
|
||||
## The nine JEPs in 27
|
||||
|
||||
| JEP | Title | Status in 27 | Chapter |
|
||||
|---|---|---|---|
|
||||
| 523 | Make G1 the Default Garbage Collector in All Environments | final | [2](02-g1-default.md) |
|
||||
| 534 | Compact Object Headers by Default | final | [3](03-compact-headers.md) |
|
||||
| 527 | Post-Quantum Hybrid Key Exchange for TLS 1.3 | final | [4](04-post-quantum-tls.md) |
|
||||
| 532 | Primitive Types in Patterns, instanceof, and switch | fifth preview | [5](05-primitive-patterns.md) |
|
||||
| 531 | Lazy Constants | third preview | [6](06-lazy-constants.md) |
|
||||
| 533 | Structured Concurrency | seventh preview | [7](07-structured-concurrency.md) |
|
||||
| 538 | PEM Encodings of Cryptographic Objects | third preview | [8](08-pem-api.md) |
|
||||
| 536 | JFR: In-Process Data Redaction | final | [9](09-jfr-redaction-and-vector.md) |
|
||||
| 537 | Vector API | twelfth incubator | [9](09-jfr-redaction-and-vector.md) |
|
||||
|
||||
## The ten JEPs in 26 (the release many teams skipped)
|
||||
|
||||
| JEP | Title | Status in 26 | Chapter |
|
||||
|---|---|---|---|
|
||||
| 500 | Prepare to Make Final Mean Final | final | [11](11-recap-26.md) |
|
||||
| 504 | Remove the Applet API | final | [11](11-recap-26.md) |
|
||||
| 516 | Ahead-of-Time Object Caching with Any GC | final | [11](11-recap-26.md) |
|
||||
| 517 | HTTP/3 for the HTTP Client API | final | [11](11-recap-26.md) |
|
||||
| 522 | G1 GC: Improve Throughput by Reducing Synchronization | final | [11](11-recap-26.md) (not measured here) |
|
||||
| 524 | PEM Encodings of Cryptographic Objects | second preview | [8](08-pem-api.md) |
|
||||
| 525 | Structured Concurrency | sixth preview | [7](07-structured-concurrency.md) |
|
||||
| 526 | Lazy Constants | second preview | [6](06-lazy-constants.md) |
|
||||
| 529 | Vector API | eleventh incubator | [9](09-jfr-redaction-and-vector.md) |
|
||||
| 530 | Primitive Types in Patterns, instanceof, and switch | fourth preview | [5](05-primitive-patterns.md) |
|
||||
|
||||
## How the list was verified
|
||||
|
||||
openjdk.org/jeps and jdk.java.net/27 returned HTTP 403 from the sandbox used to write this, and no workaround was attempted. The lists were
|
||||
cross-checked between the Inside.java release announcement, Oracle's release blog, InfoWorld's and foojay's write-ups, and then against the
|
||||
**binaries**: the JDK 27 and 26 builds used here were diffed class by class ([51](output/51-api-diff-26-to-27.txt),
|
||||
[52](output/52-api-diff-25-to-26.txt)), which is how two API names in a secondary write-up were corrected. Treat the JEP titles above as
|
||||
"as reported by four secondary sources"; treat every behaviour as "observed on Corretto 26.0.2.1 / 27+35".
|
||||
|
||||
## What was not reproduced
|
||||
|
||||
* JDK-8377013 (a reported `TimeZone.getDefault()` regression) could not be reproduced and is left out.
|
||||
* HTTP/3 was never spoken to a real HTTP/3 server: the sandbox has no UDP egress ([11](11-recap-26.md)).
|
||||
* JEP 522 (G1 synchronization) was not benchmarked.
|
||||
|
||||
Next: [2. G1 becomes the default](02-g1-default.md)
|
||||
@@ -0,0 +1,56 @@
|
||||
# 2. G1 becomes the default, even on one CPU (JEP 523)
|
||||
|
||||
Prev: [1. What shipped](01-what-shipped.md) · Next: [3. Compact object headers](03-compact-headers.md)
|
||||
|
||||
## The old rule
|
||||
|
||||
Since JDK 9 the JVM has chosen its collector by "server-class machine" ergonomics: G1 if it sees at least **two** CPUs and roughly **1792 MB**
|
||||
of memory, Serial otherwise. A container limited to one CPU, or to 1 GB, quietly got Serial. JEP 523 removes the exception: G1 is chosen
|
||||
in every environment.
|
||||
|
||||
## What the containers say
|
||||
|
||||
[`scripts/g1-default.sh`](../scripts/g1-default.sh) runs [`GcReport`](../g1-container/src/GcReport.java) in `amazoncorretto:26` and `:27`
|
||||
containers. Only the JDK version and the limits change.
|
||||
|
||||
| Container | JDK 26 picks | JDK 27 picks | Transcript |
|
||||
|---|---|---|---|
|
||||
| `--cpus=1 --memory=2g` | Serial (`UseSerialGC ... ERGONOMIC`) | G1 | [01](output/01-g1-default-1cpu-vs-2cpu.txt) |
|
||||
| `--cpus=2 --memory=2g` | G1 | G1 | [01](output/01-g1-default-1cpu-vs-2cpu.txt) |
|
||||
| `--cpus=2 --memory=1g` | Serial | G1 | [02](output/02-g1-default-memory.txt) |
|
||||
|
||||
So both halves of the old rule are gone: CPU count *and* memory limit. An explicit `-XX:+UseSerialGC` still wins
|
||||
([03](output/03-g1-default-optout.txt)); its origin shows as `VM_CREATION`, not `ERGONOMIC`.
|
||||
|
||||
## What it costs when your container is small
|
||||
|
||||
[`Workload`](../g1-container/src/Workload.java) allocates 50,000 short-lived objects per batch, keeps about 1% of them, and reports wall time, GC
|
||||
count and time, the slowest single batch and peak RSS. Three runs per configuration, 1 CPU, 2 GB ([04](output/04-g1-cost-1cpu.txt)):
|
||||
|
||||
| 4000 batches | wall time | GC count / total GC time | slowest batch | peak RSS |
|
||||
|---|---|---|---|---|
|
||||
| 26, default (Serial) | 6.0-6.4 s | 1275 / ~1.85 s | 115-142 ms | 557 MB |
|
||||
| 27, default (G1) | 8.2-8.4 s | 140 / ~1.98 s | 35-41 ms | 547 MB |
|
||||
| 27, `-XX:+UseSerialGC` | 5.0-5.7 s | 1264 / ~1.66 s | 119-128 ms | 557 MB |
|
||||
|
||||
The shape, not the digits: on one CPU, G1 has roughly **3x shorter worst-case stalls** and takes **about a third longer** to finish the same allocation-heavy work.
|
||||
G1's concurrent work has to share the only CPU with your application.
|
||||
|
||||
A short-lived process makes it look worse ([05](output/05-g1-cost-1cpu-short.txt), 400 batches): 26 finishes in ~0.53 s using ~102 MB RSS; 27 with G1 takes
|
||||
~1.0 s and touches ~492 MB, because G1 grows the heap toward the 512 MB default maximum instead of collecting early. Serial on 27 matches 26 (~0.52 s, ~98 MB).
|
||||
|
||||
## Two suspects, tested
|
||||
|
||||
[`scripts/g1-tuning.sh`](../scripts/g1-tuning.sh) ([06](output/06-g1-tuning-1cpu.txt)):
|
||||
|
||||
1. JDK 27 also changed the heap free ratios G1 uses (`MinHeapFreeRatio` 40 -> 0, `MaxHeapFreeRatio` 70 -> 100). Restoring 40/70 changed nothing measurable.
|
||||
2. G1 being allowed to grow toward `MaxHeapSize`. Capping the heap at `-Xmx256m` cut peak RSS from ~492 MB to ~294 MB with about the same wall time.
|
||||
|
||||
## Advice
|
||||
|
||||
* Nothing to do if you already set a collector explicitly.
|
||||
* If you were relying on the implicit Serial in small containers and you are throughput- or footprint-bound, pin it: `-XX:+UseSerialGC`.
|
||||
* If you are happy with G1, **set `-Xmx`** (or `-XX:MaxRAMPercentage`) so the heap does not sprawl to the default maximum.
|
||||
* Note `-XX:InitiatingHeapOccupancyPercent` is deprecated in 27 in favour of `-XX:G1IHOP` ([60](output/60-removed-options.txt)).
|
||||
|
||||
Prev: [1. What shipped](01-what-shipped.md) · Next: [3. Compact object headers](03-compact-headers.md)
|
||||
@@ -0,0 +1,36 @@
|
||||
# 3. Compact object headers are the default (JEP 534)
|
||||
|
||||
Prev: [2. G1](02-g1-default.md) · Next: [4. Post-quantum TLS](04-post-quantum-tls.md)
|
||||
|
||||
Every Java object starts with a header. On JDK 26 with default settings it is **12 bytes** (8 bytes mark word plus a 4-byte compressed class pointer).
|
||||
With compact object headers the two are squeezed into **8 bytes**. JEP 534 makes that the default in 27; `-XX:-UseCompactObjectHeaders` turns it off.
|
||||
|
||||
## Measured with JOL
|
||||
|
||||
[`scripts/object-headers.sh`](../scripts/object-headers.sh) downloads JOL 0.17 (sha1-checked) and runs [`HeaderDemo`](../object-headers/src/HeaderDemo.java) three ways.
|
||||
The summary is [15](output/15-headers-summary.txt); raw runs are [10](output/10-headers-jdk26.txt) (26), [11](output/11-headers-jdk27.txt) (27),
|
||||
[12](output/12-headers-jdk27-opt-out.txt) (27 with the opt-out, which reproduces 26 exactly).
|
||||
|
||||
| Object | JDK 26 | JDK 27 |
|
||||
|---|---|---|
|
||||
| `Object` | 16 B | 8 B |
|
||||
| `Point { int x; int y; }` | 24 B | 16 B |
|
||||
| `Order { long id; int quantity; boolean paid; String customer; }` | 32 B | 32 B |
|
||||
| boxed `Long` | 24 B | 16 B |
|
||||
| boxed `Integer` | 16 B | 16 B |
|
||||
| `int[3]` | 32 B | 24 B |
|
||||
| 1,000,000 boxed `Long` in an `ArrayList` | 28.9 MB | 20.9 MB |
|
||||
| 1,000,000 `Point` in an `ArrayList` | 28.9 MB | 20.9 MB |
|
||||
| 1,000,000 boxed `Integer` in an `ArrayList` | 20.9 MB | 20.9 MB |
|
||||
|
||||
The pattern to notice: saving 4 bytes only helps when it crosses an 8-byte alignment boundary. `Order` and boxed `Integer` do not move, because padding
|
||||
was already absorbing the difference. Your heap will not shrink by "4 bytes times object count"; it shrinks by the number of objects that were sitting just past a boundary.
|
||||
|
||||
## Two things that bite
|
||||
|
||||
* **JOL 0.17 cannot inspect a `record`.** `Unsafe.objectFieldOffset` refuses records ([13](output/13-jol-record-failure.txt)). The workaround
|
||||
`-Djol.magicFieldOffset=true` prints a layout but shows the header mark as `N/A` ([14](output/14-jol-record-workaround.txt)).
|
||||
* **Anything that hard-codes 12 bytes** (off-heap size estimators, "object overhead" constants in capacity plans, tests that assert `Instance size`) is now wrong by default.
|
||||
`-XX:+UseCompressedClassPointers` is also no longer an option in 27: the JVM prints "Ignoring option UseCompressedClassPointers; support was removed in 27.0" ([60](output/60-removed-options.txt)).
|
||||
|
||||
Prev: [2. G1](02-g1-default.md) · Next: [4. Post-quantum TLS](04-post-quantum-tls.md)
|
||||
@@ -0,0 +1,36 @@
|
||||
# 4. Post-quantum hybrid key exchange in TLS 1.3 (JEP 527)
|
||||
|
||||
Prev: [3. Compact headers](03-compact-headers.md) · Next: [5. Primitive patterns](05-primitive-patterns.md)
|
||||
|
||||
JDK 27's default TLS 1.3 client offers the hybrid group **X25519MLKEM768** first: an ordinary X25519 exchange and an ML-KEM-768 key encapsulation combined, so a
|
||||
recorded session stays safe even if a large quantum computer later breaks X25519.
|
||||
|
||||
## Who negotiates what
|
||||
|
||||
[`scripts/tls-pq.sh`](../scripts/tls-pq.sh) starts a loopback TLS server with [`TlsPeer`](../jep-tour/src/TlsPeer.java) on one JDK and connects with a client on
|
||||
the other, for all four pairings, with `-Djavax.net.debug=ssl:handshake` ([30](output/30-tls-groups-matrix.txt)).
|
||||
|
||||
| Client | Server | Group selected |
|
||||
|---|---|---|
|
||||
| 26 | 26 | x25519 |
|
||||
| 27 | 27 | **X25519MLKEM768** |
|
||||
| 27 | 26 | x25519 (the 26 server does not know the hybrid group) |
|
||||
| 26 | 27 | x25519 (the 26 client never offered it) |
|
||||
|
||||
Nothing fails when the peers disagree: the hybrid only happens when both ends are on 27 (or another stack that supports it).
|
||||
|
||||
## The catch: a bigger first packet
|
||||
|
||||
[`ClientHelloSize`](../jep-tour/src/ClientHelloSize.java) captures the first TLS record ([31](output/31-tls-clienthello-size.txt)):
|
||||
|
||||
| Client | ClientHello record | Fits one TCP segment (1460-byte MSS)? |
|
||||
|---|---|---|
|
||||
| JDK 26 | 417 bytes | yes |
|
||||
| JDK 27 | 1573 bytes | **no** |
|
||||
| JDK 27, `-Djdk.tls.namedGroups=x25519,secp256r1` | 408 bytes | yes |
|
||||
|
||||
The ML-KEM public key alone is 1184 bytes, so the ClientHello no longer fits in one segment. Middleboxes that mishandle a ClientHello spanning segments are the
|
||||
known failure mode of large post-quantum ClientHellos; **that failure was not observed here** (loopback has no middleboxes). If you meet it, the opt-out is the system
|
||||
property above, and the client then behaves like 26 ([32](output/32-tls-opt-out.txt)).
|
||||
|
||||
Prev: [3. Compact headers](03-compact-headers.md) · Next: [5. Primitive patterns](05-primitive-patterns.md)
|
||||
@@ -0,0 +1,32 @@
|
||||
# 5. Primitive types in patterns (JEP 532, fifth preview)
|
||||
|
||||
Prev: [4. Post-quantum TLS](04-post-quantum-tls.md) · Next: [6. Lazy constants](06-lazy-constants.md)
|
||||
|
||||
Compile and run with `--enable-preview --release 27`. Source: [`PrimitivePatterns`](../jep-tour/src/PrimitivePatterns.java), transcript [23](output/23-primitive-patterns.txt).
|
||||
|
||||
## The idea in one sentence
|
||||
|
||||
A pattern may now name a primitive type, and the test is **"can this value be converted to that type without losing information?"**. It is an exactness test, not a cast.
|
||||
|
||||
```java
|
||||
int small = 100, big = 300;
|
||||
small instanceof byte // true : 100 fits
|
||||
big instanceof byte // false : a byte holds -128..127
|
||||
16_777_216 instanceof float // true
|
||||
16_777_217 instanceof float // false : a float has a 24-bit significand
|
||||
```
|
||||
|
||||
You can also `switch` on a `long`, `float`, `double` or `boolean`, use `case int` against an `Integer`, and put a narrowing primitive in a record pattern:
|
||||
`Reading(byte c)` matches `Reading[celsius=36]` but not `Reading[celsius=4000]` ([23](output/23-primitive-patterns.txt)).
|
||||
|
||||
## The compile error you will meet
|
||||
|
||||
Dominance rules apply. Put `case Integer i` before `case int primitive` and the second label can never match:
|
||||
|
||||
```
|
||||
error: this case label is dominated by a preceding case label
|
||||
```
|
||||
|
||||
The real text is in [20-broken-dominated.txt](output/20-broken-dominated.txt); source in [`Dominated.java`](../jep-tour/src/broken/Dominated.java).
|
||||
|
||||
Prev: [4. Post-quantum TLS](04-post-quantum-tls.md) · Next: [6. Lazy constants](06-lazy-constants.md)
|
||||
@@ -0,0 +1,23 @@
|
||||
# 6. Lazy constants (JEP 531, third preview)
|
||||
|
||||
Prev: [5. Primitive patterns](05-primitive-patterns.md) · Next: [7. Structured concurrency](07-structured-concurrency.md)
|
||||
|
||||
Compile and run with `--enable-preview --release 27`. Source: [`LazyDemo`](../jep-tour/src/LazyDemo.java), transcript [22](output/22-lazy.txt).
|
||||
|
||||
A **lazy constant** holds a value that is computed the first time somebody asks for it, exactly once, even when many threads ask at the same instant,
|
||||
after which the JVM may treat it like a `final` field. It replaces the hand-written holder-class idiom and the double-checked-locking field.
|
||||
|
||||
```java
|
||||
static final LazyConstant<Settings> SETTINGS = LazyConstant.of(LazyDemo::loadSettings);
|
||||
Settings s = SETTINGS.get(); // computes on first call, returns the same instance afterwards
|
||||
```
|
||||
|
||||
What the transcript shows, each backed by an assertion: the supplier ran once; 64 virtual threads racing on `get()` caused one initialisation; `List.ofLazy(5, i -> ...)`
|
||||
computed only element 3 after `get(3)`; `Map.ofLazy(keys, f)` computed only the requested key; `Set.ofLazy(Set.of(2..7), isPrime)` answers `contains` on demand.
|
||||
|
||||
## What changed since 26 (the compile errors)
|
||||
|
||||
* `LazyConstant.orElse(...)` and `isInitialized()` are **gone** in 27 ([20-broken-lazy26.txt](output/20-broken-lazy26.txt); the class is `LazyConstant` in both, the old `StableValue` was already removed in 26 - [52](output/52-api-diff-25-to-26.txt)).
|
||||
* `Set.ofLazy(Set, Predicate)` is new in 27 ([62](output/62-new-api.txt), [51](output/51-api-diff-26-to-27.txt)).
|
||||
|
||||
Prev: [5. Primitive patterns](05-primitive-patterns.md) · Next: [7. Structured concurrency](07-structured-concurrency.md)
|
||||
@@ -0,0 +1,27 @@
|
||||
# 7. Structured concurrency (JEP 533, seventh preview)
|
||||
|
||||
Prev: [6. Lazy constants](06-lazy-constants.md) · Next: [8. PEM](08-pem-api.md)
|
||||
|
||||
Compile and run with `--enable-preview --release 27`. Source: [`StructuredDemo`](../jep-tour/src/StructuredDemo.java), transcript [21](output/21-structured.txt).
|
||||
|
||||
The 27 API, as exercised:
|
||||
|
||||
```java
|
||||
try (var scope = StructuredTaskScope.open(Joiner.<String>allSuccessfulOrThrow())) {
|
||||
scope.fork(StructuredDemo::fetchPrice);
|
||||
scope.fork(StructuredDemo::fetchStock);
|
||||
List<String> results = scope.join(); // [price=42, stock=7], in fork order
|
||||
}
|
||||
```
|
||||
|
||||
* A failing subtask makes `join()` throw `ExecutionException` with the original as its cause.
|
||||
* **New in 27:** `StructuredTaskScope` and `Joiner` gained a third type parameter, the exception `join()` throws. `Joiner.<String, OrderFailed>allSuccessfulOrThrow(OrderFailed::new)` makes `join()` throw *your* type.
|
||||
* A timeout is a scope option (`cfg -> cfg.withTimeout(Duration.ofMillis(100))`) and surfaces as `CancelledByTimeoutException`.
|
||||
|
||||
## What broke from 26
|
||||
|
||||
[`StructuredScope26.java`](../jep-tour/src/broken/StructuredScope26.java) compiles on 26 and fails on 27 with three errors ([20-broken-structuredscope26.txt](output/20-broken-structuredscope26.txt)):
|
||||
`wrong number of type arguments; required 3`, and `FailedException` / `TimeoutException` no longer exist as nested classes
|
||||
([51](output/51-api-diff-26-to-27.txt): removed `StructuredTaskScope$FailedException`, `$TimeoutException`; added `$CancelledByTimeoutException`).
|
||||
|
||||
Prev: [6. Lazy constants](06-lazy-constants.md) · Next: [8. PEM](08-pem-api.md)
|
||||
@@ -0,0 +1,27 @@
|
||||
# 8. PEM encodings (JEP 538, third preview)
|
||||
|
||||
Prev: [7. Structured concurrency](07-structured-concurrency.md) · Next: [9. JFR redaction and the Vector API](09-jfr-redaction-and-vector.md)
|
||||
|
||||
Compile and run with `--enable-preview --release 27`. Source: [`PemDemo`](../jep-tour/src/PemDemo.java), transcript [24](output/24-pem.txt).
|
||||
|
||||
PEM is the `-----BEGIN ...-----` text format that every key and certificate file on a Linux box uses. The preview API replaces hand-rolled Base64 and header strings:
|
||||
|
||||
```java
|
||||
String pem = PEMEncoder.of().encodeToString(keyPair.getPublic()); // -----BEGIN PUBLIC KEY-----
|
||||
PublicKey back = PEMDecoder.of().decode(pem, PublicKey.class);
|
||||
String enc = PEMEncoder.of().withEncryption(password).encodeToString(privateKey); // ENCRYPTED PRIVATE KEY
|
||||
```
|
||||
|
||||
Each round trip is asserted in the demo, including: without the password `decode` returns a still-encrypted `EncryptedPrivateKeyInfo`; with `withDecryption(password)` you get the original key back.
|
||||
|
||||
## The trap: `new PEM(type, byte[])` does not Base64-encode
|
||||
|
||||
The bytes you pass are treated as the **already Base64-encoded** content and written between the header and footer verbatim
|
||||
([24](output/24-pem.txt): the demo prints `hello, pem` in clear between `BEGIN ANKURM DEMO` and `END ANKURM DEMO`). To get a valid PEM, Base64-encode first and pass that; then `content()` is the Base64 text and `decode()` gives your payload back. This cost a failed assertion while writing this repository.
|
||||
|
||||
## What moved between 26 and 27
|
||||
|
||||
[`Pem26Style.java`](../jep-tour/src/broken/Pem26Style.java) compiles on 26 and produces three errors on 27 ([20-broken-pem26style.txt](output/20-broken-pem26style.txt)): `DEREncodable` became `BinaryEncodable`;
|
||||
`PEMDecoder.withFactory(Provider)` is gone; `PEM.content()` now returns `byte[]` rather than `String`.
|
||||
|
||||
Prev: [7. Structured concurrency](07-structured-concurrency.md) · Next: [9. JFR redaction and the Vector API](09-jfr-redaction-and-vector.md)
|
||||
@@ -0,0 +1,28 @@
|
||||
# 9. JFR redaction (JEP 536) and the Vector API (JEP 537)
|
||||
|
||||
Prev: [8. PEM](08-pem-api.md) · Next: [10. Other 27 changes](10-other-27-changes.md)
|
||||
|
||||
## JFR redacts secrets in the recording by default
|
||||
|
||||
A JFR file records the JVM's command-line arguments, system properties and environment variables. Those routinely hold passwords and tokens, and recordings get attached to tickets.
|
||||
[`scripts/jfr-redaction.sh`](../scripts/jfr-redaction.sh) starts an [`Idle`](../jep-tour/src/Idle.java) process with `-Dapi.token=abc123 -Dregion=ap-south-1 ... --password=hunter2 --user=ankur`
|
||||
and `DB_PASSWORD=hunter2` in the environment, then prints what reached the file ([40](output/40-jfr-redaction.txt)):
|
||||
|
||||
| Configuration | `-Dapi.token` | `--password` | `DB_PASSWORD` | `region` |
|
||||
|---|---|---|---|---|
|
||||
| JDK 26 | abc123 | hunter2 | hunter2 | ap-south-1 |
|
||||
| JDK 27 default | `[REDACTED]` | `[REDACTED]` | `[REDACTED]` | ap-south-1 |
|
||||
| 27, `redact-argument=--user*,redact-key=region` | abc123 (exposed) | hunter2 (exposed) | hunter2 (exposed) | `[REDACTED]` |
|
||||
| 27, `redact-argument=+--user*,redact-key=+region` | `[REDACTED]` | `[REDACTED]` | `[REDACTED]` | `[REDACTED]` |
|
||||
| 27, `redact-argument=none,redact-key=none` | abc123 | hunter2 | hunter2 | ap-south-1 |
|
||||
|
||||
**The trap in row 3:** a list you supply *replaces* the built-in patterns. Without the `+` prefix you have silently turned the defaults off for everything you did not list.
|
||||
|
||||
## The Vector API is still incubating
|
||||
|
||||
[`VectorDemo`](../jep-tour/src/VectorDemo.java) ([25](output/25-vector.txt)) computes a dot product with and without `jdk.incubator.vector` and asserts they agree within 0.1%.
|
||||
The same class file runs on 26 (eleventh incubator, JEP 529) and 27 (twelfth, JEP 537): the only public API change between them is that `VectorOperators` changed from `abstract` to `final`
|
||||
([50](output/50-vector-api-surface.txt)). The preferred species is machine dependent (`S_512_BIT`, 16 float lanes, on the machine that wrote the transcript).
|
||||
For the API itself see the ankurm.com guide: <https://ankurm.com/java-vector-api-jep-537-simd-guide/>.
|
||||
|
||||
Prev: [8. PEM](08-pem-api.md) · Next: [10. Other 27 changes](10-other-27-changes.md)
|
||||
@@ -0,0 +1,25 @@
|
||||
# 10. The changes that are not JEPs but will still break a Monday
|
||||
|
||||
Prev: [9. JFR and Vector](09-jfr-redaction-and-vector.md) · Next: [11. Recap of Java 26](11-recap-26.md)
|
||||
|
||||
Script: [`scripts/other-changes.sh`](../scripts/other-changes.sh). All from real launches; each option runs `java <option> -version` on 26 and on 27 ([60](output/60-removed-options.txt)).
|
||||
|
||||
| Option / property | JDK 26 | JDK 27 |
|
||||
|---|---|---|
|
||||
| `-noverify`, `-Xverify:none` | deprecation warning | **`Unrecognized option`, the JVM does not start** |
|
||||
| `-noclassgc` | deprecation warning | **`Unrecognized option`, the JVM does not start** |
|
||||
| `-XX:+UseCompressedClassPointers` | deprecated in 25 | ignored: "support was removed in 27.0" |
|
||||
| `-XX:InitiatingHeapOccupancyPercent=40` | accepted | deprecated; use `-XX:G1IHOP` |
|
||||
| `-XX:+UseGraalJIT` (experimental) | JVMCI error | `Unrecognized VM option` (JVMCI hook removed) |
|
||||
| `-Djdk.lang.Process.launchMechanism=VFORK` | deprecation banner | "has been removed. Switching to FORK instead" ([61](output/61-behaviour-changes.txt)) |
|
||||
| `-Djava.locale.useOldISOCodes=true` | works, deprecated | ignored: `Locale("iw").language` is `he` ([61](output/61-behaviour-changes.txt)) |
|
||||
|
||||
**The point of the table:** rows 1-2 are the ones that stop a service from starting. They are old flags that live in Dockerfiles and `JAVA_TOOL_OPTIONS` long after anyone remembers why.
|
||||
Grep your images before you upgrade.
|
||||
|
||||
## New public API worth knowing
|
||||
|
||||
Found by diffing `javap` dumps ([51](output/51-api-diff-26-to-27.txt)) and exercised once each in [`Api27`](../other-changes/src/Api27.java) ([62](output/62-new-api.txt)):
|
||||
`Math.acosh/asinh/atanh`, `String.encodedLength(Charset)` (length in bytes without allocating the array), `BigDecimal.rootn`, `KeyStore.getCreationInstant`.
|
||||
|
||||
Prev: [9. JFR and Vector](09-jfr-redaction-and-vector.md) · Next: [11. Recap of Java 26](11-recap-26.md)
|
||||
@@ -0,0 +1,68 @@
|
||||
# 11. Recap: the Java 26 changes you skipped
|
||||
|
||||
Prev: [10. Other 27 changes](10-other-27-changes.md) · Next: [12. Version lanes 25 - 29](12-lanes-25-to-29.md)
|
||||
|
||||
Java 26 (GA 2026-03-17) is also a non-LTS release. If you are on 25 and going to 27 you meet all of it at once. Script: [`scripts/recap26.sh`](../scripts/recap26.sh).
|
||||
|
||||
## JEP 500: final means final
|
||||
|
||||
Reflection has always let `Field.setAccessible(true)` followed by `Field.setInt(...)` overwrite a `final` field. Source: [`FinalFieldMutation`](../recap26/src/FinalFieldMutation.java), transcript [70](output/70-final-field-mutation.txt).
|
||||
|
||||
| Run | Result |
|
||||
|---|---|
|
||||
| JDK 25 | silent |
|
||||
| JDK 26 default | three `WARNING:` lines, then it proceeds |
|
||||
| JDK 26 `--enable-final-field-mutation=ALL-UNNAMED` | silent (the opt-in the warning names) |
|
||||
| JDK 26 `--illegal-final-field-mutation=deny` | `IllegalAccessException`: "... is not allowed to mutate final fields" |
|
||||
| JDK 26 `--illegal-final-field-mutation=debug` | the warning plus the stack trace of the offending call |
|
||||
|
||||
`--illegal-final-field-mutation` takes `allow`, `warn`, `debug` or `deny`. A JFR event, `jdk.FinalFieldMutation`, is recorded with default settings whenever a mutation is *permitted*
|
||||
(one event, with the declaring class and field name); under `deny` there is nothing to record.
|
||||
|
||||
Even when it works it misleads: the field reads 9090 but `port()` still returns 8080, because `final int port = 8080` is a constant variable and javac copied the literal into the method.
|
||||
|
||||
Who this hits: serialisation libraries, mocking frameworks, dependency-injection containers and test code that set `final` fields. Run your test suite once with `deny` on 26 or later.
|
||||
|
||||
## JEP 504: the Applet API is gone
|
||||
|
||||
`java.applet.*`, `javax.swing.JApplet` and the `AppletInitializer` overload of `java.beans.Beans.instantiate` were removed ([52](output/52-api-diff-25-to-26.txt)).
|
||||
[`AppletGone.java`](../recap26/src/broken/AppletGone.java) compiles on 25 with a `[removal]` warning and fails on 26 with `package java.applet does not exist` ([73](output/73-removed-in-26.txt)).
|
||||
In the same transcript, [`ThreadStopGone.java`](../recap26/src/broken/ThreadStopGone.java): `Thread.stop()` (which has thrown `UnsupportedOperationException` since 20) no longer exists at all: `cannot find symbol`.
|
||||
|
||||
## JEP 516: AOT object caching with any GC
|
||||
|
||||
The AOT cache (JEP 483 / 514 / 515 in 24 and 25) stores pre-parsed and pre-linked classes and, in some configurations, pre-built heap objects such as the module graph.
|
||||
Until 26 the heap-object part needed G1. Workflow used here: `-XX:AOTMode=record -XX:AOTConfiguration=...`, then `-XX:AOTMode=create -XX:AOTCache=...`, then run with `-XX:AOTCache=...`.
|
||||
|
||||
What the JVM's own log says ([71](output/71-aot-cache-matrix.txt)):
|
||||
|
||||
| Cache built under | Run under | JDK 25 | JDK 26 / 27 |
|
||||
|---|---|---|---|
|
||||
| G1 | G1 or Serial | heap objects used | heap objects used |
|
||||
| G1 | ZGC | cache refused | cache refused |
|
||||
| ZGC | ZGC | cache used, **heap objects not used** | **heap objects used** |
|
||||
| ZGC | G1 or Serial | cache refused | cache refused |
|
||||
|
||||
So "any GC" means *each* GC can now benefit, not that one cache serves every GC: the cache records whether compressed oops were on
|
||||
(`The saved state of UseCompressedOops (1) is different from runtime (0), CDS will be disabled`), and ZGC does not use them. Build the cache under the collector you deploy with.
|
||||
|
||||
Startup, median of 9 runs, indicative only ([72](output/72-aot-startup.txt)): with ZGC, JDK 25 barely moves (about 83 -> 81 ms, because no heap objects are used), while JDK 26 and 27 go from about 62 to about 40 ms; with G1 all three go from about 60 to about 35-37 ms.
|
||||
A 27 JVM has a new diagnostic flag `AOTCompatibleOopCompression`; setting it at cache creation did not make a G1-built cache load under ZGC in one attempt, and nothing more was investigated.
|
||||
|
||||
## JEP 517: HTTP/3 in the HTTP client
|
||||
|
||||
`HttpClient.Version.HTTP_3`, `HttpOption.H3_DISCOVERY` and `HttpOption.Http3DiscoveryMode` (`ANY`, `ALT_SVC`, `HTTP_3_URI_ONLY`) are the API surface ([75](output/75-http3-fallback.txt), from `javap`).
|
||||
The sandbox has no UDP egress, so no real HTTP/3 exchange was run. What [`Http3Fallback`](../recap26/src/Http3Fallback.java) shows instead: a client that *prefers* HTTP/3 against a TLS server that only speaks HTTP/1.1
|
||||
falls back and `response.version()` says `HTTP_1_1`; a request pinned to `HTTP_3_URI_ONLY` fails with `HttpConnectTimeoutException: quic handshake timeout`.
|
||||
|
||||
## JEP 522: G1 throughput
|
||||
|
||||
"Improve throughput by reducing synchronization between application and GC threads." Not benchmarked here; it is a claim from the JEP, and it is the reason 26 is a fairer G1 baseline than 25 in [chapter 2](02-g1-default.md).
|
||||
|
||||
## New public API without a JEP
|
||||
|
||||
Verified by javap diff ([52](output/52-api-diff-25-to-26.txt)) and asserted in [`Api26`](../recap26/src/Api26.java) ([74](output/74-api26.txt)): `String.equalsFoldCase`, `compareToFoldCase` and `UNICODE_CASEFOLD_ORDER`
|
||||
(`"STRASSE".equalsFoldCase("straße")` is true; `equalsIgnoreCase` says false), `UUID.ofEpochMillis` (a version-7 UUID for a given instant), `Process` implementing `Closeable`,
|
||||
`MemoryMXBean.getTotalGcCpuTime()`, `ByteOrder` becoming an enum, `HPKEParameterSpec` (Hybrid Public Key Encryption), and the Unicode 17 blocks in `Character.UnicodeBlock`.
|
||||
|
||||
Prev: [10. Other 27 changes](10-other-27-changes.md) · Next: [12. Version lanes 25 - 29](12-lanes-25-to-29.md)
|
||||
@@ -0,0 +1,31 @@
|
||||
# 12. Version lanes: 25 (LTS) to 29 (next LTS)
|
||||
|
||||
Ordinals in the 25 column come from Java 25's published JEP list (470, 502, 505, 507, 508), not from a run here; the existence of `StableValue` and `PEMRecord` in 25 and their absence in 26 *was* observed ([52](output/52-api-diff-25-to-26.txt)).
|
||||
|
||||
Prev: [11. Recap of Java 26](11-recap-26.md) · Next: [13. Upgrade checklist](13-upgrade-checklist.md) · Coming from 21: [14](14-lanes-21-to-25.md)
|
||||
|
||||
Dates and support windows are from Oracle's Java SE Support Roadmap, read on 2026-09-21: <https://www.oracle.com/java/technologies/java-se-support-roadmap.html>.
|
||||
Feature notes link to the chapter that has the run.
|
||||
|
||||
| Release | GA | Kind | Premier support until | What to read here |
|
||||
|---|---|---|---|---|
|
||||
| 25 | Sept 2025 | **LTS** | Sept 2030 | the baseline for every "broke on 26/27" demo in this repository |
|
||||
| 26 | March 2026 | non-LTS | Sept 2026 | [chapter 11](11-recap-26.md): final-field warnings, Applet removal, HTTP/3, AOT with any GC |
|
||||
| 27 | Sept 2026 | non-LTS | March 2027 | chapters [2](02-g1-default.md) - [10](10-other-27-changes.md): G1 default, compact headers, PQ TLS, JFR redaction |
|
||||
| 28 | March 2027 | non-LTS (planned) | Sept 2027 | not covered: not released |
|
||||
| 29 | Sept 2027 | **LTS (planned)** | Sept 2032 | not covered: not released |
|
||||
|
||||
Oracle's stated cadence: "Oracle intends to make future LTS releases every two years meaning the next planned LTS release is Java 29 in September 2027."
|
||||
Other vendors set their own support lengths for non-LTS builds; check the vendor you deploy.
|
||||
|
||||
The preview-feature ladder across the lane (each preview must be recompiled and can break the next release, see [20-broken-*](output/)):
|
||||
|
||||
| Feature | 25 | 26 | 27 |
|
||||
|---|---|---|---|
|
||||
| Structured Concurrency | 5th preview (JEP 505); `--enable-preview` needed, run in [82](output/82-structured-not-final.txt) | 6th preview (JEP 525), `anySuccessfulResultOrThrow` renamed `anySuccessfulOrThrow` ([89](output/89-joiner-api.txt)) | 7th preview (JEP 533), API reshaped |
|
||||
| Lazy Constants (was Stable Values in 25) | Stable Values, preview | 2nd preview (JEP 526) | 3rd preview (JEP 531), `orElse`/`isInitialized` removed |
|
||||
| PEM encodings | 1st preview (`PEMRecord`) | 2nd preview (JEP 524) | 3rd preview (JEP 538), `DEREncodable` renamed |
|
||||
| Primitive patterns | 3rd preview | 4th preview (JEP 530) | 5th preview (JEP 532) |
|
||||
| Vector API | 10th incubator | 11th (JEP 529) | 12th (JEP 537) |
|
||||
|
||||
Prev: [11. Recap of Java 26](11-recap-26.md) · Next: [13. Upgrade checklist](13-upgrade-checklist.md) · Coming from 21: [14](14-lanes-21-to-25.md)
|
||||
@@ -0,0 +1,18 @@
|
||||
# 13. Upgrade checklist: 25 to 27 (or to 26)
|
||||
|
||||
Prev: [12. Version lanes](12-lanes-25-to-29.md) · Next: [14. The 21 to 25 lane](14-lanes-21-to-25.md) · [Back to the README](../README.md)
|
||||
|
||||
Ordered by "will stop a service from starting" first.
|
||||
|
||||
1. **Grep for flags that no longer exist.** `-noverify`, `-Xverify:none` and `-noclassgc` make a 27 JVM refuse to start ([60](output/60-removed-options.txt)). Look in Dockerfiles, `JAVA_TOOL_OPTIONS`, systemd units and start scripts.
|
||||
2. **Pin your collector in small containers.** If nobody sets one, 27 gives you G1 on one CPU, where 26 gave you Serial ([02](02-g1-default.md)). Decide on purpose, and set `-Xmx` or `-XX:MaxRAMPercentage`.
|
||||
3. **Run your tests once with `--illegal-final-field-mutation=deny` on 26 or later.** Mocking, DI and serialisation libraries are the usual offenders ([11](11-recap-26.md)).
|
||||
4. **Compile everything on 26 and 27.** `java.applet`, `JApplet` and `Thread.stop()` are gone ([73](output/73-removed-in-26.txt)).
|
||||
5. **Test TLS through your real network path.** JDK 27 clients send a 1573-byte ClientHello ([04](04-post-quantum-tls.md)). If a middlebox objects, `-Djdk.tls.namedGroups=x25519,secp256r1` restores the old behaviour.
|
||||
6. **Search for hard-coded object sizes.** Estimators, capacity plans and tests that assume a 12-byte header ([03](03-compact-headers.md)).
|
||||
7. **Do not ship preview APIs from a library.** Structured concurrency, lazy constants and PEM changed API between 26 and 27, and primitive patterns is now on its fifth preview ([12](12-lanes-25-to-29.md)).
|
||||
8. **Check custom JFR redaction settings.** A list without `+` replaces the defaults ([09](09-jfr-redaction-and-vector.md)).
|
||||
9. **Rebuild AOT caches per JDK and per collector** ([11](11-recap-26.md)).
|
||||
10. **Decide whether to move at all.** 26 and 27 are non-LTS: 26's premier support ends September 2026 and 27's in March 2027. Staying on 25 and planning for 29 is a legitimate answer ([12](12-lanes-25-to-29.md)).
|
||||
|
||||
Prev: [12. Version lanes](12-lanes-25-to-29.md) · [Back to the README](../README.md)
|
||||
@@ -0,0 +1,40 @@
|
||||
# 14. The 21 to 25 lane: every claim in the hub posts, checked
|
||||
|
||||
Prev: [13. Upgrade checklist](13-upgrade-checklist.md) · [Back to the README](../README.md)
|
||||
|
||||
The two Java version guides on ankurm.com ([features](https://ankurm.com/java-21-to-25-lts-features/), [upgrade guide](https://ankurm.com/java-21-to-25-upgrade-guide-ai-prompts/))
|
||||
make about twenty checkable claims. `scripts/lanes.sh` checks each one on JDK 21, 25, 26 and 27, plus 23 and 24 (from the `amazoncorretto:23` and `:24`
|
||||
images) where the question is *when* something changed. The verdicts are below; the transcripts are the proof.
|
||||
|
||||
| Claim | Verdict | Where it changed | Transcript |
|
||||
|---|---|---|---|
|
||||
| Records, pattern-matching `switch`, virtual threads, sequenced collections from the article run unchanged on 21, 25, 26, 27 | true | final in 21 | [80](output/80-hub-examples.txt) |
|
||||
| Scoped values are final in 25 | true | preview in 21, final in 25 (JEP 506) | [81](output/81-scoped-values.txt) |
|
||||
| Structured concurrency is final in 25 | **false: still preview** | 5th preview in 25, 6th in 26, 7th in 27; `--enable-preview` is required on all three | [82](output/82-structured-not-final.txt) |
|
||||
| `Joiner.anySuccessfulResultOrThrow()` (the article's code) works on 26 and 27 | **false: renamed** | `anySuccessfulOrThrow()` from 26; `allSuccessfulOrThrow()` returns a `List` instead of a `Stream` from 26; a third type parameter arrives in 27 | [82](output/82-structured-not-final.txt), [89](output/89-joiner-api.txt) |
|
||||
| Finalization is removed by default | **false: still on** | `finalize()` still runs on 21, 25, 26 and 27 unless you pass `--finalization=disabled` | [83](output/83-finalization.txt) |
|
||||
| `System.setSecurityManager()` throws `UnsupportedOperationException` | true | already on 21 by default; permanent from 24 (JEP 486) | [84](output/84-security-manager.txt) |
|
||||
| `Thread.stop`, `suspend` and `resume` are removed | **half true** | `suspend`/`resume` compile on 21 and do not compile on 23, 24, 25 or 26; `stop()` still compiles on 25 and throws; removed in 26 | [85](output/85-thread-stop-suspend.txt), [73](output/73-removed-in-26.txt) |
|
||||
| `sun.misc.Unsafe` memory methods warn | true from 24 | none on 21, warning on 24 and 25 (JEP 498) | [86](output/86-unsafe-and-jni.txt) |
|
||||
| JNI use warns by default | true from 24 | none on 21, warning on 24 and 25 (JEP 472) | [86](output/86-unsafe-and-jni.txt) |
|
||||
| Virtual threads pin their carrier inside `synchronized` on "Java 21 to 24" | **false: 21 to 23** | pinned on 21 and 23, not pinned on 24, 25, 26, 27 (JEP 491) | [87](output/87-pinning.txt) |
|
||||
| "Java 25 ships an improved generational ZGC mode" | **misleading** | generational is the only ZGC from 24; `-XX:-ZGenerational` is ignored with a warning on 24 and 25 and rejected on 26 and 27 | [88](output/88-zgc-generational.txt) |
|
||||
| Reflection writing to a `final` field warns from 26 | true | silent on 25, warns on 26 and 27 (JEP 500) | [70](output/70-final-field-mutation.txt), [91](output/91-final-field-mutation-27.txt) |
|
||||
| Unnamed patterns and unnamed classes are final in 25 | **half true** | the underscore was final in 22 (JEP 456); compact source files with instance `main()` (JEP 512) are final in 25 | [90](output/90-unnamed-and-compact.txt) |
|
||||
|
||||
Build-file claims (`--release`, Gradle, Lombok, Mockito, annotation processing, `jdeps`) are checked in [chapter 15](15-build-files.md).
|
||||
|
||||
Claims about other projects came from their own pages, read on 2026-09-21, not from a run:
|
||||
|
||||
| Claim | Verdict | Source |
|
||||
|---|---|---|
|
||||
| Spring Boot 3.4 is the first with official Java 25 support | **false** | Spring Boot 3.4.x is documented up to Java 24, 3.5.x up to Java 25, 4.1.1 up to Java 26 ([system requirements](https://docs.spring.io/spring-boot/system-requirements.html)); 27 is not listed yet |
|
||||
| Lombok 1.18.34 or later works on Java 25 | **false** | JDK 25 support arrived in 1.18.40 (2025-09-04), JDK 26 in 1.18.46, JDK 27 in 1.18.48 ([changelog](https://projectlombok.org/changelog)); a run confirms 1.18.34 fails on 25 ([95](output/95-lombok-matrix.txt), [chapter 15](15-build-files.md)) |
|
||||
| Mockito 5.12 or later is enough for Java 25 | **false** (run) | 5.12.0 and 5.17.0 cannot mock an interface on 25 or 27; 5.18.0 is the first that can ([97](output/97-mockito-bytebuddy.txt), [chapter 15](15-build-files.md)) |
|
||||
| Hibernate 7 requires Jakarta EE 10 | **false** | Hibernate ORM 7.0 requires Jakarta Persistence 3.2 (Jakarta EE 11) ([release page](https://hibernate.org/orm/releases/7.0/)) |
|
||||
|
||||
The next chapter is [15](15-build-files.md), the build-file half; [12](12-lanes-25-to-29.md) carries the lane table forward to 29.
|
||||
|
||||
`prompts/` holds the thirteen AI prompts from the two posts, one per file, corrected to match this chapter.
|
||||
|
||||
Prev: [13. Upgrade checklist](13-upgrade-checklist.md) · [Back to the README](../README.md)
|
||||
@@ -0,0 +1,61 @@
|
||||
# 15. Build files: what the 21 to 25 upgrade does to Maven, Gradle and Lombok
|
||||
|
||||
Prev: [14. The 21 to 25 lane](14-lanes-21-to-25.md) · [Back to the README](../README.md)
|
||||
|
||||
The build half of the [upgrade guide](https://ankurm.com/java-21-to-25-upgrade-guide-ai-prompts/), run by `scripts/upgrade.sh`.
|
||||
Everything below is a run on JDK 21, 23, 24, 25, 26 or 27; the transcripts are in `output/92` to `output/97`.
|
||||
|
||||
## 15.1 Maven: `maven.compiler.release`
|
||||
|
||||
[`lanes/upgrade/pom.xml`](../lanes/upgrade/pom.xml) sets `maven.compiler.source`, `target` and `release` to 25.
|
||||
|
||||
* Building on **JDK 21** fails at once: `error: release version 25 not supported`. The build JDK has to be 25 before the release can be 25 ([92](output/92-maven-release.txt)).
|
||||
* Building on **JDK 25** succeeds and the class file has major version 69. Building on **JDK 27** with `release` still 25 also succeeds and also produces version 69: a newer JDK can compile for 25. Running that class on JDK 21 gives `UnsupportedClassVersionError` (65 is Java 21).
|
||||
* `--release N` restricts the compiler to the *API of release N*, not just the language level and byte-code version. [94](output/94-release-flag.txt): JDK 27's `javac --release 25` rejects `String.equalsFoldCase` (new in 26).
|
||||
`javac -source 25 -target 25` compiles it with a warning, and the class then dies on a JDK 25 with `NoSuchMethodError`. That, and not "rejecting internal APIs", is what `--release` buys you.
|
||||
|
||||
## 15.2 Gradle: the toolchain block, and the JDK that runs Gradle
|
||||
|
||||
[`lanes/upgrade/build.gradle.kts`](../lanes/upgrade/build.gradle.kts) asks for a Java 25 toolchain. Two different JDKs are involved ([93](output/93-gradle-toolchain.txt)):
|
||||
|
||||
* the toolchain JDK, which compiles your code: Gradle 8.14.3 found and used JDK 25 for this while itself running on JDK 21;
|
||||
* the JDK that runs Gradle itself: Gradle 8.14.3 on JDK 25 fails (`25.0.4.1` with a Kotlin DSL script; `Unsupported class file major version 69` with a Groovy one, seen in a side run), Gradle 9.1.0 on JDK 25 works.
|
||||
|
||||
Gradle's [compatibility table](https://docs.gradle.org/current/userguide/compatibility.html), read 2026-09-21: Java 25 needs Gradle 9.1.0, Java 26 needs 9.4.0, and Java 27 is not listed for any release yet.
|
||||
|
||||
## 15.3 Lombok and annotation processing
|
||||
|
||||
[`lanes/src/LombokProbe.java`](../lanes/src/LombokProbe.java) needs Lombok's processor to compile. [95](output/95-lombok-matrix.txt):
|
||||
|
||||
| Lombok | JDK 25 | JDK 26 | JDK 27 |
|
||||
|---|---|---|---|
|
||||
| 1.18.34 | fails: `ExceptionInInitializerError` | fails | fails |
|
||||
| 1.18.40 | compiles | compiles | fails |
|
||||
| 1.18.46 | compiles | compiles | fails |
|
||||
| 1.18.48 | compiles | compiles | compiles |
|
||||
|
||||
The probe uses one annotation, so "compiles" is a lower bound: the [Lombok changelog](https://projectlombok.org/changelog) is the support statement (JDK 25 in 1.18.40, JDK 26 in 1.18.46, JDK 27 in 1.18.48).
|
||||
1.18.40 compiling on 26 does not contradict it.
|
||||
|
||||
Separate trap, same file: since JDK 23 `javac` no longer runs annotation processors it merely finds on the class path. JDK 21 compiles the probe with a `Note: Annotation processing is enabled...`; JDK 23, 24 and 25 give `cannot find symbol` for `getName()`.
|
||||
Maven and Gradle projects that declare the processor with `annotationProcessorPaths` / `annotationProcessor` are unaffected; hand-run `javac` lines and IDE setups that relied on discovery are not.
|
||||
|
||||
## 15.4 Mockito and ByteBuddy
|
||||
|
||||
[`lanes/src/MockitoProbe.java`](../lanes/src/MockitoProbe.java) mocks an interface and stubs one call. [97](output/97-mockito-bytebuddy.txt), each Mockito with the ByteBuddy it declares:
|
||||
|
||||
| Mockito | ByteBuddy | JDK 21 | JDK 25 | JDK 27 |
|
||||
|---|---|---|---|---|
|
||||
| 5.12.0 | 1.14.15 | works | fails | fails |
|
||||
| 5.17.0 | 1.15.11 | works | fails | fails |
|
||||
| 5.18.0 | 1.17.5 | works | works | works |
|
||||
| 5.23.0 | 1.17.7 | works | works | works |
|
||||
|
||||
The failure is `Mockito cannot mock this class` (ByteBuddy cannot instrument class files newer than it knows). 5.18.0 was the first version that worked; 5.14.2, 5.16.1 and 5.17.0 failed in a side run (not committed).
|
||||
Even on the working versions the JVM prints `WARNING: A Java agent has been loaded dynamically` on 21, 25 and 27, and Mockito 5.23.0 adds a note that self-attaching will stop working: the fix is to add Mockito as an agent, as its documentation describes.
|
||||
|
||||
## 15.5 `jdeps --jdk-internals`
|
||||
|
||||
[96](output/96-jdeps-internals.txt) is `jdeps --jdk-internals` on the class from [`UnsafeWarning.java`](../lanes/src/UnsafeWarning.java): it names `sun.misc.Unsafe` before the JVM prints its run-time warning ([86](output/86-unsafe-and-jni.txt)).
|
||||
|
||||
Prev: [14. The 21 to 25 lane](14-lanes-21-to-25.md) · [Back to the README](../README.md)
|
||||
@@ -0,0 +1,43 @@
|
||||
# JEP 523: which collector does the JVM pick when you do not choose one?
|
||||
# Same class files, same vendor (Amazon Corretto), same 2 GB memory limit. Only the JDK version and the CPU limit change.
|
||||
|
||||
=== amazoncorretto:26 --cpus=1 --memory=2g
|
||||
$ docker run --rm --cpus=1 --memory=2g amazoncorretto:26 java -cp /app GcReport
|
||||
java.version = 26.0.2.1
|
||||
availableCpus = 1
|
||||
maxHeapMB = 511
|
||||
collector beans = Copy, MarkSweepCompact
|
||||
UseG1GC = false (origin DEFAULT)
|
||||
UseSerialGC = true (origin ERGONOMIC)
|
||||
UseParallelGC = false (origin DEFAULT)
|
||||
|
||||
=== amazoncorretto:27 --cpus=1 --memory=2g
|
||||
$ docker run --rm --cpus=1 --memory=2g amazoncorretto:27 java -cp /app GcReport
|
||||
java.version = 27
|
||||
availableCpus = 1
|
||||
maxHeapMB = 512
|
||||
collector beans = G1 Young Generation, G1 Concurrent GC, G1 Old Generation
|
||||
UseG1GC = true (origin ERGONOMIC)
|
||||
UseSerialGC = false (origin DEFAULT)
|
||||
UseParallelGC = false (origin DEFAULT)
|
||||
|
||||
=== amazoncorretto:26 --cpus=2 --memory=2g
|
||||
$ docker run --rm --cpus=2 --memory=2g amazoncorretto:26 java -cp /app GcReport
|
||||
java.version = 26.0.2.1
|
||||
availableCpus = 2
|
||||
maxHeapMB = 512
|
||||
collector beans = G1 Young Generation, G1 Concurrent GC, G1 Old Generation
|
||||
UseG1GC = true (origin ERGONOMIC)
|
||||
UseSerialGC = false (origin DEFAULT)
|
||||
UseParallelGC = false (origin DEFAULT)
|
||||
|
||||
=== amazoncorretto:27 --cpus=2 --memory=2g
|
||||
$ docker run --rm --cpus=2 --memory=2g amazoncorretto:27 java -cp /app GcReport
|
||||
java.version = 27
|
||||
availableCpus = 2
|
||||
maxHeapMB = 512
|
||||
collector beans = G1 Young Generation, G1 Concurrent GC, G1 Old Generation
|
||||
UseG1GC = true (origin ERGONOMIC)
|
||||
UseSerialGC = false (origin DEFAULT)
|
||||
UseParallelGC = false (origin DEFAULT)
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
# The other half of the old rule: memory. The old heuristic wanted at least 2 CPUs AND about 1792 MB.
|
||||
# With 2 CPUs the CPU half of the rule is satisfied, so only the memory limit differs between these runs.
|
||||
|
||||
=== amazoncorretto:26 --cpus=2 --memory=1g
|
||||
$ docker run --rm --cpus=2 --memory=1g amazoncorretto:26 java -cp /app GcReport
|
||||
java.version = 26.0.2.1
|
||||
availableCpus = 2
|
||||
maxHeapMB = 255
|
||||
collector beans = Copy, MarkSweepCompact
|
||||
UseG1GC = false (origin DEFAULT)
|
||||
UseSerialGC = true (origin ERGONOMIC)
|
||||
UseParallelGC = false (origin DEFAULT)
|
||||
|
||||
=== amazoncorretto:27 --cpus=2 --memory=1g
|
||||
$ docker run --rm --cpus=2 --memory=1g amazoncorretto:27 java -cp /app GcReport
|
||||
java.version = 27
|
||||
availableCpus = 2
|
||||
maxHeapMB = 256
|
||||
collector beans = G1 Young Generation, G1 Concurrent GC, G1 Old Generation
|
||||
UseG1GC = true (origin ERGONOMIC)
|
||||
UseSerialGC = false (origin DEFAULT)
|
||||
UseParallelGC = false (origin DEFAULT)
|
||||
|
||||
=== amazoncorretto:26 --cpus=2 --memory=2g
|
||||
$ docker run --rm --cpus=2 --memory=2g amazoncorretto:26 java -cp /app GcReport
|
||||
java.version = 26.0.2.1
|
||||
availableCpus = 2
|
||||
maxHeapMB = 512
|
||||
collector beans = G1 Young Generation, G1 Concurrent GC, G1 Old Generation
|
||||
UseG1GC = true (origin ERGONOMIC)
|
||||
UseSerialGC = false (origin DEFAULT)
|
||||
UseParallelGC = false (origin DEFAULT)
|
||||
|
||||
=== amazoncorretto:27 --cpus=2 --memory=2g
|
||||
$ docker run --rm --cpus=2 --memory=2g amazoncorretto:27 java -cp /app GcReport
|
||||
java.version = 27
|
||||
availableCpus = 2
|
||||
maxHeapMB = 512
|
||||
collector beans = G1 Young Generation, G1 Concurrent GC, G1 Old Generation
|
||||
UseG1GC = true (origin ERGONOMIC)
|
||||
UseSerialGC = false (origin DEFAULT)
|
||||
UseParallelGC = false (origin DEFAULT)
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# The opt-out still works on 27: an explicit choice always wins over the JVM's.
|
||||
|
||||
=== amazoncorretto:27 --cpus=1 --memory=2g -XX:+UseSerialGC
|
||||
$ docker run --rm --cpus=1 --memory=2g amazoncorretto:27 java -XX:+UseSerialGC -cp /app GcReport
|
||||
java.version = 27
|
||||
availableCpus = 1
|
||||
maxHeapMB = 511
|
||||
collector beans = Copy, MarkSweepCompact
|
||||
UseG1GC = false (origin DEFAULT)
|
||||
UseSerialGC = true (origin VM_CREATION)
|
||||
UseParallelGC = false (origin DEFAULT)
|
||||
@@ -0,0 +1,51 @@
|
||||
# Allocation workload, 1 CPU / 2 GB container, 4000 batches x 50,000 objects, 3 runs per configuration (indicative, not a benchmark)
|
||||
# 'default' means nobody passed a collector flag.
|
||||
|
||||
=== amazoncorretto:26 default run 1
|
||||
wall time = 5980 ms
|
||||
gc count / time = 1275 / 1831 ms
|
||||
slowest batch = 115 ms
|
||||
peak RSS = 557 MB
|
||||
=== amazoncorretto:26 default run 2
|
||||
wall time = 6145 ms
|
||||
gc count / time = 1275 / 1872 ms
|
||||
slowest batch = 142 ms
|
||||
peak RSS = 557 MB
|
||||
=== amazoncorretto:26 default run 3
|
||||
wall time = 6402 ms
|
||||
gc count / time = 1275 / 1861 ms
|
||||
slowest batch = 129 ms
|
||||
peak RSS = 557 MB
|
||||
|
||||
=== amazoncorretto:27 default run 1
|
||||
wall time = 8196 ms
|
||||
gc count / time = 140 / 1955 ms
|
||||
slowest batch = 39 ms
|
||||
peak RSS = 547 MB
|
||||
=== amazoncorretto:27 default run 2
|
||||
wall time = 8214 ms
|
||||
gc count / time = 140 / 1970 ms
|
||||
slowest batch = 41 ms
|
||||
peak RSS = 547 MB
|
||||
=== amazoncorretto:27 default run 3
|
||||
wall time = 8432 ms
|
||||
gc count / time = 140 / 2004 ms
|
||||
slowest batch = 35 ms
|
||||
peak RSS = 546 MB
|
||||
|
||||
=== amazoncorretto:27 -XX:+UseSerialGC run 1
|
||||
wall time = 5306 ms
|
||||
gc count / time = 1264 / 1669 ms
|
||||
slowest batch = 125 ms
|
||||
peak RSS = 557 MB
|
||||
=== amazoncorretto:27 -XX:+UseSerialGC run 2
|
||||
wall time = 4972 ms
|
||||
gc count / time = 1264 / 1599 ms
|
||||
slowest batch = 119 ms
|
||||
peak RSS = 557 MB
|
||||
=== amazoncorretto:27 -XX:+UseSerialGC run 3
|
||||
wall time = 5698 ms
|
||||
gc count / time = 1264 / 1713 ms
|
||||
slowest batch = 128 ms
|
||||
peak RSS = 557 MB
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
# Allocation workload, 1 CPU / 2 GB container, 400 batches x 50,000 objects, 3 runs per configuration (indicative, not a benchmark)
|
||||
# 'default' means nobody passed a collector flag.
|
||||
|
||||
=== amazoncorretto:26 default run 1
|
||||
wall time = 531 ms
|
||||
gc count / time = 683 / 160 ms
|
||||
slowest batch = 25 ms
|
||||
peak RSS = 102 MB
|
||||
=== amazoncorretto:26 default run 2
|
||||
wall time = 536 ms
|
||||
gc count / time = 683 / 165 ms
|
||||
slowest batch = 22 ms
|
||||
peak RSS = 103 MB
|
||||
=== amazoncorretto:26 default run 3
|
||||
wall time = 564 ms
|
||||
gc count / time = 683 / 161 ms
|
||||
slowest batch = 36 ms
|
||||
peak RSS = 102 MB
|
||||
|
||||
=== amazoncorretto:27 default run 1
|
||||
wall time = 1052 ms
|
||||
gc count / time = 26 / 204 ms
|
||||
slowest batch = 26 ms
|
||||
peak RSS = 492 MB
|
||||
=== amazoncorretto:27 default run 2
|
||||
wall time = 974 ms
|
||||
gc count / time = 26 / 192 ms
|
||||
slowest batch = 25 ms
|
||||
peak RSS = 492 MB
|
||||
=== amazoncorretto:27 default run 3
|
||||
wall time = 1041 ms
|
||||
gc count / time = 26 / 234 ms
|
||||
slowest batch = 36 ms
|
||||
peak RSS = 492 MB
|
||||
|
||||
=== amazoncorretto:27 -XX:+UseSerialGC run 1
|
||||
wall time = 528 ms
|
||||
gc count / time = 668 / 147 ms
|
||||
slowest batch = 23 ms
|
||||
peak RSS = 98 MB
|
||||
=== amazoncorretto:27 -XX:+UseSerialGC run 2
|
||||
wall time = 522 ms
|
||||
gc count / time = 668 / 157 ms
|
||||
slowest batch = 27 ms
|
||||
peak RSS = 98 MB
|
||||
=== amazoncorretto:27 -XX:+UseSerialGC run 3
|
||||
wall time = 588 ms
|
||||
gc count / time = 668 / 157 ms
|
||||
slowest batch = 48 ms
|
||||
peak RSS = 97 MB
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# JDK 27, G1 (the default), 1 CPU / 2 GB container, 400 batches, 2 runs per configuration
|
||||
|
||||
=== flags that differ between 26 and 27 (from -XX:+PrintFlagsFinal)
|
||||
--- amazoncorretto:26
|
||||
uint ConcGCThreads = 0 {product} {default}
|
||||
uintx MaxHeapFreeRatio = 70 {manageable} {default}
|
||||
size_t MaxHeapSize = 536870912 {product} {ergonomic}
|
||||
uintx MinHeapFreeRatio = 40 {manageable} {default}
|
||||
uint ParallelGCThreads = 0 {product} {default}
|
||||
bool UseCompactObjectHeaders = false {product lp64_product} {default}
|
||||
bool UseCompressedClassPointers = true {product} {default}
|
||||
--- amazoncorretto:27
|
||||
uint ConcGCThreads = 1 {product} {ergonomic}
|
||||
uint G1IHOP = 45 {product} {default}
|
||||
uintx MaxHeapFreeRatio = 100 {manageable} {default}
|
||||
size_t MaxHeapSize = 536870912 {product} {ergonomic}
|
||||
uintx MinHeapFreeRatio = 0 {manageable} {default}
|
||||
uint ParallelGCThreads = 1 {product} {default}
|
||||
bool UseCompactObjectHeaders = true {product lp64_product} {default}
|
||||
|
||||
=== amazoncorretto:27 flags: [none]
|
||||
wall time = 1064 ms
|
||||
gc count / time = 26 / 208 ms
|
||||
peak RSS = 492 MB
|
||||
wall time = 1078 ms
|
||||
gc count / time = 26 / 202 ms
|
||||
peak RSS = 493 MB
|
||||
=== amazoncorretto:27 flags: [-XX:MinHeapFreeRatio=40 -XX:MaxHeapFreeRatio=70]
|
||||
wall time = 1115 ms
|
||||
gc count / time = 26 / 268 ms
|
||||
peak RSS = 492 MB
|
||||
wall time = 982 ms
|
||||
gc count / time = 26 / 199 ms
|
||||
peak RSS = 492 MB
|
||||
=== amazoncorretto:27 flags: [-Xmx256m]
|
||||
wall time = 976 ms
|
||||
gc count / time = 37 / 240 ms
|
||||
peak RSS = 294 MB
|
||||
wall time = 957 ms
|
||||
gc count / time = 37 / 261 ms
|
||||
peak RSS = 294 MB
|
||||
@@ -0,0 +1,82 @@
|
||||
java.version = 26.0.2.1
|
||||
# VM mode: 64 bits
|
||||
# Compressed references (oops): 0-bit shift
|
||||
# Compressed class pointers: 0-bit shift and 0x3E000000 base
|
||||
# Object alignment: 8 bytes
|
||||
# ref, bool, byte, char, shrt, int, flt, lng, dbl
|
||||
# Field sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
|
||||
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
|
||||
# Array base offsets: 16, 16, 16, 16, 16, 16, 16, 16, 16
|
||||
|
||||
|
||||
=== java.lang.Object
|
||||
java.lang.Object object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) N/A
|
||||
8 4 (object header: class) N/A
|
||||
12 4 (object alignment gap)
|
||||
Instance size: 16 bytes
|
||||
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
|
||||
|
||||
|
||||
=== Point { int x; int y; }
|
||||
HeaderDemo$Point object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) N/A
|
||||
8 4 (object header: class) N/A
|
||||
12 4 int Point.x N/A
|
||||
16 4 int Point.y N/A
|
||||
20 4 (object alignment gap)
|
||||
Instance size: 24 bytes
|
||||
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
|
||||
|
||||
|
||||
=== Order { long id; int quantity; boolean paid; String customer; }
|
||||
HeaderDemo$Order object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) N/A
|
||||
8 4 (object header: class) N/A
|
||||
12 4 int Order.quantity N/A
|
||||
16 8 long Order.id N/A
|
||||
24 1 boolean Order.paid N/A
|
||||
25 3 (alignment/padding gap)
|
||||
28 4 java.lang.String Order.customer N/A
|
||||
Instance size: 32 bytes
|
||||
Space losses: 3 bytes internal + 0 bytes external = 3 bytes total
|
||||
|
||||
|
||||
=== java.lang.Long and java.lang.Integer (boxed values)
|
||||
java.lang.Long object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
|
||||
8 4 (object header: class) 0x001a15d0
|
||||
12 4 (alignment/padding gap)
|
||||
16 8 long Long.value 123456789
|
||||
Instance size: 24 bytes
|
||||
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total
|
||||
|
||||
java.lang.Integer object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
|
||||
8 4 (object header: class) 0x0019f570
|
||||
12 4 int Integer.value 123456
|
||||
Instance size: 16 bytes
|
||||
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
|
||||
|
||||
|
||||
=== int[3]
|
||||
[I object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
|
||||
8 4 (object header: class) 0x00174360
|
||||
12 4 (array length) 3
|
||||
16 12 int [I.<elements> N/A
|
||||
28 4 (object alignment gap)
|
||||
Instance size: 32 bytes
|
||||
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
|
||||
|
||||
|
||||
=== What it adds up to: one million objects
|
||||
1,000,000 boxed Integer values in an ArrayList : 20,861,992 bytes
|
||||
1,000,000 boxed Long values in an ArrayList : 28,861,992 bytes
|
||||
1,000,000 Point objects in an ArrayList : 28,861,992 bytes
|
||||
@@ -0,0 +1,79 @@
|
||||
java.version = 27
|
||||
# WARNING: Unable to attach Serviceability Agent. sun.jvm.hotspot.runtime.VM.isCompressedKlassPointersEnabled()
|
||||
# VM mode: 64 bits
|
||||
# Lilliput VM detected (experimental)
|
||||
# Compressed references (oops): 3-bit shift
|
||||
# Compressed class pointers: 3-bit shift
|
||||
# WARNING | Compressed references base/shifts are guessed by the experiment!
|
||||
# WARNING | Therefore, computed addresses are just guesses, and ARE NOT RELIABLE.
|
||||
# WARNING | Make sure to attach Serviceability Agent to get the reliable addresses.
|
||||
# Object alignment: 8 bytes
|
||||
# ref, bool, byte, char, shrt, int, flt, lng, dbl
|
||||
# Field sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
|
||||
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
|
||||
# Array base offsets: 12, 12, 12, 12, 12, 12, 12, 16, 16
|
||||
|
||||
|
||||
=== java.lang.Object
|
||||
java.lang.Object object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) N/A
|
||||
Instance size: 8 bytes
|
||||
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
|
||||
|
||||
|
||||
=== Point { int x; int y; }
|
||||
HeaderDemo$Point object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) N/A
|
||||
8 4 int Point.x N/A
|
||||
12 4 int Point.y N/A
|
||||
Instance size: 16 bytes
|
||||
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
|
||||
|
||||
|
||||
=== Order { long id; int quantity; boolean paid; String customer; }
|
||||
HeaderDemo$Order object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) N/A
|
||||
8 8 long Order.id N/A
|
||||
16 4 int Order.quantity N/A
|
||||
20 1 boolean Order.paid N/A
|
||||
21 3 (alignment/padding gap)
|
||||
24 4 java.lang.String Order.customer N/A
|
||||
28 4 (object alignment gap)
|
||||
Instance size: 32 bytes
|
||||
Space losses: 3 bytes internal + 4 bytes external = 7 bytes total
|
||||
|
||||
|
||||
=== java.lang.Long and java.lang.Integer (boxed values)
|
||||
java.lang.Long object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x001aa80000000001 (Lilliput)
|
||||
8 8 long Long.value 123456789
|
||||
Instance size: 16 bytes
|
||||
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
|
||||
|
||||
java.lang.Integer object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x001a840000000001 (Lilliput)
|
||||
8 4 int Integer.value 123456
|
||||
12 4 (object alignment gap)
|
||||
Instance size: 16 bytes
|
||||
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
|
||||
|
||||
|
||||
=== int[3]
|
||||
[I object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0017840000000001 (Lilliput)
|
||||
8 4 (array length) 3
|
||||
12 12 int [I.<elements> N/A
|
||||
Instance size: 24 bytes
|
||||
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
|
||||
|
||||
|
||||
=== What it adds up to: one million objects
|
||||
1,000,000 boxed Integer values in an ArrayList : 20,861,984 bytes
|
||||
1,000,000 boxed Long values in an ArrayList : 20,861,984 bytes
|
||||
1,000,000 Point objects in an ArrayList : 20,861,984 bytes
|
||||
@@ -0,0 +1,86 @@
|
||||
java.version = 27
|
||||
# WARNING: Unable to attach Serviceability Agent. sun.jvm.hotspot.runtime.VM.isCompressedKlassPointersEnabled()
|
||||
# VM mode: 64 bits
|
||||
# Compressed references (oops): 3-bit shift
|
||||
# Compressed class pointers: 3-bit shift
|
||||
# WARNING | Compressed references base/shifts are guessed by the experiment!
|
||||
# WARNING | Therefore, computed addresses are just guesses, and ARE NOT RELIABLE.
|
||||
# WARNING | Make sure to attach Serviceability Agent to get the reliable addresses.
|
||||
# Object alignment: 8 bytes
|
||||
# ref, bool, byte, char, shrt, int, flt, lng, dbl
|
||||
# Field sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
|
||||
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
|
||||
# Array base offsets: 16, 16, 16, 16, 16, 16, 16, 16, 16
|
||||
|
||||
|
||||
=== java.lang.Object
|
||||
java.lang.Object object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) N/A
|
||||
8 4 (object header: class) N/A
|
||||
12 4 (object alignment gap)
|
||||
Instance size: 16 bytes
|
||||
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
|
||||
|
||||
|
||||
=== Point { int x; int y; }
|
||||
HeaderDemo$Point object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) N/A
|
||||
8 4 (object header: class) N/A
|
||||
12 4 int Point.x N/A
|
||||
16 4 int Point.y N/A
|
||||
20 4 (object alignment gap)
|
||||
Instance size: 24 bytes
|
||||
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
|
||||
|
||||
|
||||
=== Order { long id; int quantity; boolean paid; String customer; }
|
||||
HeaderDemo$Order object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) N/A
|
||||
8 4 (object header: class) N/A
|
||||
12 4 int Order.quantity N/A
|
||||
16 8 long Order.id N/A
|
||||
24 1 boolean Order.paid N/A
|
||||
25 3 (alignment/padding gap)
|
||||
28 4 java.lang.String Order.customer N/A
|
||||
Instance size: 32 bytes
|
||||
Space losses: 3 bytes internal + 0 bytes external = 3 bytes total
|
||||
|
||||
|
||||
=== java.lang.Long and java.lang.Integer (boxed values)
|
||||
java.lang.Long object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0000000000000009 (non-biasable; age: 1)
|
||||
8 4 (object header: class) 0x001aa208
|
||||
12 4 (alignment/padding gap)
|
||||
16 8 long Long.value 123456789
|
||||
Instance size: 24 bytes
|
||||
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total
|
||||
|
||||
java.lang.Integer object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
|
||||
8 4 (object header: class) 0x001a7db8
|
||||
12 4 int Integer.value 123456
|
||||
Instance size: 16 bytes
|
||||
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
|
||||
|
||||
|
||||
=== int[3]
|
||||
[I object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
|
||||
8 4 (object header: class) 0x00176c00
|
||||
12 4 (array length) 3
|
||||
16 12 int [I.<elements> N/A
|
||||
28 4 (object alignment gap)
|
||||
Instance size: 32 bytes
|
||||
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
|
||||
|
||||
|
||||
=== What it adds up to: one million objects
|
||||
1,000,000 boxed Integer values in an ArrayList : 20,861,992 bytes
|
||||
1,000,000 boxed Long values in an ArrayList : 28,861,992 bytes
|
||||
1,000,000 Point objects in an ArrayList : 28,861,992 bytes
|
||||
@@ -0,0 +1,11 @@
|
||||
# WARNING: Unable to attach Serviceability Agent. sun.jvm.hotspot.runtime.VM.isCompressedKlassPointersEnabled()
|
||||
Exception in thread "main" java.lang.RuntimeException: Cannot get the field offset, try with -Djol.magicFieldOffset=true
|
||||
at org.openjdk.jol.vm.HotspotUnsafe.fieldOffset(HotspotUnsafe.java:533)
|
||||
at org.openjdk.jol.layouters.CurrentLayouter.layout(CurrentLayouter.java:70)
|
||||
at org.openjdk.jol.info.ClassLayout.parseClass(ClassLayout.java:72)
|
||||
at org.openjdk.jol.info.ClassLayout.parseClass(ClassLayout.java:56)
|
||||
at RecordProbe.main(RecordProbe.java:12)
|
||||
Caused by: java.lang.UnsupportedOperationException: can't get field offset on a record class: private final int RecordProbe$Coordinates.lat
|
||||
at jdk.unsupported/sun.misc.Unsafe.objectFieldOffset(Unsafe.java:903)
|
||||
at org.openjdk.jol.vm.HotspotUnsafe.fieldOffset(HotspotUnsafe.java:526)
|
||||
... 4 more
|
||||
@@ -0,0 +1,9 @@
|
||||
# WARNING: Unable to attach Serviceability Agent. sun.jvm.hotspot.runtime.VM.isCompressedKlassPointersEnabled()
|
||||
RecordProbe$Coordinates object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) N/A
|
||||
8 4 int Coordinates.lat N/A
|
||||
12 4 int Coordinates.lon N/A
|
||||
Instance size: 16 bytes
|
||||
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# Instance sizes in bytes, extracted from 10-, 11- and 12- transcripts
|
||||
--- 10-headers-jdk26
|
||||
=== java.lang.Object -> Instance size: 16 bytes
|
||||
=== Point { int x; int y; } -> Instance size: 24 bytes
|
||||
=== Order { long id; int quantity; boolean paid; String customer; } -> Instance size: 32 bytes
|
||||
=== java.lang.Long and java.lang.Integer (boxed values) -> Instance size: 24 bytes
|
||||
=== java.lang.Long and java.lang.Integer (boxed values) -> Instance size: 16 bytes
|
||||
=== int[3] -> Instance size: 32 bytes
|
||||
1,000,000 boxed Integer values in an ArrayList : 20,861,992 bytes
|
||||
1,000,000 boxed Long values in an ArrayList : 28,861,992 bytes
|
||||
1,000,000 Point objects in an ArrayList : 28,861,992 bytes
|
||||
--- 11-headers-jdk27
|
||||
=== java.lang.Object -> Instance size: 8 bytes
|
||||
=== Point { int x; int y; } -> Instance size: 16 bytes
|
||||
=== Order { long id; int quantity; boolean paid; String customer; } -> Instance size: 32 bytes
|
||||
=== java.lang.Long and java.lang.Integer (boxed values) -> Instance size: 16 bytes
|
||||
=== java.lang.Long and java.lang.Integer (boxed values) -> Instance size: 16 bytes
|
||||
=== int[3] -> Instance size: 24 bytes
|
||||
1,000,000 boxed Integer values in an ArrayList : 20,861,984 bytes
|
||||
1,000,000 boxed Long values in an ArrayList : 20,861,984 bytes
|
||||
1,000,000 Point objects in an ArrayList : 20,861,984 bytes
|
||||
--- 12-headers-jdk27-opt-out
|
||||
=== java.lang.Object -> Instance size: 16 bytes
|
||||
=== Point { int x; int y; } -> Instance size: 24 bytes
|
||||
=== Order { long id; int quantity; boolean paid; String customer; } -> Instance size: 32 bytes
|
||||
=== java.lang.Long and java.lang.Integer (boxed values) -> Instance size: 24 bytes
|
||||
=== java.lang.Long and java.lang.Integer (boxed values) -> Instance size: 16 bytes
|
||||
=== int[3] -> Instance size: 32 bytes
|
||||
1,000,000 boxed Integer values in an ArrayList : 20,861,992 bytes
|
||||
1,000,000 boxed Long values in an ArrayList : 28,861,992 bytes
|
||||
1,000,000 Point objects in an ArrayList : 28,861,992 bytes
|
||||
@@ -0,0 +1,6 @@
|
||||
$ javac --enable-preview --release 27 Dominated.java (JDK 27)
|
||||
Dominated.java:9: error: this case label is dominated by a preceding case label
|
||||
case int primitive -> "an int"; // dominated: every Integer is already caught above
|
||||
^
|
||||
1 error
|
||||
exit=1
|
||||
@@ -0,0 +1,16 @@
|
||||
$ javac --enable-preview --release 26 Lazy26.java (JDK 26)
|
||||
exit=0
|
||||
|
||||
$ javac --enable-preview --release 27 Lazy26.java (JDK 27)
|
||||
Lazy26.java:12: error: cannot find symbol
|
||||
if (!GREETING.isInitialized()) {
|
||||
^
|
||||
symbol: method isInitialized()
|
||||
location: variable GREETING of type LazyConstant<String>
|
||||
Lazy26.java:13: error: cannot find symbol
|
||||
System.out.println("not yet: " + GREETING.orElse("<unset>"));
|
||||
^
|
||||
symbol: method orElse(String)
|
||||
location: variable GREETING of type LazyConstant<String>
|
||||
2 errors
|
||||
exit=1
|
||||
@@ -0,0 +1,19 @@
|
||||
$ javac --enable-preview --release 26 Pem26Style.java (JDK 26)
|
||||
exit=0
|
||||
|
||||
$ javac --enable-preview --release 27 Pem26Style.java (JDK 27)
|
||||
Pem26Style.java:1: error: cannot find symbol
|
||||
import java.security.DEREncodable;
|
||||
^
|
||||
symbol: class DEREncodable
|
||||
location: package java.security
|
||||
Pem26Style.java:20: error: cannot find symbol
|
||||
PEMDecoder viaProvider = PEMDecoder.of().withFactory(provider); // 2
|
||||
^
|
||||
symbol: method withFactory(Provider)
|
||||
location: class PEMDecoder
|
||||
Pem26Style.java:22: error: incompatible types: byte[] cannot be converted to String
|
||||
String base64Text = pem.content(); // 3
|
||||
^
|
||||
3 errors
|
||||
exit=1
|
||||
@@ -0,0 +1,19 @@
|
||||
$ javac --enable-preview --release 26 StructuredScope26.java (JDK 26)
|
||||
exit=0
|
||||
|
||||
$ javac --enable-preview --release 27 StructuredScope26.java (JDK 27)
|
||||
StructuredScope26.java:12: error: wrong number of type arguments; required 3
|
||||
try (StructuredTaskScope<String, List<String>> scope =
|
||||
^
|
||||
StructuredScope26.java:17: error: cannot find symbol
|
||||
} catch (StructuredTaskScope.FailedException e) {
|
||||
^
|
||||
symbol: class FailedException
|
||||
location: interface StructuredTaskScope
|
||||
StructuredScope26.java:19: error: cannot find symbol
|
||||
} catch (StructuredTaskScope.TimeoutException e) {
|
||||
^
|
||||
symbol: class TimeoutException
|
||||
location: interface StructuredTaskScope
|
||||
3 errors
|
||||
exit=1
|
||||
@@ -0,0 +1,14 @@
|
||||
$ java --enable-preview StructuredDemo (JDK 27)
|
||||
--- allSuccessfulOrThrow(): results as a List, failures as ExecutionException
|
||||
results = [price=42, stock=7]
|
||||
CHECK ok : join() returns the subtask results in fork order
|
||||
caught java.util.concurrent.ExecutionException with cause java.lang.IllegalStateException: inventory service is down
|
||||
CHECK ok : a failing subtask surfaces as ExecutionException(cause)
|
||||
--- allSuccessfulOrThrow(Function): join() throws the exception type you choose
|
||||
caught OrderFailed: order failed: inventory service is down
|
||||
CHECK ok : the mapped exception wraps the original failure
|
||||
--- withTimeout(...): what happens when the scope runs out of time
|
||||
caught java.util.concurrent.ExecutionException
|
||||
cause: java.util.concurrent.StructuredTaskScope$CancelledByTimeoutException
|
||||
CHECK ok : a timeout is reported as CancelledByTimeoutException
|
||||
exit=0
|
||||
@@ -0,0 +1,22 @@
|
||||
$ java --enable-preview LazyDemo (JDK 27)
|
||||
--- a lazy constant computes once, on first use
|
||||
toString before first get(): jdk.internal.lang.LazyConstantImpl@...[computing function=LazyDemo$$Lambda/0x...@...]
|
||||
(loading settings on main)
|
||||
toString after first get(): jdk.internal.lang.LazyConstantImpl@...[Settings[region=ap-south-1, poolSize=16]]
|
||||
CHECK ok : get() returns the same instance every time
|
||||
CHECK ok : the supplier ran exactly once
|
||||
--- and once even when 64 threads race for it
|
||||
CHECK ok : 64 racing threads triggered exactly one initialisation
|
||||
--- List.ofLazy: each element is computed on first access
|
||||
computed so far: 0
|
||||
squares.get(3) = square(3)=9
|
||||
squares.get(3) = square(3)=9 (second read)
|
||||
CHECK ok : only element 3 was ever computed
|
||||
--- Map.ofLazy: the keys are fixed, the values are computed on first access
|
||||
lengths.get("gamma") = 5
|
||||
CHECK ok : only the requested key's value was computed
|
||||
--- Set.ofLazy (new in 27): membership is decided by a predicate, on demand
|
||||
primes.contains(7) = true, primes.contains(6) = false
|
||||
CHECK ok : the lazy set answers membership using the predicate
|
||||
primes = [2, 3, 5, 7]
|
||||
exit=0
|
||||
@@ -0,0 +1,28 @@
|
||||
$ java --enable-preview PrimitivePatterns (JDK 27)
|
||||
--- instanceof <primitive>: an exact-conversion test, not a cast
|
||||
100 instanceof byte = true
|
||||
300 instanceof byte = false (a byte holds -128..127)
|
||||
CHECK ok : 100 converts to byte exactly, 300 does not
|
||||
binding: byte narrow = 100
|
||||
16_777_216 instanceof float = true
|
||||
16_777_217 instanceof float = false (float has a 24-bit significand)
|
||||
CHECK ok : int to float is exact up to 2^24 and lossy after
|
||||
--- switch on a long, with pattern labels and a guard
|
||||
classify(0) = zero
|
||||
classify(1) = one
|
||||
classify(-7) = negative (-7)
|
||||
classify(9000000000) = positive (9000000000)
|
||||
CHECK ok : long switch dispatches on constants, then patterns
|
||||
--- switch on an Object: an Integer matches 'case int'
|
||||
describe(Integer 7) = an int 7
|
||||
describe(Integer 5000) = a large int 5000
|
||||
describe(Long 7) = a long 7
|
||||
describe(Double 2.5) = a double 2.5
|
||||
describe(String hello) = a String of length 5
|
||||
describe(Character x) = something else: x
|
||||
CHECK ok : an Integer 5000 matches case int with a guard
|
||||
--- record pattern with a narrowing primitive component
|
||||
Reading[celsius=36] -> fits in a byte: 36
|
||||
Reading[celsius=4000] -> needs a full int: 4000
|
||||
CHECK ok : Reading(byte c) matches 36 but not 4000
|
||||
exit=0
|
||||
@@ -0,0 +1,29 @@
|
||||
$ java --enable-preview PemDemo (JDK 27)
|
||||
--- public key, encoded
|
||||
-----BEGIN PUBLIC KEY----- ... -----END PUBLIC KEY-----
|
||||
--- private key, encoded
|
||||
-----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY-----
|
||||
CHECK ok : a PublicKey encodes as BEGIN PUBLIC KEY
|
||||
CHECK ok : a PrivateKey encodes as BEGIN PRIVATE KEY (PKCS#8)
|
||||
CHECK ok : the decoded public key equals the original
|
||||
CHECK ok : the decoded private key equals the original
|
||||
--- decode(String) returns whatever the header says it is
|
||||
-----BEGIN PUBLIC KEY----- -> PublicKey (EC)
|
||||
-----BEGIN PRIVATE KEY----- -> PrivateKey (EC)
|
||||
--- encrypted private key
|
||||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
CHECK ok : withEncryption produces ENCRYPTED PRIVATE KEY
|
||||
decoded with no password: javax.crypto.EncryptedPrivateKeyInfo
|
||||
CHECK ok : without a password you get the still-encrypted structure back
|
||||
CHECK ok : with the password you get the original private key
|
||||
--- PEM(type, byte[]) does NOT Base64-encode: the bytes go in as they are
|
||||
-----BEGIN ANKURM DEMO-----
|
||||
hello, pem
|
||||
-----END ANKURM DEMO-----
|
||||
CHECK ok : raw bytes appear verbatim between the header and footer
|
||||
--- give it the Base64 text and it round-trips
|
||||
-----BEGIN ANKURM DEMO-----
|
||||
aGVsbG8sIHBlbQ==
|
||||
-----END ANKURM DEMO-----
|
||||
CHECK ok : type, Base64 text (content()) and decoded payload (decode()) all survive
|
||||
exit=0
|
||||
@@ -0,0 +1,7 @@
|
||||
$ java --add-modules jdk.incubator.vector VectorDemo (JDK 27)
|
||||
java.version = 27
|
||||
preferred species = Species[float, 16, S_512_BIT] (16 float lanes, machine dependent)
|
||||
scalar dot = 749999.6
|
||||
vector dot = 749999.6
|
||||
CHECK ok : vector and scalar dot products agree to within 0.1%
|
||||
exit=0
|
||||
@@ -0,0 +1,21 @@
|
||||
# Who talks to whom: the key-exchange group each pairing actually negotiates (TLS 1.3, loopback)
|
||||
|
||||
=== client JDK 26 -> server JDK 26
|
||||
client offered : "named groups": [x25519, secp256r1, secp384r1, secp521r1, x448, ffdhe2048, ffdhe3072, ffdhe4096, ffdhe6144, ffdhe8192]
|
||||
server selected: x25519
|
||||
handshake complete: TLSv1.3 TLS_AES_256_GCM_SHA384
|
||||
|
||||
=== client JDK 27 -> server JDK 27
|
||||
client offered : "named groups": [X25519MLKEM768, x25519, secp256r1, secp384r1, secp521r1, x448, ffdhe2048, ffdhe3072, ffdhe4096]
|
||||
server selected: X25519MLKEM768
|
||||
handshake complete: TLSv1.3 TLS_AES_256_GCM_SHA384
|
||||
|
||||
=== client JDK 27 -> server JDK 26
|
||||
client offered : "named groups": [X25519MLKEM768, x25519, secp256r1, secp384r1, secp521r1, x448, ffdhe2048, ffdhe3072, ffdhe4096]
|
||||
server selected: x25519
|
||||
handshake complete: TLSv1.3 TLS_AES_256_GCM_SHA384
|
||||
|
||||
=== client JDK 26 -> server JDK 27
|
||||
client offered : "named groups": [x25519, secp256r1, secp384r1, secp521r1, x448, ffdhe2048, ffdhe3072, ffdhe4096, ffdhe6144, ffdhe8192]
|
||||
server selected: x25519
|
||||
handshake complete: TLSv1.3 TLS_AES_256_GCM_SHA384
|
||||
@@ -0,0 +1,19 @@
|
||||
# Size of the first TLS record (the ClientHello) each JDK sends
|
||||
|
||||
=== JDK 26
|
||||
java.version = 26.0.2.1
|
||||
record type = 0x16 (0x16 = handshake)
|
||||
ClientHello record = 417 bytes (+5 byte record header)
|
||||
fits one TCP segment = yes (1460-byte MSS on a 1500-byte MTU)
|
||||
|
||||
=== JDK 27
|
||||
java.version = 27
|
||||
record type = 0x16 (0x16 = handshake)
|
||||
ClientHello record = 1573 bytes (+5 byte record header)
|
||||
fits one TCP segment = NO (1460-byte MSS on a 1500-byte MTU)
|
||||
|
||||
=== JDK 27 with -Djdk.tls.namedGroups=x25519,secp256r1 (post-quantum group removed)
|
||||
java.version = 27
|
||||
record type = 0x16 (0x16 = handshake)
|
||||
ClientHello record = 408 bytes (+5 byte record header)
|
||||
fits one TCP segment = yes (1460-byte MSS on a 1500-byte MTU)
|
||||
@@ -0,0 +1,6 @@
|
||||
# Opting out on JDK 27: a client that does not offer the hybrid group
|
||||
|
||||
=== client JDK 27 with -Djdk.tls.namedGroups=x25519,secp256r1 -> server JDK 27
|
||||
client offered : "named groups": [x25519, secp256r1]
|
||||
server selected: x25519
|
||||
handshake complete: TLSv1.3 TLS_AES_256_GCM_SHA384
|
||||
@@ -0,0 +1,41 @@
|
||||
# The process under test: java -Dapi.token=abc123 -Dregion=ap-south-1 ... Idle --password=hunter2 --user=ankur
|
||||
# with DB_PASSWORD=hunter2 in the environment. Which of those values reach the recording?
|
||||
|
||||
=== jdk26-default
|
||||
jvmArguments = "-Dapi.token=abc123 -Dregion=ap-south-1 -XX:StartFlightRecording:filename=<file>"
|
||||
javaArguments = "Idle --password=hunter2 --user=ankur"
|
||||
key = "region" value = "ap-south-1"
|
||||
key = "api.token" value = "abc123"
|
||||
key = "DB_PASSWORD" value = "hunter2"
|
||||
|
||||
=== jdk27-default
|
||||
jvmArguments = "[REDACTED] -Dregion=ap-south-1 -XX:StartFlightRecording:filename=<file>"
|
||||
javaArguments = "Idle [REDACTED] --user=ankur"
|
||||
key = "region" value = "ap-south-1"
|
||||
key = "api.token" value = "[REDACTED]"
|
||||
key = "DB_PASSWORD" value = "[REDACTED]"
|
||||
|
||||
=== jdk27-own-list-replaces-defaults
|
||||
-XX:FlightRecorderOptions:redact-argument=--user*,redact-key=region
|
||||
jvmArguments = "-Dapi.token=abc123 -Dregion=[REDACTED] -XX:FlightRecorderOptions:redact-argument=[REDACTED],redact-key=region -XX:StartFlightRecording:filename=<file>"
|
||||
javaArguments = "Idle --password=hunter2 [REDACTED]"
|
||||
key = "region" value = "[REDACTED]"
|
||||
key = "api.token" value = "abc123"
|
||||
key = "DB_PASSWORD" value = "hunter2"
|
||||
|
||||
=== jdk27-plus-extends-defaults
|
||||
-XX:FlightRecorderOptions:redact-argument=+--user*,redact-key=+region
|
||||
jvmArguments = "[REDACTED] -Dregion=[REDACTED] -XX:FlightRecorderOptions:redact-argument=[REDACTED],redact-key=+region -XX:StartFlightRecording:filename=<file>"
|
||||
javaArguments = "Idle [REDACTED] [REDACTED]"
|
||||
key = "region" value = "[REDACTED]"
|
||||
key = "api.token" value = "[REDACTED]"
|
||||
key = "DB_PASSWORD" value = "[REDACTED]"
|
||||
|
||||
=== jdk27-none-disables-redaction
|
||||
-XX:FlightRecorderOptions:redact-argument=none,redact-key=none
|
||||
jvmArguments = "-Dapi.token=abc123 -Dregion=ap-south-1 -XX:FlightRecorderOptions:redact-argument=[REDACTED],redact-key=none -XX:StartFlightRecording:filename=<file>"
|
||||
javaArguments = "Idle --password=hunter2 --user=ankur"
|
||||
key = "region" value = "ap-south-1"
|
||||
key = "api.token" value = "abc123"
|
||||
key = "DB_PASSWORD" value = "hunter2"
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# jdk.incubator.vector: what changed between 26 and 27 (JEP 529 was the 11th incubation in 26, JEP 537 is the 12th in 27)
|
||||
|
||||
## public classes removed
|
||||
## public classes added
|
||||
## public class changes
|
||||
jdk.incubator.vector.VectorOperators
|
||||
- public abstract class jdk.incubator.vector.VectorOperators {
|
||||
+ public final class jdk.incubator.vector.VectorOperators {
|
||||
@@ -0,0 +1,190 @@
|
||||
# Public API removed/added/changed between JDK 26 and 27 (javap -public of every exported class; internal packages skipped)
|
||||
|
||||
## public classes removed
|
||||
java.security.DEREncodable
|
||||
java.util.concurrent.StructuredTaskScope$FailedException
|
||||
java.util.concurrent.StructuredTaskScope$TimeoutException
|
||||
## public classes added
|
||||
com.sun.source.tree.VarTypeTree
|
||||
java.security.BinaryEncodable
|
||||
java.time.format.DateTimeFormatterPatternProvider
|
||||
java.util.concurrent.StructuredTaskScope$CancelledByTimeoutException
|
||||
javax.crypto.CryptoException
|
||||
## public class changes
|
||||
com.sun.source.tree.Tree$Kind
|
||||
+ public static final com.sun.source.tree.Tree$Kind VAR_TYPE;
|
||||
com.sun.source.tree.TreeVisitor
|
||||
+ public abstract R visitVarType(com.sun.source.tree.VarTypeTree, P);
|
||||
com.sun.source.util.DocSourcePositions
|
||||
- public abstract long getEndPosition(com.sun.source.tree.CompilationUnitTree, com.sun.source.doctree.DocCommentTree, com.sun.source.doctree.DocTree);
|
||||
- public abstract long getStartPosition(com.sun.source.tree.CompilationUnitTree, com.sun.source.doctree.DocCommentTree, com.sun.source.doctree.DocTree);
|
||||
+ public abstract long getEndPosition(com.sun.source.doctree.DocCommentTree, com.sun.source.doctree.DocTree);
|
||||
+ public abstract long getStartPosition(com.sun.source.doctree.DocCommentTree, com.sun.source.doctree.DocTree);
|
||||
+ public default long getEndPosition(com.sun.source.tree.CompilationUnitTree, com.sun.source.doctree.DocCommentTree, com.sun.source.doctree.DocTree);
|
||||
+ public default long getStartPosition(com.sun.source.tree.CompilationUnitTree, com.sun.source.doctree.DocCommentTree, com.sun.source.doctree.DocTree);
|
||||
com.sun.source.util.SimpleTreeVisitor
|
||||
+ public R visitVarType(com.sun.source.tree.VarTypeTree, P);
|
||||
com.sun.source.util.SourcePositions
|
||||
- public abstract long getEndPosition(com.sun.source.tree.CompilationUnitTree, com.sun.source.tree.Tree);
|
||||
- public abstract long getStartPosition(com.sun.source.tree.CompilationUnitTree, com.sun.source.tree.Tree);
|
||||
+ public abstract long getEndPosition(com.sun.source.tree.Tree);
|
||||
+ public abstract long getStartPosition(com.sun.source.tree.Tree);
|
||||
+ public default long getEndPosition(com.sun.source.tree.CompilationUnitTree, com.sun.source.tree.Tree);
|
||||
+ public default long getStartPosition(com.sun.source.tree.CompilationUnitTree, com.sun.source.tree.Tree);
|
||||
com.sun.source.util.TreeScanner
|
||||
+ public R visitVarType(com.sun.source.tree.VarTypeTree, P);
|
||||
java.awt.KeyboardFocusManager
|
||||
- public static java.awt.KeyboardFocusManager getCurrentKeyboardFocusManager();
|
||||
+ public static synchronized java.awt.KeyboardFocusManager getCurrentKeyboardFocusManager();
|
||||
java.awt.geom.Arc2D
|
||||
+ public java.awt.Rectangle getBounds();
|
||||
java.lang.LazyConstant
|
||||
- public abstract T orElse(T);
|
||||
- public abstract boolean isInitialized();
|
||||
java.lang.Math
|
||||
+ public static double acosh(double);
|
||||
+ public static double asinh(double);
|
||||
+ public static double atanh(double);
|
||||
java.lang.StrictMath
|
||||
+ public static double acosh(double);
|
||||
+ public static double asinh(double);
|
||||
+ public static double atanh(double);
|
||||
java.lang.String
|
||||
+ public int encodedLength(java.nio.charset.Charset);
|
||||
java.lang.classfile.ClassFile
|
||||
+ public static final int JAVA_27_VERSION;
|
||||
java.lang.classfile.instruction.IncrementInstruction
|
||||
+ public static java.lang.classfile.instruction.IncrementInstruction of(java.lang.classfile.Opcode, int, int);
|
||||
java.lang.foreign.MemorySegment
|
||||
+ public abstract java.lang.String getString(long, java.nio.charset.Charset, long);
|
||||
+ public static long copy(java.lang.String, java.nio.charset.Charset, int, java.lang.foreign.MemorySegment, long, int);
|
||||
java.lang.foreign.SegmentAllocator
|
||||
+ public default java.lang.foreign.MemorySegment allocateFrom(java.lang.String, java.nio.charset.Charset, int, int);
|
||||
java.lang.reflect.ClassFileFormatVersion
|
||||
+ public static final java.lang.reflect.ClassFileFormatVersion RELEASE_27;
|
||||
java.lang.reflect.Executable
|
||||
- public abstract java.lang.String toGenericString();
|
||||
+ public java.lang.String toGenericString();
|
||||
java.math.BigDecimal
|
||||
+ public java.math.BigDecimal rootn(int, java.math.MathContext);
|
||||
java.security.AsymmetricKey
|
||||
- public interface java.security.AsymmetricKey extends java.security.Key,java.security.DEREncodable {
|
||||
+ public interface java.security.AsymmetricKey extends java.security.Key,java.security.BinaryEncodable {
|
||||
java.security.KeyPair
|
||||
- public final class java.security.KeyPair implements java.io.Serializable,java.security.DEREncodable {
|
||||
+ public final class java.security.KeyPair implements java.io.Serializable,java.security.BinaryEncodable {
|
||||
java.security.KeyStore
|
||||
+ public final java.time.Instant getCreationInstant(java.lang.String) throws java.security.KeyStoreException;
|
||||
java.security.KeyStoreSpi
|
||||
+ public java.time.Instant engineGetCreationInstant(java.lang.String);
|
||||
java.security.PEM
|
||||
- public final class java.security.PEM extends java.lang.Record implements java.security.DEREncodable {
|
||||
+ public final class java.security.PEM implements java.security.BinaryEncodable {
|
||||
- public final boolean equals(java.lang.Object);
|
||||
- public final byte[] decode();
|
||||
- public final int hashCode();
|
||||
- public final java.lang.String toString();
|
||||
- public java.lang.String content();
|
||||
+ public byte[] content();
|
||||
+ public byte[] decode();
|
||||
+ public java.lang.String toString();
|
||||
+ public java.security.PEM(java.lang.String, byte[]);
|
||||
+ public java.security.PEM(java.lang.String, byte[], byte[]);
|
||||
java.security.PEMDecoder
|
||||
- public <S extends java.security.DEREncodable> S decode(java.io.InputStream, java.lang.Class<S>) throws java.io.IOException;
|
||||
- public <S extends java.security.DEREncodable> S decode(java.lang.String, java.lang.Class<S>);
|
||||
- public java.security.DEREncodable decode(java.io.InputStream) throws java.io.IOException;
|
||||
- public java.security.DEREncodable decode(java.lang.String);
|
||||
- public java.security.PEMDecoder withFactory(java.security.Provider);
|
||||
+ public <S extends java.security.BinaryEncodable> S decode(java.io.InputStream, java.lang.Class<S>) throws java.io.IOException;
|
||||
+ public <S extends java.security.BinaryEncodable> S decode(java.lang.String, java.lang.Class<S>);
|
||||
+ public java.security.BinaryEncodable decode(java.io.InputStream) throws java.io.IOException;
|
||||
+ public java.security.BinaryEncodable decode(java.lang.String);
|
||||
+ public java.security.PEMDecoder withFactoriesOf(java.security.Provider);
|
||||
java.security.PEMEncoder
|
||||
- public byte[] encode(java.security.DEREncodable);
|
||||
- public java.lang.String encodeToString(java.security.DEREncodable);
|
||||
+ public byte[] encode(java.security.BinaryEncodable);
|
||||
+ public java.lang.String encodeToString(java.security.BinaryEncodable);
|
||||
java.security.cert.X509CRL
|
||||
- public abstract class java.security.cert.X509CRL extends java.security.cert.CRL implements java.security.cert.X509Extension,java.security.DEREncodable {
|
||||
+ public abstract class java.security.cert.X509CRL extends java.security.cert.CRL implements java.security.cert.X509Extension,java.security.BinaryEncodable {
|
||||
java.security.cert.X509Certificate
|
||||
- public abstract class java.security.cert.X509Certificate extends java.security.cert.Certificate implements java.security.cert.X509Extension,java.security.DEREncodable {
|
||||
+ public abstract class java.security.cert.X509Certificate extends java.security.cert.Certificate implements java.security.cert.X509Extension,java.security.BinaryEncodable {
|
||||
java.security.spec.PKCS8EncodedKeySpec
|
||||
- public class java.security.spec.PKCS8EncodedKeySpec extends java.security.spec.EncodedKeySpec implements java.security.DEREncodable {
|
||||
+ public class java.security.spec.PKCS8EncodedKeySpec extends java.security.spec.EncodedKeySpec implements java.security.BinaryEncodable {
|
||||
java.security.spec.X509EncodedKeySpec
|
||||
- public class java.security.spec.X509EncodedKeySpec extends java.security.spec.EncodedKeySpec implements java.security.DEREncodable {
|
||||
+ public class java.security.spec.X509EncodedKeySpec extends java.security.spec.EncodedKeySpec implements java.security.BinaryEncodable {
|
||||
java.util.EnumSet
|
||||
+ public java.util.Spliterator<E> spliterator();
|
||||
java.util.Locale
|
||||
- public final java.lang.String getDisplayCountry();
|
||||
- public final java.lang.String getDisplayLanguage();
|
||||
- public final java.lang.String getDisplayName();
|
||||
- public final java.lang.String getDisplayVariant();
|
||||
+ public java.lang.String getDisplayCountry();
|
||||
+ public java.lang.String getDisplayLanguage();
|
||||
+ public java.lang.String getDisplayName();
|
||||
+ public java.lang.String getDisplayVariant();
|
||||
java.util.Set
|
||||
+ public static <E> java.util.Set<E> ofLazy(java.util.Set<? extends E>, java.util.function.Predicate<? super E>);
|
||||
java.util.concurrent.StructuredTaskScope
|
||||
- public interface java.util.concurrent.StructuredTaskScope<T, R> extends java.lang.AutoCloseable {
|
||||
+ public interface java.util.concurrent.StructuredTaskScope<T, R, R_X extends java.lang.Throwable> extends java.lang.AutoCloseable {
|
||||
- public abstract R join() throws java.lang.InterruptedException;
|
||||
- public static <T, R> java.util.concurrent.StructuredTaskScope<T, R> open(java.util.concurrent.StructuredTaskScope$Joiner<? super T, ? extends R>);
|
||||
- public static <T, R> java.util.concurrent.StructuredTaskScope<T, R> open(java.util.concurrent.StructuredTaskScope$Joiner<? super T, ? extends R>, java.util.function.UnaryOperator<java.util.concurrent.StructuredTaskScope$Configuration>);
|
||||
- public static <T> java.util.concurrent.StructuredTaskScope<T, java.lang.Void> open();
|
||||
+ public abstract R join() throws R_X, java.lang.InterruptedException;
|
||||
+ public static <T, R, R_X extends java.lang.Throwable> java.util.concurrent.StructuredTaskScope<T, R, R_X> open(java.util.concurrent.StructuredTaskScope$Joiner<? super T, ? extends R, R_X>);
|
||||
+ public static <T, R, R_X extends java.lang.Throwable> java.util.concurrent.StructuredTaskScope<T, R, R_X> open(java.util.concurrent.StructuredTaskScope$Joiner<? super T, ? extends R, R_X>, java.util.function.UnaryOperator<java.util.concurrent.StructuredTaskScope$Configuration>);
|
||||
+ public static <T> java.util.concurrent.StructuredTaskScope<T, java.lang.Void, java.util.concurrent.ExecutionException> open();
|
||||
+ public static <T> java.util.concurrent.StructuredTaskScope<T, java.lang.Void, java.util.concurrent.ExecutionException> open(java.util.function.UnaryOperator<java.util.concurrent.StructuredTaskScope$Configuration>);
|
||||
java.util.concurrent.StructuredTaskScope$Joiner
|
||||
- public interface java.util.concurrent.StructuredTaskScope$Joiner<T, R> {
|
||||
+ public interface java.util.concurrent.StructuredTaskScope$Joiner<T, R, R_X extends java.lang.Throwable> {
|
||||
- public abstract R result() throws java.lang.Throwable;
|
||||
- public default void onTimeout();
|
||||
- public static <T> java.util.concurrent.StructuredTaskScope$Joiner<T, T> anySuccessfulOrThrow();
|
||||
- public static <T> java.util.concurrent.StructuredTaskScope$Joiner<T, java.lang.Void> awaitAll();
|
||||
- public static <T> java.util.concurrent.StructuredTaskScope$Joiner<T, java.lang.Void> awaitAllSuccessfulOrThrow();
|
||||
- public static <T> java.util.concurrent.StructuredTaskScope$Joiner<T, java.util.List<T>> allSuccessfulOrThrow();
|
||||
- public static <T> java.util.concurrent.StructuredTaskScope$Joiner<T, java.util.List<java.util.concurrent.StructuredTaskScope$Subtask<T>>> allUntil(java.util.function.Predicate<java.util.concurrent.StructuredTaskScope$Subtask<T>>);
|
||||
+ public abstract R result() throws R_X;
|
||||
+ public abstract R timeout() throws R_X;
|
||||
+ public static <T, R_X extends java.lang.Throwable> java.util.concurrent.StructuredTaskScope$Joiner<T, T, R_X> anySuccessfulOrThrow(java.util.function.Function<java.lang.Throwable, R_X>);
|
||||
+ public static <T, R_X extends java.lang.Throwable> java.util.concurrent.StructuredTaskScope$Joiner<T, java.lang.Void, R_X> awaitAllSuccessfulOrThrow(java.util.function.Function<java.lang.Throwable, R_X>);
|
||||
+ public static <T, R_X extends java.lang.Throwable> java.util.concurrent.StructuredTaskScope$Joiner<T, java.util.List<T>, R_X> allSuccessfulOrThrow(java.util.function.Function<java.lang.Throwable, R_X>);
|
||||
+ public static <T> java.util.concurrent.StructuredTaskScope$Joiner<T, T, java.util.concurrent.ExecutionException> anySuccessfulOrThrow();
|
||||
+ public static <T> java.util.concurrent.StructuredTaskScope$Joiner<T, java.lang.Void, java.util.concurrent.ExecutionException> awaitAllSuccessfulOrThrow();
|
||||
+ public static <T> java.util.concurrent.StructuredTaskScope$Joiner<T, java.util.List<T>, java.util.concurrent.ExecutionException> allSuccessfulOrThrow();
|
||||
+ public static <T> java.util.concurrent.StructuredTaskScope$Joiner<T, java.util.List<java.util.concurrent.StructuredTaskScope$Subtask<T>>, java.lang.RuntimeException> allUntil(java.util.function.Predicate<? super java.util.concurrent.StructuredTaskScope$Subtask<T>>);
|
||||
javax.crypto.EncryptedPrivateKeyInfo
|
||||
- public class javax.crypto.EncryptedPrivateKeyInfo implements java.security.DEREncodable {
|
||||
+ public class javax.crypto.EncryptedPrivateKeyInfo implements java.security.BinaryEncodable {
|
||||
- public java.security.KeyPair getKeyPair(java.security.Key, java.security.Provider) throws java.security.NoSuchAlgorithmException, java.security.InvalidKeyException;
|
||||
- public java.security.PrivateKey getKey(java.security.Key, java.security.Provider) throws java.security.NoSuchAlgorithmException, java.security.InvalidKeyException;
|
||||
- public static javax.crypto.EncryptedPrivateKeyInfo encrypt(java.security.DEREncodable, char[]);
|
||||
- public static javax.crypto.EncryptedPrivateKeyInfo encrypt(java.security.DEREncodable, char[], java.lang.String, java.security.spec.AlgorithmParameterSpec, java.security.Provider);
|
||||
- public static javax.crypto.EncryptedPrivateKeyInfo encrypt(java.security.DEREncodable, java.security.Key, java.lang.String, java.security.spec.AlgorithmParameterSpec, java.security.Provider, java.security.SecureRandom);
|
||||
+ public java.security.KeyPair getKeyPair(java.security.Key) throws java.security.NoSuchAlgorithmException, java.security.InvalidKeyException;
|
||||
+ public java.security.PrivateKey getKey(java.security.Key) throws java.security.NoSuchAlgorithmException, java.security.InvalidKeyException;
|
||||
+ public static javax.crypto.EncryptedPrivateKeyInfo encrypt(java.security.BinaryEncodable, char[]);
|
||||
+ public static javax.crypto.EncryptedPrivateKeyInfo encrypt(java.security.BinaryEncodable, char[], java.lang.String, java.security.spec.AlgorithmParameterSpec, java.security.Provider);
|
||||
+ public static javax.crypto.EncryptedPrivateKeyInfo encrypt(java.security.BinaryEncodable, java.security.Key, java.lang.String, java.security.spec.AlgorithmParameterSpec, java.security.Provider, java.security.SecureRandom);
|
||||
javax.lang.model.SourceVersion
|
||||
+ public static final javax.lang.model.SourceVersion RELEASE_27;
|
||||
javax.swing.JEditorPane$JEditorPaneAccessibleHypertextSupport
|
||||
+ public void changedUpdate(javax.swing.event.DocumentEvent);
|
||||
+ public void insertUpdate(javax.swing.event.DocumentEvent);
|
||||
+ public void removeUpdate(javax.swing.event.DocumentEvent);
|
||||
jdk.incubator.vector.VectorOperators
|
||||
- public abstract class jdk.incubator.vector.VectorOperators {
|
||||
+ public final class jdk.incubator.vector.VectorOperators {
|
||||
jdk.javadoc.doclet.Taglet
|
||||
+ public default java.lang.String toString(java.util.List<? extends com.sun.source.doctree.DocTree>, javax.lang.model.element.Element, java.net.URI);
|
||||
jdk.jfr.events.ContainerMemoryUsageEvent
|
||||
+ public long hostMemoryUsage;
|
||||
@@ -0,0 +1,197 @@
|
||||
# Public API removed/added/changed between JDK 25 and 26
|
||||
|
||||
## public classes removed
|
||||
java.applet.Applet
|
||||
java.applet.Applet$AccessibleApplet
|
||||
java.applet.AppletContext
|
||||
java.applet.AppletStub
|
||||
java.applet.AudioClip
|
||||
java.beans.AppletInitializer
|
||||
java.lang.StableValue
|
||||
java.security.PEMRecord
|
||||
javax.management.modelmbean.XMLParseException
|
||||
javax.swing.JApplet
|
||||
javax.swing.JApplet$AccessibleJApplet
|
||||
## public classes added
|
||||
java.lang.LazyConstant
|
||||
java.net.http.HttpOption
|
||||
java.net.http.HttpOption$Http3DiscoveryMode
|
||||
java.net.http.HttpResponse$PushPromiseHandler$PushId
|
||||
java.net.http.HttpResponse$PushPromiseHandler$PushId$Http3PushId
|
||||
java.net.http.StreamLimitException
|
||||
java.net.http.UnsupportedProtocolVersionException
|
||||
java.security.PEM
|
||||
javax.crypto.spec.HPKEParameterSpec
|
||||
jdk.jfr.events.FinalFieldMutationEvent
|
||||
jdk.jshell.SourceCodeAnalysis$CompletionContext
|
||||
jdk.jshell.SourceCodeAnalysis$CompletionState
|
||||
jdk.jshell.SourceCodeAnalysis$ElementSuggestion
|
||||
jdk.jshell.SourceCodeAnalysis$ElementSuggestionConvertor
|
||||
## public class changes
|
||||
com.sun.net.httpserver.HttpExchange
|
||||
+ public static final long RSPBODY_CHUNKED;
|
||||
+ public static final long RSPBODY_EMPTY;
|
||||
java.awt.Robot
|
||||
+ public static final int DEFAULT_DELAY;
|
||||
+ public static final int DEFAULT_STEP_LENGTH;
|
||||
+ public synchronized void type(char);
|
||||
+ public synchronized void type(int);
|
||||
+ public void click();
|
||||
+ public void click(int);
|
||||
+ public void glide(int, int);
|
||||
+ public void glide(int, int, int, int);
|
||||
+ public void glide(int, int, int, int, int, int);
|
||||
+ public void waitForIdle(int);
|
||||
java.beans.Beans
|
||||
- public static java.lang.Object instantiate(java.lang.ClassLoader, java.lang.String, java.beans.beancontext.BeanContext, java.beans.AppletInitializer) throws java.io.IOException, java.lang.ClassNotFoundException;
|
||||
java.lang.Character$UnicodeBlock
|
||||
+ public static final java.lang.Character$UnicodeBlock BERIA_ERFE;
|
||||
+ public static final java.lang.Character$UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_J;
|
||||
+ public static final java.lang.Character$UnicodeBlock MISCELLANEOUS_SYMBOLS_SUPPLEMENT;
|
||||
+ public static final java.lang.Character$UnicodeBlock SHARADA_SUPPLEMENT;
|
||||
+ public static final java.lang.Character$UnicodeBlock SIDETIC;
|
||||
+ public static final java.lang.Character$UnicodeBlock TAI_YO;
|
||||
+ public static final java.lang.Character$UnicodeBlock TANGUT_COMPONENTS_SUPPLEMENT;
|
||||
+ public static final java.lang.Character$UnicodeBlock TOLONG_SIKI;
|
||||
java.lang.Character$UnicodeScript
|
||||
+ public static final java.lang.Character$UnicodeScript BERIA_ERFE;
|
||||
+ public static final java.lang.Character$UnicodeScript SIDETIC;
|
||||
+ public static final java.lang.Character$UnicodeScript TAI_YO;
|
||||
+ public static final java.lang.Character$UnicodeScript TOLONG_SIKI;
|
||||
java.lang.Process
|
||||
- public abstract class java.lang.Process {
|
||||
+ public abstract class java.lang.Process implements java.io.Closeable {
|
||||
+ public void close() throws java.io.IOException;
|
||||
java.lang.String
|
||||
+ public boolean equalsFoldCase(java.lang.String);
|
||||
+ public int compareToFoldCase(java.lang.String);
|
||||
+ public static final java.util.Comparator<java.lang.String> UNICODE_CASEFOLD_ORDER;
|
||||
java.lang.Thread
|
||||
- public final void stop();
|
||||
java.lang.classfile.ClassFile
|
||||
+ public static final int JAVA_26_VERSION;
|
||||
java.lang.management.MemoryMXBean
|
||||
+ public default long getTotalGcCpuTime();
|
||||
java.lang.reflect.ClassFileFormatVersion
|
||||
+ public static final java.lang.reflect.ClassFileFormatVersion RELEASE_26;
|
||||
java.math.BigInteger
|
||||
+ public java.math.BigInteger rootn(int);
|
||||
+ public java.math.BigInteger[] rootnAndRemainder(int);
|
||||
java.net.MulticastSocket
|
||||
- public byte getTTL() throws java.io.IOException;
|
||||
- public void send(java.net.DatagramPacket, byte) throws java.io.IOException;
|
||||
- public void setTTL(byte) throws java.io.IOException;
|
||||
java.net.http.HttpClient$Version
|
||||
+ public static final java.net.http.HttpClient$Version HTTP_3;
|
||||
java.net.http.HttpRequest
|
||||
+ public <T> java.util.Optional<T> getOption(java.net.http.HttpOption<T>);
|
||||
java.net.http.HttpRequest$BodyPublishers
|
||||
+ public static java.net.http.HttpRequest$BodyPublisher ofFileChannel(java.nio.channels.FileChannel, long, long) throws java.io.IOException;
|
||||
java.net.http.HttpRequest$Builder
|
||||
+ public default <T> java.net.http.HttpRequest$Builder setOption(java.net.http.HttpOption<T>, T);
|
||||
java.net.http.HttpResponse$PushPromiseHandler
|
||||
+ public default void applyPushPromise(java.net.http.HttpRequest, java.net.http.HttpRequest, java.net.http.HttpResponse$PushPromiseHandler$PushId, java.util.function.Function<java.net.http.HttpResponse$BodyHandler<T>, java.util.concurrent.CompletableFuture<java.net.http.HttpResponse<T>>>);
|
||||
+ public default void notifyAdditionalPromise(java.net.http.HttpRequest, java.net.http.HttpResponse$PushPromiseHandler$PushId);
|
||||
java.nio.ByteOrder
|
||||
- public final class java.nio.ByteOrder {
|
||||
+ public final class java.nio.ByteOrder extends java.lang.Enum<java.nio.ByteOrder> {
|
||||
- public java.lang.String toString();
|
||||
+ public static java.nio.ByteOrder valueOf(java.lang.String);
|
||||
+ public static java.nio.ByteOrder[] values();
|
||||
java.security.SecureRandom
|
||||
+ public long nextLong();
|
||||
java.sql.Array
|
||||
- public interface java.sql.Array {
|
||||
+ public interface java.sql.Array extends java.lang.AutoCloseable {
|
||||
+ public default void close() throws java.sql.SQLException;
|
||||
java.sql.Blob
|
||||
- public interface java.sql.Blob {
|
||||
+ public interface java.sql.Blob extends java.lang.AutoCloseable {
|
||||
+ public default void close() throws java.sql.SQLException;
|
||||
java.sql.Clob
|
||||
- public interface java.sql.Clob {
|
||||
+ public interface java.sql.Clob extends java.lang.AutoCloseable {
|
||||
+ public default void close() throws java.sql.SQLException;
|
||||
java.sql.Connection
|
||||
+ public default boolean isSimpleIdentifier(java.lang.String) throws java.sql.SQLException;
|
||||
+ public default java.lang.String enquoteIdentifier(java.lang.String, boolean) throws java.sql.SQLException;
|
||||
+ public default java.lang.String enquoteLiteral(java.lang.String) throws java.sql.SQLException;
|
||||
+ public default java.lang.String enquoteNCharLiteral(java.lang.String) throws java.sql.SQLException;
|
||||
java.sql.JDBCType
|
||||
+ public static final java.sql.JDBCType DECFLOAT;
|
||||
+ public static final java.sql.JDBCType JSON;
|
||||
java.sql.SQLXML
|
||||
- public interface java.sql.SQLXML {
|
||||
+ public interface java.sql.SQLXML extends java.lang.AutoCloseable {
|
||||
+ public default void close() throws java.sql.SQLException;
|
||||
java.sql.Types
|
||||
+ public static final int DECFLOAT;
|
||||
+ public static final int JSON;
|
||||
java.time.Duration
|
||||
+ public static final java.time.Duration MAX;
|
||||
+ public static final java.time.Duration MIN;
|
||||
java.time.Instant
|
||||
+ public java.time.Instant plusSaturating(java.time.Duration);
|
||||
java.util.Comparator
|
||||
+ public default <U extends T> U max(U, U);
|
||||
+ public default <U extends T> U min(U, U);
|
||||
java.util.List
|
||||
+ public static <E> java.util.List<E> ofLazy(int, java.util.function.IntFunction<? extends E>);
|
||||
java.util.Locale$IsoCountryCode
|
||||
- public abstract class java.util.Locale$IsoCountryCode extends java.lang.Enum<java.util.Locale$IsoCountryCode> {
|
||||
+ public final class java.util.Locale$IsoCountryCode extends java.lang.Enum<java.util.Locale$IsoCountryCode> {
|
||||
java.util.Map
|
||||
+ public static <K, V> java.util.Map<K, V> ofLazy(java.util.Set<? extends K>, java.util.function.Function<? super K, ? extends V>);
|
||||
java.util.UUID
|
||||
+ public static java.util.UUID ofEpochMillis(long);
|
||||
java.util.concurrent.StructuredTaskScope
|
||||
- public static <T, R> java.util.concurrent.StructuredTaskScope<T, R> open(java.util.concurrent.StructuredTaskScope$Joiner<? super T, ? extends R>, java.util.function.Function<java.util.concurrent.StructuredTaskScope$Configuration, java.util.concurrent.StructuredTaskScope$Configuration>);
|
||||
+ public static <T, R> java.util.concurrent.StructuredTaskScope<T, R> open(java.util.concurrent.StructuredTaskScope$Joiner<? super T, ? extends R>, java.util.function.UnaryOperator<java.util.concurrent.StructuredTaskScope$Configuration>);
|
||||
java.util.concurrent.StructuredTaskScope$Joiner
|
||||
- public default boolean onComplete(java.util.concurrent.StructuredTaskScope$Subtask<? extends T>);
|
||||
- public default boolean onFork(java.util.concurrent.StructuredTaskScope$Subtask<? extends T>);
|
||||
- public static <T> java.util.concurrent.StructuredTaskScope$Joiner<T, T> anySuccessfulResultOrThrow();
|
||||
- public static <T> java.util.concurrent.StructuredTaskScope$Joiner<T, java.util.stream.Stream<java.util.concurrent.StructuredTaskScope$Subtask<T>>> allSuccessfulOrThrow();
|
||||
- public static <T> java.util.concurrent.StructuredTaskScope$Joiner<T, java.util.stream.Stream<java.util.concurrent.StructuredTaskScope$Subtask<T>>> allUntil(java.util.function.Predicate<java.util.concurrent.StructuredTaskScope$Subtask<? extends T>>);
|
||||
+ public default boolean onComplete(java.util.concurrent.StructuredTaskScope$Subtask<T>);
|
||||
+ public default boolean onFork(java.util.concurrent.StructuredTaskScope$Subtask<T>);
|
||||
+ public default void onTimeout();
|
||||
+ public static <T> java.util.concurrent.StructuredTaskScope$Joiner<T, T> anySuccessfulOrThrow();
|
||||
+ public static <T> java.util.concurrent.StructuredTaskScope$Joiner<T, java.util.List<T>> allSuccessfulOrThrow();
|
||||
+ public static <T> java.util.concurrent.StructuredTaskScope$Joiner<T, java.util.List<java.util.concurrent.StructuredTaskScope$Subtask<T>>> allUntil(java.util.function.Predicate<java.util.concurrent.StructuredTaskScope$Subtask<T>>);
|
||||
java.util.concurrent.ThreadLocalRandom
|
||||
+ public double nextGaussian();
|
||||
javax.crypto.EncryptedPrivateKeyInfo
|
||||
- public java.security.PrivateKey getKey(char[]) throws java.security.GeneralSecurityException;
|
||||
- public java.security.PrivateKey getKey(java.security.Key, java.security.Provider) throws java.security.GeneralSecurityException;
|
||||
- public static javax.crypto.EncryptedPrivateKeyInfo encryptKey(java.security.PrivateKey, char[]);
|
||||
- public static javax.crypto.EncryptedPrivateKeyInfo encryptKey(java.security.PrivateKey, char[], java.lang.String, java.security.spec.AlgorithmParameterSpec, java.security.Provider);
|
||||
- public static javax.crypto.EncryptedPrivateKeyInfo encryptKey(java.security.PrivateKey, java.security.Key, java.lang.String, java.security.spec.AlgorithmParameterSpec, java.security.Provider, java.security.SecureRandom);
|
||||
+ public java.security.KeyPair getKeyPair(char[]) throws java.security.NoSuchAlgorithmException, java.security.InvalidKeyException;
|
||||
+ public java.security.KeyPair getKeyPair(java.security.Key, java.security.Provider) throws java.security.NoSuchAlgorithmException, java.security.InvalidKeyException;
|
||||
+ public java.security.PrivateKey getKey(char[]) throws java.security.NoSuchAlgorithmException, java.security.InvalidKeyException;
|
||||
+ public java.security.PrivateKey getKey(java.security.Key, java.security.Provider) throws java.security.NoSuchAlgorithmException, java.security.InvalidKeyException;
|
||||
+ public static javax.crypto.EncryptedPrivateKeyInfo encrypt(java.security.DEREncodable, char[]);
|
||||
+ public static javax.crypto.EncryptedPrivateKeyInfo encrypt(java.security.DEREncodable, char[], java.lang.String, java.security.spec.AlgorithmParameterSpec, java.security.Provider);
|
||||
+ public static javax.crypto.EncryptedPrivateKeyInfo encrypt(java.security.DEREncodable, java.security.Key, java.lang.String, java.security.spec.AlgorithmParameterSpec, java.security.Provider, java.security.SecureRandom);
|
||||
javax.imageio.spi.ServiceRegistry
|
||||
- public void finalize() throws java.lang.Throwable;
|
||||
javax.lang.model.SourceVersion
|
||||
+ public static final javax.lang.model.SourceVersion RELEASE_26;
|
||||
javax.management.modelmbean.DescriptorSupport
|
||||
- public javax.management.modelmbean.DescriptorSupport(java.lang.String) throws javax.management.MBeanException, javax.management.RuntimeOperationsException, javax.management.modelmbean.XMLParseException;
|
||||
- public synchronized java.lang.String toXMLString();
|
||||
javax.swing.RepaintManager
|
||||
- public void addDirtyRegion(java.applet.Applet, int, int, int, int);
|
||||
jdk.incubator.vector.VectorOperators
|
||||
- public static final jdk.incubator.vector.VectorOperators$Binary SUADD;
|
||||
+ public static final jdk.incubator.vector.VectorOperators$Associative SUADD;
|
||||
jdk.jpackage.main.Main
|
||||
- public int execute(java.io.PrintWriter, java.io.PrintWriter, java.lang.String...);
|
||||
- public static final java.util.ResourceBundle I18N;
|
||||
- public static void main(java.lang.String...) throws java.lang.Exception;
|
||||
+ public static void main(java.lang.String...);
|
||||
jdk.jshell.SourceCodeAnalysis
|
||||
+ public abstract <S> java.util.List<S> completionSuggestions(java.lang.String, int, jdk.jshell.SourceCodeAnalysis$ElementSuggestionConvertor<S>);
|
||||
jdk.jshell.SourceCodeAnalysis$Documentation
|
||||
+ public default int activeParameterIndex();
|
||||
@@ -0,0 +1,54 @@
|
||||
# JVM options that JDK 27 removed or renamed. Each runs 'java <option> -version' on 26 and on 27.
|
||||
|
||||
=== -noverify
|
||||
JDK 26:
|
||||
OpenJDK 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release.
|
||||
OpenJDK 64-Bit Server VM Corretto-26.0.2.11.1 (build 26.0.2.1+11-FR, mixed mode, sharing)
|
||||
JDK 27:
|
||||
Unrecognized option: -noverify
|
||||
Error: Could not create the Java Virtual Machine.
|
||||
|
||||
=== -Xverify:none
|
||||
JDK 26:
|
||||
OpenJDK 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release.
|
||||
OpenJDK 64-Bit Server VM Corretto-26.0.2.11.1 (build 26.0.2.1+11-FR, mixed mode, sharing)
|
||||
JDK 27:
|
||||
Unrecognized verification option: -Xverify:none
|
||||
Error: Could not create the Java Virtual Machine.
|
||||
|
||||
=== -noclassgc
|
||||
JDK 26:
|
||||
Warning: -noclassgc option is deprecated and may be removed in a future release.
|
||||
OpenJDK 64-Bit Server VM Corretto-26.0.2.11.1 (build 26.0.2.1+11-FR, mixed mode, sharing)
|
||||
JDK 27:
|
||||
Unrecognized option: -noclassgc
|
||||
Error: Could not create the Java Virtual Machine.
|
||||
|
||||
=== -XX:+UseCompressedClassPointers
|
||||
JDK 26:
|
||||
OpenJDK 64-Bit Server VM warning: Option UseCompressedClassPointers was deprecated in version 25.0 and will likely be removed in a future release.
|
||||
OpenJDK 64-Bit Server VM Corretto-26.0.2.11.1 (build 26.0.2.1+11-FR, mixed mode, sharing)
|
||||
JDK 27:
|
||||
OpenJDK 64-Bit Server VM warning: Ignoring option UseCompressedClassPointers; support was removed in 27.0
|
||||
OpenJDK 64-Bit Server VM Corretto-27.0.0.35.1 (build 27+35-FR, mixed mode, sharing)
|
||||
|
||||
=== -XX:InitiatingHeapOccupancyPercent=40
|
||||
JDK 26:
|
||||
OpenJDK 64-Bit Server VM Corretto-26.0.2.11.1 (build 26.0.2.1+11-FR, mixed mode, sharing)
|
||||
JDK 27:
|
||||
OpenJDK 64-Bit Server VM warning: Option InitiatingHeapOccupancyPercent was deprecated in version 27.0 and will likely be removed in a future release. Use option G1IHOP instead.
|
||||
OpenJDK 64-Bit Server VM Corretto-27.0.0.35.1 (build 27+35-FR, mixed mode, sharing)
|
||||
|
||||
=== -XX:G1IHOP=40
|
||||
JDK 26:
|
||||
Unrecognized VM option 'G1IHOP=40'
|
||||
Error: Could not create the Java Virtual Machine.
|
||||
JDK 27:
|
||||
OpenJDK 64-Bit Server VM Corretto-27.0.0.35.1 (build 27+35-FR, mixed mode, sharing)
|
||||
|
||||
=== -XX:+UnlockExperimentalVMOptions -XX:+UseGraalJIT (JVMCI and the Graal JIT hook were removed in 27)
|
||||
JDK 26:
|
||||
Cannot use JVMCI compiler: JVMCI compiler 'graal' specified by jvmci.Compiler not found
|
||||
JDK 27:
|
||||
Unrecognized VM option 'UseGraalJIT'
|
||||
Error: Could not create the Java Virtual Machine.
|
||||
@@ -0,0 +1,21 @@
|
||||
# Behaviour changes that need no new API to observe
|
||||
|
||||
=== a script that pins the VFORK process launch mechanism
|
||||
JDK 26: java -Djdk.lang.Process.launchMechanism=VFORK SpawnProbe
|
||||
VFORK MODE DEPRECATED
|
||||
The VFORK launch mechanism has been deprecated for being dangerous.
|
||||
It will be removed in a future java version. Either remove the
|
||||
JDK 27: java -Djdk.lang.Process.launchMechanism=VFORK SpawnProbe
|
||||
The VFORK launch mechanism has been removed. Switching to FORK instead.
|
||||
Please remove the jdk.lang.Process.launchMechanism property (preferred)
|
||||
or use FORK mode instead (-Djdk.lang.Process.launchMechanism=FORK).
|
||||
|
||||
=== the legacy ISO 639 language codes property (iw, ji, in)
|
||||
JDK 26: java -Djava.locale.useOldISOCodes=true Compat
|
||||
java.version = 26.0.2.1
|
||||
WARNING: The use of the system property "java.locale.useOldISOCodes" is deprecated. It will be removed in a future release of the JDK.
|
||||
Locale("iw").language = iw (Hebrew; old code 'iw', current code 'he')
|
||||
JDK 27: java -Djava.locale.useOldISOCodes=true Compat
|
||||
java.version = 27
|
||||
WARNING: The system property "java.locale.useOldISOCodes" is no longer supported. Any specified value will be ignored.
|
||||
Locale("iw").language = he (Hebrew; old code 'iw', current code 'he')
|
||||
@@ -0,0 +1,12 @@
|
||||
# New public API in 27, each exercised once (found by diffing javap dumps, see 51-api-diff-26-to-27.txt)
|
||||
Math.acosh(2) = 1.316958
|
||||
Math.asinh(1) = 0.881374
|
||||
Math.atanh(.5) = 0.549306
|
||||
CHECK ok : acosh inverts cosh
|
||||
"naïve café".length() = 10, encodedLength(UTF_8) = 12
|
||||
CHECK ok : encodedLength matches getBytes().length without allocating the array
|
||||
BigDecimal(27).rootn(3) = 3
|
||||
CHECK ok : rootn(3) of 27 is 3
|
||||
KeyStore.getCreationInstant("aes-key") returns an Instant: true
|
||||
CHECK ok : KeyStore.getCreationInstant returns the entry's creation time as a java.time.Instant
|
||||
CHECK ok : Set.ofLazy(Set, Predicate) exists (preview API)
|
||||
@@ -0,0 +1,45 @@
|
||||
# JEP 500: reflection writing to a final field, same class file behaviour on 25 and on 26
|
||||
|
||||
=== JDK 25 (class compiled --release 25)
|
||||
field reads : 9090
|
||||
port() returns : 8080
|
||||
|
||||
=== JDK 26, defaults
|
||||
WARNING: Final field port in class FinalFieldMutation$Config has been mutated reflectively by class FinalFieldMutation in unnamed module @<hash> (file:<repo>/build/recap26/26/)
|
||||
WARNING: Use --enable-final-field-mutation=ALL-UNNAMED to avoid a warning
|
||||
WARNING: Mutating final fields will be blocked in a future release unless final field mutation is enabled
|
||||
field reads : 9090
|
||||
port() returns : 8080
|
||||
|
||||
=== JDK 26, --enable-final-field-mutation=ALL-UNNAMED (the opt-in the warning asks for)
|
||||
field reads : 9090
|
||||
port() returns : 8080
|
||||
|
||||
=== JDK 26, --illegal-final-field-mutation=deny (what a future default will look like)
|
||||
setInt refused : class FinalFieldMutation (in unnamed module @<hash>) cannot set final field FinalFieldMutation$Config.port (in unnamed module @<hash>), unnamed module @<hash> is not allowed to mutate final fields
|
||||
|
||||
=== JDK 26, --illegal-final-field-mutation=debug (warning plus the offending stack trace)
|
||||
Final field port in class FinalFieldMutation$Config has been mutated reflectively by class FinalFieldMutation in unnamed module @<hash> (file:<repo>/build/recap26/26/)
|
||||
at java.base/java.lang.reflect.Field.postSetFinal(Field.java:1534)
|
||||
at java.base/java.lang.reflect.Field.setFinal(Field.java:1449)
|
||||
at java.base/java.lang.reflect.Field.setInt(Field.java:1134)
|
||||
at FinalFieldMutation.main(FinalFieldMutation.java:22)
|
||||
field reads : 9090
|
||||
port() returns : 8080
|
||||
|
||||
=== JDK 26, JFR default settings, [no flag]: jfr print --events jdk.FinalFieldMutation
|
||||
jdk.FinalFieldMutation
|
||||
declaringClass = FinalFieldMutation$Config (classLoader = app)
|
||||
fieldName = "port"
|
||||
FinalFieldMutation.main(String[]) line: 22
|
||||
events recorded: 1
|
||||
|
||||
=== JDK 26, JFR default settings, [--enable-final-field-mutation=ALL-UNNAMED]: jfr print --events jdk.FinalFieldMutation
|
||||
jdk.FinalFieldMutation
|
||||
declaringClass = FinalFieldMutation$Config (classLoader = app)
|
||||
fieldName = "port"
|
||||
FinalFieldMutation.main(String[]) line: 22
|
||||
events recorded: 1
|
||||
|
||||
=== JDK 26, JFR default settings, [--illegal-final-field-mutation=deny]: jfr print --events jdk.FinalFieldMutation
|
||||
events recorded: 0
|
||||
@@ -0,0 +1,20 @@
|
||||
# JEP 516: can the cache's archived heap objects be used? One row per (JDK, GC the cache was built under, GC at run time).
|
||||
# 'heap objects' = the log says the archived module graph was used; 'unusable' = the JVM refused the whole cache.
|
||||
JDK 25 cache built under G1 run under Serial -> heap objects used (full module graph: enabled)
|
||||
JDK 25 cache built under G1 run under G1 -> heap objects used (full module graph: enabled)
|
||||
JDK 25 cache built under G1 run under Z -> unusable: saved state of UseCompressedOops and UseCompressedClassPointers is different from runtime
|
||||
JDK 25 cache built under Z run under Serial -> unusable: saved state of UseCompressedOops and UseCompressedClassPointers is different from runtime
|
||||
JDK 25 cache built under Z run under G1 -> unusable: saved state of UseCompressedOops and UseCompressedClassPointers is different from runtime
|
||||
JDK 25 cache built under Z run under Z -> cache used, heap objects NOT used (full module graph: disabled)
|
||||
JDK 26 cache built under G1 run under Serial -> heap objects used (full module graph: enabled)
|
||||
JDK 26 cache built under G1 run under G1 -> heap objects used (full module graph: enabled)
|
||||
JDK 26 cache built under G1 run under Z -> unusable: saved state of UseCompressedOops and UseCompressedClassPointers is different from runtime
|
||||
JDK 26 cache built under Z run under Serial -> unusable: saved state of UseCompressedOops and UseCompressedClassPointers is different from runtime
|
||||
JDK 26 cache built under Z run under G1 -> unusable: saved state of UseCompressedOops and UseCompressedClassPointers is different from runtime
|
||||
JDK 26 cache built under Z run under Z -> heap objects used (full module graph: enabled)
|
||||
JDK 27 cache built under G1 run under Serial -> heap objects used (full module graph: enabled)
|
||||
JDK 27 cache built under G1 run under G1 -> heap objects used (full module graph: enabled)
|
||||
JDK 27 cache built under G1 run under Z -> unusable: saved state of UseCompressedOops (1) is different from runtime (0)
|
||||
JDK 27 cache built under Z run under Serial -> unusable: saved state of UseCompressedOops (0) is different from runtime (1)
|
||||
JDK 27 cache built under Z run under G1 -> unusable: saved state of UseCompressedOops (0) is different from runtime (1)
|
||||
JDK 27 cache built under Z run under Z -> heap objects used (full module graph: enabled)
|
||||
@@ -0,0 +1,7 @@
|
||||
# Wall-clock ms for 'java -cp app.jar AotApp' (median of 9), no AOT cache vs cache built under the same GC. INDICATIVE: shared 2-CPU sandbox.
|
||||
JDK 25 G1 no cache: 57 ms with cache: 37 ms
|
||||
JDK 25 Z no cache: 83 ms with cache: 81 ms
|
||||
JDK 26 G1 no cache: 59 ms with cache: 35 ms
|
||||
JDK 26 Z no cache: 62 ms with cache: 40 ms
|
||||
JDK 27 G1 no cache: 61 ms with cache: 36 ms
|
||||
JDK 27 Z no cache: 63 ms with cache: 38 ms
|
||||
@@ -0,0 +1,34 @@
|
||||
# Source that compiled on 25 and does not on 26
|
||||
|
||||
=== recap26/src/broken/AppletGone.java
|
||||
javac (JDK 25, --release 25): exit 0
|
||||
<repo>/recap26/src/broken/AppletGone.java:5: warning: [removal] Applet in java.applet has been deprecated and marked for removal
|
||||
public class AppletGone extends Applet {
|
||||
^
|
||||
1 warning
|
||||
javac (JDK 26, --release 26): exit 1
|
||||
<repo>/recap26/src/broken/AppletGone.java:3: error: package java.applet does not exist
|
||||
import java.applet.Applet;
|
||||
^
|
||||
<repo>/recap26/src/broken/AppletGone.java:5: error: cannot find symbol
|
||||
public class AppletGone extends Applet {
|
||||
^
|
||||
symbol: class Applet
|
||||
<repo>/recap26/src/broken/AppletGone.java:6: error: init() in AppletGone does not override or implement a method from a supertype
|
||||
@Override public void init() { System.out.println("applet init"); }
|
||||
^
|
||||
3 errors
|
||||
|
||||
=== recap26/src/broken/ThreadStopGone.java
|
||||
javac (JDK 25, --release 25): exit 0
|
||||
<repo>/recap26/src/broken/ThreadStopGone.java:5: warning: [removal] stop() in Thread has been deprecated and marked for removal
|
||||
t.stop();
|
||||
^
|
||||
1 warning
|
||||
javac (JDK 26, --release 26): exit 1
|
||||
<repo>/recap26/src/broken/ThreadStopGone.java:5: error: cannot find symbol
|
||||
t.stop();
|
||||
^
|
||||
symbol: method stop()
|
||||
location: variable t of type Thread
|
||||
1 error
|
||||
@@ -0,0 +1,12 @@
|
||||
CHECK ok : "STRASSE".equalsFoldCase("stra" + sharp s + "e") is true (full case folding)
|
||||
CHECK ok : equalsIgnoreCase says false for the same pair (simple folding only)
|
||||
CHECK ok : "apple".compareToFoldCase("BANANA") < 0
|
||||
CHECK ok : sorted with String.UNICODE_CASEFOLD_ORDER: [A, b, B, c]
|
||||
CHECK ok : UUID.ofEpochMillis(..).version() == 7
|
||||
CHECK ok : the first 48 bits are the timestamp: 018bcfe5-6800-...
|
||||
CHECK ok : try-with-resources on Process (implements Closeable in 26)
|
||||
CHECK ok : MemoryMXBean.getTotalGcCpuTime() exists and is non-negative
|
||||
CHECK ok : ByteOrder is an enum: [LITTLE_ENDIAN, BIG_ENDIAN]
|
||||
CHECK ok : HttpClient.Version.HTTP_3 exists and is accepted by the builder
|
||||
CHECK ok : Character.UnicodeBlock.SIDETIC exists (Unicode 17)
|
||||
exit code: 0
|
||||
@@ -0,0 +1,26 @@
|
||||
# JEP 517: a client that prefers HTTP/3 against a server that only speaks HTTP/1.1 over TLS (loopback, JDK's own HttpsServer)
|
||||
# There is no live HTTP/3 server in this transcript: the sandbox has no UDP egress. The API surface is javap output below.
|
||||
client asked for : HTTP_3
|
||||
server answered : HTTP_1_1 200 hello
|
||||
HTTP_3_URI_ONLY : java.net.http.HttpConnectTimeoutException: quic handshake timeout
|
||||
|
||||
# javap --module java.net.http -public java.net.http.HttpOption 'java.net.http.HttpOption$Http3DiscoveryMode'
|
||||
Compiled from "HttpOption.java"
|
||||
public interface java.net.http.HttpOption<T> {
|
||||
public static final java.net.http.HttpOption<java.net.http.HttpOption$Http3DiscoveryMode> H3_DISCOVERY;
|
||||
public abstract java.lang.String name();
|
||||
public abstract java.lang.Class<T> type();
|
||||
}
|
||||
Compiled from "HttpOption.java"
|
||||
public final class java.net.http.HttpOption$Http3DiscoveryMode extends java.lang.Enum<java.net.http.HttpOption$Http3DiscoveryMode> {
|
||||
public static final java.net.http.HttpOption$Http3DiscoveryMode ANY;
|
||||
public static final java.net.http.HttpOption$Http3DiscoveryMode ALT_SVC;
|
||||
public static final java.net.http.HttpOption$Http3DiscoveryMode HTTP_3_URI_ONLY;
|
||||
public static java.net.http.HttpOption$Http3DiscoveryMode[] values();
|
||||
public static java.net.http.HttpOption$Http3DiscoveryMode valueOf(java.lang.String);
|
||||
}
|
||||
|
||||
# javap ... HttpClient$Version
|
||||
public static final java.net.http.HttpClient$Version HTTP_1_1;
|
||||
public static final java.net.http.HttpClient$Version HTTP_2;
|
||||
public static final java.net.http.HttpClient$Version HTTP_3;
|
||||
@@ -0,0 +1,69 @@
|
||||
# One class file (javac 21 --release 21), four JVMs
|
||||
|
||||
$ java -cp hub HubExamples (JDK 21)
|
||||
java.version = 21.0.12.1
|
||||
CHECK ok : record accessor: c.email()
|
||||
CHECK ok : record toString: Customer[id=1, [email protected], country=IN]
|
||||
CHECK ok : compact constructor rejects an email without @: Invalid email
|
||||
CHECK ok : area(Square(3)) == 9.0
|
||||
CHECK ok : area(Triangle(4, 5)) == 10.0
|
||||
CHECK ok : guard pattern: Circle(101) is a large circle
|
||||
CHECK ok : guard pattern: Circle(1) is a small circle
|
||||
CHECK ok : all 10,000 virtual-thread tasks completed before close() returned
|
||||
CHECK ok : and it took seconds, not the 1,000 s a serial loop needs (exact time is machine dependent, not printed)
|
||||
CHECK ok : Thread.ofVirtual().name(..).start(..) gives a virtual thread
|
||||
CHECK ok : List.getFirst() / getLast()
|
||||
CHECK ok : List.reversed(): [chris, brian, alex]
|
||||
CHECK ok : reversed() is a view, not a copy: it sees the element added afterwards
|
||||
CHECK ok : LinkedHashSet.getFirst() == 3, getLast() == 5
|
||||
|
||||
$ java -cp hub HubExamples (JDK 25)
|
||||
java.version = 25.0.4.1
|
||||
CHECK ok : record accessor: c.email()
|
||||
CHECK ok : record toString: Customer[id=1, [email protected], country=IN]
|
||||
CHECK ok : compact constructor rejects an email without @: Invalid email
|
||||
CHECK ok : area(Square(3)) == 9.0
|
||||
CHECK ok : area(Triangle(4, 5)) == 10.0
|
||||
CHECK ok : guard pattern: Circle(101) is a large circle
|
||||
CHECK ok : guard pattern: Circle(1) is a small circle
|
||||
CHECK ok : all 10,000 virtual-thread tasks completed before close() returned
|
||||
CHECK ok : and it took seconds, not the 1,000 s a serial loop needs (exact time is machine dependent, not printed)
|
||||
CHECK ok : Thread.ofVirtual().name(..).start(..) gives a virtual thread
|
||||
CHECK ok : List.getFirst() / getLast()
|
||||
CHECK ok : List.reversed(): [chris, brian, alex]
|
||||
CHECK ok : reversed() is a view, not a copy: it sees the element added afterwards
|
||||
CHECK ok : LinkedHashSet.getFirst() == 3, getLast() == 5
|
||||
|
||||
$ java -cp hub HubExamples (JDK 26)
|
||||
java.version = 26.0.2.1
|
||||
CHECK ok : record accessor: c.email()
|
||||
CHECK ok : record toString: Customer[id=1, [email protected], country=IN]
|
||||
CHECK ok : compact constructor rejects an email without @: Invalid email
|
||||
CHECK ok : area(Square(3)) == 9.0
|
||||
CHECK ok : area(Triangle(4, 5)) == 10.0
|
||||
CHECK ok : guard pattern: Circle(101) is a large circle
|
||||
CHECK ok : guard pattern: Circle(1) is a small circle
|
||||
CHECK ok : all 10,000 virtual-thread tasks completed before close() returned
|
||||
CHECK ok : and it took seconds, not the 1,000 s a serial loop needs (exact time is machine dependent, not printed)
|
||||
CHECK ok : Thread.ofVirtual().name(..).start(..) gives a virtual thread
|
||||
CHECK ok : List.getFirst() / getLast()
|
||||
CHECK ok : List.reversed(): [chris, brian, alex]
|
||||
CHECK ok : reversed() is a view, not a copy: it sees the element added afterwards
|
||||
CHECK ok : LinkedHashSet.getFirst() == 3, getLast() == 5
|
||||
|
||||
$ java -cp hub HubExamples (JDK 27)
|
||||
java.version = 27
|
||||
CHECK ok : record accessor: c.email()
|
||||
CHECK ok : record toString: Customer[id=1, [email protected], country=IN]
|
||||
CHECK ok : compact constructor rejects an email without @: Invalid email
|
||||
CHECK ok : area(Square(3)) == 9.0
|
||||
CHECK ok : area(Triangle(4, 5)) == 10.0
|
||||
CHECK ok : guard pattern: Circle(101) is a large circle
|
||||
CHECK ok : guard pattern: Circle(1) is a small circle
|
||||
CHECK ok : all 10,000 virtual-thread tasks completed before close() returned
|
||||
CHECK ok : and it took seconds, not the 1,000 s a serial loop needs (exact time is machine dependent, not printed)
|
||||
CHECK ok : Thread.ofVirtual().name(..).start(..) gives a virtual thread
|
||||
CHECK ok : List.getFirst() / getLast()
|
||||
CHECK ok : List.reversed(): [chris, brian, alex]
|
||||
CHECK ok : reversed() is a view, not a copy: it sees the element added afterwards
|
||||
CHECK ok : LinkedHashSet.getFirst() == 3, getLast() == 5
|
||||
@@ -0,0 +1,41 @@
|
||||
# ScopedValue (JEP 506). Preview API in 21, final in 25.
|
||||
|
||||
$ javac ScopedValueDemo.java (JDK 21, no flag)
|
||||
<repo>/lanes/src/ScopedValueDemo.java:9: error: ScopedValue is a preview API and is disabled by default.
|
||||
static final ScopedValue<String> CURRENT_USER = ScopedValue.newInstance();
|
||||
^
|
||||
(use --enable-preview to enable preview APIs)
|
||||
<repo>/lanes/src/ScopedValueDemo.java:9: error: ScopedValue is a preview API and is disabled by default.
|
||||
static final ScopedValue<String> CURRENT_USER = ScopedValue.newInstance();
|
||||
^
|
||||
(use --enable-preview to enable preview APIs)
|
||||
<repo>/lanes/src/ScopedValueDemo.java:13: error: ScopedValue is a preview API and is disabled by default.
|
||||
ScopedValue.where(CURRENT_USER, "ankur").run(() -> {
|
||||
^
|
||||
(use --enable-preview to enable preview APIs)
|
||||
3 errors
|
||||
exit=1
|
||||
|
||||
$ javac ScopedValueDemo.java (JDK 25, no flag)
|
||||
exit=0
|
||||
$ java ScopedValueDemo (JDK 25)
|
||||
java.version = 25.0.4.1
|
||||
CHECK ok : inside the scope: CURRENT_USER.get() == ankur
|
||||
CHECK ok : a method that was never passed the value still sees it
|
||||
CHECK ok : outside the scope: CURRENT_USER.get() throws NoSuchElementException
|
||||
|
||||
$ javac ScopedValueDemo.java (JDK 26, no flag)
|
||||
exit=0
|
||||
$ java ScopedValueDemo (JDK 26)
|
||||
java.version = 26.0.2.1
|
||||
CHECK ok : inside the scope: CURRENT_USER.get() == ankur
|
||||
CHECK ok : a method that was never passed the value still sees it
|
||||
CHECK ok : outside the scope: CURRENT_USER.get() throws NoSuchElementException
|
||||
|
||||
$ javac ScopedValueDemo.java (JDK 27, no flag)
|
||||
exit=0
|
||||
$ java ScopedValueDemo (JDK 27)
|
||||
java.version = 27
|
||||
CHECK ok : inside the scope: CURRENT_USER.get() == ankur
|
||||
CHECK ok : a method that was never passed the value still sees it
|
||||
CHECK ok : outside the scope: CURRENT_USER.get() throws NoSuchElementException
|
||||
@@ -0,0 +1,117 @@
|
||||
# StructuredTaskScope (JEP 505 in 25). Fifth preview in 25, sixth in 26, seventh in 27.
|
||||
|
||||
$ javac StructuredHub.java (JDK 25, no flag)
|
||||
<repo>/lanes/src/StructuredHub.java:1: error: StructuredTaskScope is a preview API and is disabled by default.
|
||||
import java.util.concurrent.StructuredTaskScope;
|
||||
^
|
||||
(use --enable-preview to enable preview APIs)
|
||||
<repo>/lanes/src/StructuredHub.java:15: error: StructuredTaskScope is a preview API and is disabled by default.
|
||||
try (var scope = StructuredTaskScope.open()) {
|
||||
^
|
||||
(use --enable-preview to enable preview APIs)
|
||||
<repo>/lanes/src/StructuredHub.java:24: error: StructuredTaskScope is a preview API and is disabled by default.
|
||||
try (var scope = StructuredTaskScope.open(StructuredTaskScope.Joiner.<String>anySuccessfulResultOrThrow())) {
|
||||
^
|
||||
(use --enable-preview to enable preview APIs)
|
||||
<repo>/lanes/src/StructuredHub.java:24: error: Joiner is a preview API and is disabled by default.
|
||||
try (var scope = StructuredTaskScope.open(StructuredTaskScope.Joiner.<String>anySuccessfulResultOrThrow())) {
|
||||
^
|
||||
(use --enable-preview to enable preview APIs)
|
||||
<repo>/lanes/src/StructuredHub.java:24: error: StructuredTaskScope is a preview API and is disabled by default.
|
||||
try (var scope = StructuredTaskScope.open(StructuredTaskScope.Joiner.<String>anySuccessfulResultOrThrow())) {
|
||||
^
|
||||
(use --enable-preview to enable preview APIs)
|
||||
5 errors
|
||||
exit=1
|
||||
$ javac --enable-preview --release 25 StructuredHub.java (JDK 25)
|
||||
exit=0
|
||||
$ java --enable-preview StructuredHub (JDK 25)
|
||||
java.version = 25.0.4.1
|
||||
CHECK ok : fan-out: both results joined: Dashboard[user=user-7, order=order-for-7]
|
||||
CHECK ok : anySuccessfulResultOrThrow(): the first result wins and the slow subtask is cancelled
|
||||
|
||||
$ javac StructuredHub.java (JDK 26, no flag)
|
||||
<repo>/lanes/src/StructuredHub.java:1: error: StructuredTaskScope is a preview API and is disabled by default.
|
||||
import java.util.concurrent.StructuredTaskScope;
|
||||
^
|
||||
(use --enable-preview to enable preview APIs)
|
||||
<repo>/lanes/src/StructuredHub.java:15: error: StructuredTaskScope is a preview API and is disabled by default.
|
||||
try (var scope = StructuredTaskScope.open()) {
|
||||
^
|
||||
(use --enable-preview to enable preview APIs)
|
||||
<repo>/lanes/src/StructuredHub.java:24: error: StructuredTaskScope is a preview API and is disabled by default.
|
||||
try (var scope = StructuredTaskScope.open(StructuredTaskScope.Joiner.<String>anySuccessfulResultOrThrow())) {
|
||||
^
|
||||
(use --enable-preview to enable preview APIs)
|
||||
<repo>/lanes/src/StructuredHub.java:24: error: Joiner is a preview API and is disabled by default.
|
||||
try (var scope = StructuredTaskScope.open(StructuredTaskScope.Joiner.<String>anySuccessfulResultOrThrow())) {
|
||||
^
|
||||
(use --enable-preview to enable preview APIs)
|
||||
<repo>/lanes/src/StructuredHub.java:24: error: cannot find symbol
|
||||
try (var scope = StructuredTaskScope.open(StructuredTaskScope.Joiner.<String>anySuccessfulResultOrThrow())) {
|
||||
^
|
||||
symbol: method <String>anySuccessfulResultOrThrow()
|
||||
location: interface Joiner
|
||||
<repo>/lanes/src/StructuredHub.java:24: error: StructuredTaskScope is a preview API and is disabled by default.
|
||||
try (var scope = StructuredTaskScope.open(StructuredTaskScope.Joiner.<String>anySuccessfulResultOrThrow())) {
|
||||
^
|
||||
(use --enable-preview to enable preview APIs)
|
||||
6 errors
|
||||
exit=1
|
||||
$ javac --enable-preview --release 26 StructuredHub.java (JDK 26)
|
||||
<repo>/lanes/src/StructuredHub.java:24: error: cannot find symbol
|
||||
try (var scope = StructuredTaskScope.open(StructuredTaskScope.Joiner.<String>anySuccessfulResultOrThrow())) {
|
||||
^
|
||||
symbol: method <String>anySuccessfulResultOrThrow()
|
||||
location: interface Joiner
|
||||
1 error
|
||||
exit=1
|
||||
|
||||
$ javac StructuredHub.java (JDK 27, no flag)
|
||||
<repo>/lanes/src/StructuredHub.java:1: error: StructuredTaskScope is a preview API and is disabled by default.
|
||||
import java.util.concurrent.StructuredTaskScope;
|
||||
^
|
||||
(use --enable-preview to enable preview APIs)
|
||||
<repo>/lanes/src/StructuredHub.java:15: error: StructuredTaskScope is a preview API and is disabled by default.
|
||||
try (var scope = StructuredTaskScope.open()) {
|
||||
^
|
||||
(use --enable-preview to enable preview APIs)
|
||||
<repo>/lanes/src/StructuredHub.java:24: error: StructuredTaskScope is a preview API and is disabled by default.
|
||||
try (var scope = StructuredTaskScope.open(StructuredTaskScope.Joiner.<String>anySuccessfulResultOrThrow())) {
|
||||
^
|
||||
(use --enable-preview to enable preview APIs)
|
||||
<repo>/lanes/src/StructuredHub.java:24: error: Joiner is a preview API and is disabled by default.
|
||||
try (var scope = StructuredTaskScope.open(StructuredTaskScope.Joiner.<String>anySuccessfulResultOrThrow())) {
|
||||
^
|
||||
(use --enable-preview to enable preview APIs)
|
||||
<repo>/lanes/src/StructuredHub.java:24: error: cannot find symbol
|
||||
try (var scope = StructuredTaskScope.open(StructuredTaskScope.Joiner.<String>anySuccessfulResultOrThrow())) {
|
||||
^
|
||||
symbol: method <String>anySuccessfulResultOrThrow()
|
||||
location: interface Joiner
|
||||
<repo>/lanes/src/StructuredHub.java:24: error: StructuredTaskScope is a preview API and is disabled by default.
|
||||
try (var scope = StructuredTaskScope.open(StructuredTaskScope.Joiner.<String>anySuccessfulResultOrThrow())) {
|
||||
^
|
||||
(use --enable-preview to enable preview APIs)
|
||||
6 errors
|
||||
exit=1
|
||||
$ javac --enable-preview --release 27 StructuredHub.java (JDK 27)
|
||||
<repo>/lanes/src/StructuredHub.java:24: error: cannot find symbol
|
||||
try (var scope = StructuredTaskScope.open(StructuredTaskScope.Joiner.<String>anySuccessfulResultOrThrow())) {
|
||||
^
|
||||
symbol: method <String>anySuccessfulResultOrThrow()
|
||||
location: interface Joiner
|
||||
1 error
|
||||
exit=1
|
||||
|
||||
$ javac --enable-preview --release 26 StructuredHubNew.java (JDK 26)
|
||||
exit=0
|
||||
$ java --enable-preview StructuredHubNew (JDK 26)
|
||||
java.version = 26.0.2.1
|
||||
CHECK ok : anySuccessfulOrThrow(): the first result wins
|
||||
|
||||
$ javac --enable-preview --release 27 StructuredHubNew.java (JDK 27)
|
||||
exit=0
|
||||
$ java --enable-preview StructuredHubNew (JDK 27)
|
||||
java.version = 27
|
||||
CHECK ok : anySuccessfulOrThrow(): the first result wins
|
||||
@@ -0,0 +1,29 @@
|
||||
# Is finalization removed by default in 25? (JEP 421 deprecated it for removal in 18)
|
||||
|
||||
$ java FinalizerDefault (JDK 21)
|
||||
java.version = 21.0.12.1
|
||||
finalizer ran: true
|
||||
$ java --finalization=disabled FinalizerDefault (JDK 21)
|
||||
java.version = 21.0.12.1
|
||||
finalizer ran: false
|
||||
|
||||
$ java FinalizerDefault (JDK 25)
|
||||
java.version = 25.0.4.1
|
||||
finalizer ran: true
|
||||
$ java --finalization=disabled FinalizerDefault (JDK 25)
|
||||
java.version = 25.0.4.1
|
||||
finalizer ran: false
|
||||
|
||||
$ java FinalizerDefault (JDK 26)
|
||||
java.version = 26.0.2.1
|
||||
finalizer ran: true
|
||||
$ java --finalization=disabled FinalizerDefault (JDK 26)
|
||||
java.version = 26.0.2.1
|
||||
finalizer ran: false
|
||||
|
||||
$ java FinalizerDefault (JDK 27)
|
||||
java.version = 27
|
||||
finalizer ran: true
|
||||
$ java --finalization=disabled FinalizerDefault (JDK 27)
|
||||
java.version = 27
|
||||
finalizer ran: false
|
||||
@@ -0,0 +1,9 @@
|
||||
# System.setSecurityManager(new SecurityManager())
|
||||
|
||||
$ java SecurityManagerGone (JDK 21)
|
||||
java.version = 21.0.12.1
|
||||
setSecurityManager: UnsupportedOperationException: The Security Manager is deprecated and will be removed in a future release
|
||||
|
||||
$ java SecurityManagerGone (JDK 25)
|
||||
java.version = 25.0.4.1
|
||||
setSecurityManager: UnsupportedOperationException: Setting a Security Manager is not supported
|
||||
@@ -0,0 +1,68 @@
|
||||
# Thread.stop(), suspend(), resume(): when did they actually go?
|
||||
|
||||
$ java ThreadStopRuntime (JDK 21)
|
||||
java.version = 21.0.12.1
|
||||
Thread.stop(): UnsupportedOperationException
|
||||
|
||||
$ java ThreadStopRuntime (JDK 25)
|
||||
java.version = 25.0.4.1
|
||||
Thread.stop(): UnsupportedOperationException
|
||||
|
||||
$ javac ThreadSuspendGone.java (JDK 21)
|
||||
exit=0
|
||||
|
||||
$ javac ThreadSuspendGone.java (JDK 25)
|
||||
<repo>/lanes/src/ThreadSuspendGone.java:8: error: cannot find symbol
|
||||
t.suspend();
|
||||
^
|
||||
symbol: method suspend()
|
||||
location: variable t of type Thread
|
||||
<repo>/lanes/src/ThreadSuspendGone.java:9: error: cannot find symbol
|
||||
t.resume();
|
||||
^
|
||||
symbol: method resume()
|
||||
location: variable t of type Thread
|
||||
2 errors
|
||||
exit=1
|
||||
|
||||
$ javac ThreadSuspendGone.java (JDK 26)
|
||||
<repo>/lanes/src/ThreadSuspendGone.java:8: error: cannot find symbol
|
||||
t.suspend();
|
||||
^
|
||||
symbol: method suspend()
|
||||
location: variable t of type Thread
|
||||
<repo>/lanes/src/ThreadSuspendGone.java:9: error: cannot find symbol
|
||||
t.resume();
|
||||
^
|
||||
symbol: method resume()
|
||||
location: variable t of type Thread
|
||||
2 errors
|
||||
exit=1
|
||||
|
||||
$ javac ThreadSuspendGone.java (JDK 23, Corretto image)
|
||||
/src/ThreadSuspendGone.java:8: error: cannot find symbol
|
||||
t.suspend();
|
||||
^
|
||||
symbol: method suspend()
|
||||
location: variable t of type Thread
|
||||
/src/ThreadSuspendGone.java:9: error: cannot find symbol
|
||||
t.resume();
|
||||
^
|
||||
symbol: method resume()
|
||||
location: variable t of type Thread
|
||||
2 errors
|
||||
exit=1
|
||||
|
||||
$ javac ThreadSuspendGone.java (JDK 24, Corretto image)
|
||||
/src/ThreadSuspendGone.java:8: error: cannot find symbol
|
||||
t.suspend();
|
||||
^
|
||||
symbol: method suspend()
|
||||
location: variable t of type Thread
|
||||
/src/ThreadSuspendGone.java:9: error: cannot find symbol
|
||||
t.resume();
|
||||
^
|
||||
symbol: method resume()
|
||||
location: variable t of type Thread
|
||||
2 errors
|
||||
exit=1
|
||||
@@ -0,0 +1,49 @@
|
||||
# sun.misc.Unsafe memory access (JEP 498) and JNI (JEP 472): what does the JVM say?
|
||||
|
||||
$ java UnsafeWarning (JDK 21)
|
||||
java.version = 21.0.12.1
|
||||
read back: 42
|
||||
|
||||
$ java UnsafeWarning (JDK 25)
|
||||
java.version = 25.0.4.1
|
||||
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
|
||||
WARNING: sun.misc.Unsafe::allocateMemory has been called by UnsafeWarning (file:<repo>/build/lanes/us25/)
|
||||
WARNING: Please consider reporting this to the maintainers of class UnsafeWarning
|
||||
WARNING: sun.misc.Unsafe::allocateMemory will be removed in a future release
|
||||
read back: 42
|
||||
|
||||
$ java UnsafeWarning (JDK 24, Corretto image)
|
||||
java.version = 24.0.2
|
||||
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
|
||||
WARNING: sun.misc.Unsafe::allocateMemory has been called by UnsafeWarning (file:/b/us21/)
|
||||
WARNING: Please consider reporting this to the maintainers of class UnsafeWarning
|
||||
WARNING: sun.misc.Unsafe::allocateMemory will be removed in a future release
|
||||
read back: 42
|
||||
|
||||
$ java JniWarning (JDK 21)
|
||||
java.version = 21.0.12.1
|
||||
System.loadLibrary("net") returned
|
||||
$ java --enable-native-access=ALL-UNNAMED JniWarning (JDK 21)
|
||||
java.version = 21.0.12.1
|
||||
System.loadLibrary("net") returned
|
||||
|
||||
$ java JniWarning (JDK 25)
|
||||
java.version = 25.0.4.1
|
||||
WARNING: A restricted method in java.lang.System has been called
|
||||
WARNING: java.lang.System::loadLibrary has been called by JniWarning in an unnamed module (file:<repo>/build/lanes/jni25/)
|
||||
WARNING: Use --enable-native-access=ALL-UNNAMED to avoid a warning for callers in this module
|
||||
WARNING: Restricted methods will be blocked in a future release unless native access is enabled
|
||||
|
||||
System.loadLibrary("net") returned
|
||||
$ java --enable-native-access=ALL-UNNAMED JniWarning (JDK 25)
|
||||
java.version = 25.0.4.1
|
||||
System.loadLibrary("net") returned
|
||||
|
||||
$ java JniWarning (JDK 24, Corretto image)
|
||||
java.version = 24.0.2
|
||||
System.loadLibrary("net") returned
|
||||
WARNING: A restricted method in java.lang.System has been called
|
||||
WARNING: java.lang.System::loadLibrary has been called by JniWarning in an unnamed module (file:/b/jni21/)
|
||||
WARNING: Use --enable-native-access=ALL-UNNAMED to avoid a warning for callers in this module
|
||||
WARNING: Restricted methods will be blocked in a future release unless native access is enabled
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# 4 virtual threads on ONE carrier, each sleeping 200 ms inside synchronized (JEP 491, Java 24)
|
||||
|
||||
$ java -Djdk.virtualThreadScheduler.parallelism=1 -Djdk.virtualThreadScheduler.maxPoolSize=1 PinningDemo (JDK 21)
|
||||
java.version = 21.0.12.1
|
||||
4 virtual threads, 1 carrier, sleep(200) inside synchronized: SERIALISED (pinned): about 4 x 200 ms
|
||||
|
||||
$ java -Djdk.virtualThreadScheduler.parallelism=1 -Djdk.virtualThreadScheduler.maxPoolSize=1 PinningDemo (JDK 25)
|
||||
java.version = 25.0.4.1
|
||||
4 virtual threads, 1 carrier, sleep(200) inside synchronized: OVERLAPPED (not pinned): about 200 ms
|
||||
|
||||
$ java -Djdk.virtualThreadScheduler.parallelism=1 -Djdk.virtualThreadScheduler.maxPoolSize=1 PinningDemo (JDK 26)
|
||||
java.version = 26.0.2.1
|
||||
4 virtual threads, 1 carrier, sleep(200) inside synchronized: OVERLAPPED (not pinned): about 200 ms
|
||||
|
||||
$ java -Djdk.virtualThreadScheduler.parallelism=1 -Djdk.virtualThreadScheduler.maxPoolSize=1 PinningDemo (JDK 27)
|
||||
java.version = 27
|
||||
4 virtual threads, 1 carrier, sleep(200) inside synchronized: OVERLAPPED (not pinned): about 200 ms
|
||||
|
||||
$ java -Djdk.virtualThreadScheduler.parallelism=1 -Djdk.virtualThreadScheduler.maxPoolSize=1 PinningDemo (JDK 23, Corretto image)
|
||||
java.version = 23.0.2
|
||||
4 virtual threads, 1 carrier, sleep(200) inside synchronized: SERIALISED (pinned): about 4 x 200 ms
|
||||
|
||||
$ java -Djdk.virtualThreadScheduler.parallelism=1 -Djdk.virtualThreadScheduler.maxPoolSize=1 PinningDemo (JDK 24, Corretto image)
|
||||
java.version = 24.0.2
|
||||
4 virtual threads, 1 carrier, sleep(200) inside synchronized: OVERLAPPED (not pinned): about 200 ms
|
||||
@@ -0,0 +1,26 @@
|
||||
# -XX:+UseZGC -XX:-ZGenerational -Xlog:gc+init -version : generational ZGC is the only ZGC from Java 24 (JEP 490)
|
||||
|
||||
$ java -XX:+UseZGC -XX:-ZGenerational -Xlog:gc+init -version (JDK 21)
|
||||
[0.004s][info][gc,init] Version: 21.0.12.1+9-LTS (release)
|
||||
[0.004s][info][gc,init] Using legacy single-generation mode
|
||||
|
||||
$ java -XX:+UseZGC -XX:-ZGenerational -Xlog:gc+init -version (JDK 25)
|
||||
OpenJDK 64-Bit Server VM warning: Ignoring option ZGenerational; support was removed in 24.0
|
||||
[0.004s][info][gc,init] Version: 25.0.4.1+1-LTS (release)
|
||||
|
||||
$ java -XX:+UseZGC -XX:-ZGenerational -Xlog:gc+init -version (JDK 26)
|
||||
Unrecognized VM option 'ZGenerational'
|
||||
Error: Could not create the Java Virtual Machine.
|
||||
|
||||
$ java -XX:+UseZGC -XX:-ZGenerational -Xlog:gc+init -version (JDK 27)
|
||||
Unrecognized VM option 'ZGenerational'
|
||||
Error: Could not create the Java Virtual Machine.
|
||||
|
||||
$ java -XX:+UseZGC -XX:-ZGenerational -Xlog:gc+init -version (JDK 23, Corretto image)
|
||||
OpenJDK 64-Bit Server VM warning: Option ZGenerational was deprecated in version 23.0 and will likely be removed in a future release.
|
||||
[0.004s][info][gc,init] Version: 23.0.2+7-FR (release)
|
||||
[0.004s][info][gc,init] Using deprecated non-generational mode
|
||||
|
||||
$ java -XX:+UseZGC -XX:-ZGenerational -Xlog:gc+init -version (JDK 24, Corretto image)
|
||||
OpenJDK 64-Bit Server VM warning: Ignoring option ZGenerational; support was removed in 24.0
|
||||
[0.005s][info][gc,init] Version: 24.0.2+12-FR (release)
|
||||
@@ -0,0 +1,24 @@
|
||||
# javap --module java.base -public 'java.util.concurrent.StructuredTaskScope$Joiner', static factories only
|
||||
|
||||
== JDK 25
|
||||
public static <T> StructuredTaskScope$Joiner<T, Stream<StructuredTaskScope$Subtask<T>>> allSuccessfulOrThrow();
|
||||
public static <T> StructuredTaskScope$Joiner<T, T> anySuccessfulResultOrThrow();
|
||||
public static <T> StructuredTaskScope$Joiner<T, Void> awaitAllSuccessfulOrThrow();
|
||||
public static <T> StructuredTaskScope$Joiner<T, Void> awaitAll();
|
||||
public static <T> StructuredTaskScope$Joiner<T, Stream<StructuredTaskScope$Subtask<T>>> allUntil(Predicate<StructuredTaskScope$Subtask<? extends T>>);
|
||||
|
||||
== JDK 26
|
||||
public static <T> StructuredTaskScope$Joiner<T, List<T>> allSuccessfulOrThrow();
|
||||
public static <T> StructuredTaskScope$Joiner<T, T> anySuccessfulOrThrow();
|
||||
public static <T> StructuredTaskScope$Joiner<T, Void> awaitAllSuccessfulOrThrow();
|
||||
public static <T> StructuredTaskScope$Joiner<T, Void> awaitAll();
|
||||
public static <T> StructuredTaskScope$Joiner<T, List<StructuredTaskScope$Subtask<T>>> allUntil(Predicate<StructuredTaskScope$Subtask<T>>);
|
||||
|
||||
== JDK 27
|
||||
public static <T, R_X extends Throwable> StructuredTaskScope$Joiner<T, List<T>, R_X> allSuccessfulOrThrow(Function<Throwable, R_X>);
|
||||
public static <T> StructuredTaskScope$Joiner<T, List<T>, ExecutionException> allSuccessfulOrThrow();
|
||||
public static <T, R_X extends Throwable> StructuredTaskScope$Joiner<T, T, R_X> anySuccessfulOrThrow(Function<Throwable, R_X>);
|
||||
public static <T> StructuredTaskScope$Joiner<T, T, ExecutionException> anySuccessfulOrThrow();
|
||||
public static <T, R_X extends Throwable> StructuredTaskScope$Joiner<T, Void, R_X> awaitAllSuccessfulOrThrow(Function<Throwable, R_X>);
|
||||
public static <T> StructuredTaskScope$Joiner<T, Void, ExecutionException> awaitAllSuccessfulOrThrow();
|
||||
public static <T> StructuredTaskScope$Joiner<T, List<StructuredTaskScope$Subtask<T>>, RuntimeException> allUntil(Predicate<? super StructuredTaskScope$Subtask<T>>);
|
||||
@@ -0,0 +1,26 @@
|
||||
# _ (unnamed variables and patterns) and compact source files with instance main()
|
||||
|
||||
$ javac UnnamedVariables.java (JDK 21, no flag)
|
||||
<repo>/lanes/src/UnnamedVariables.java:12: error: unnamed variables are a preview feature and are disabled by default.
|
||||
if (o instanceof Point(int x, _)) {
|
||||
^
|
||||
(use --enable-preview to enable unnamed variables)
|
||||
1 error
|
||||
exit=1
|
||||
|
||||
$ javac UnnamedVariables.java (JDK 25, no flag)
|
||||
exit=0
|
||||
$ java UnnamedVariables (JDK 25)
|
||||
matched a Point, x = 3, y ignored with _
|
||||
caught NumberFormatException without naming it
|
||||
|
||||
$ java CompactHello.java (JDK 21, no flag)
|
||||
<repo>/lanes/src/CompactHello.java:1: error: unnamed classes are a preview feature and are disabled by default.
|
||||
void main() {
|
||||
^
|
||||
(use --enable-preview to enable unnamed classes)
|
||||
1 error
|
||||
error: compilation failed
|
||||
|
||||
$ java CompactHello.java (JDK 25, no flag)
|
||||
compact source file: no class, no static, no String[] args
|
||||
@@ -0,0 +1,11 @@
|
||||
# Reflection writing to a final field on JDK 27: same behaviour as 26 (compare 70-final-field-mutation.txt)
|
||||
|
||||
=== JDK 27, defaults
|
||||
WARNING: Final field port in class FinalFieldMutation$Config has been mutated reflectively by class FinalFieldMutation in unnamed module @<hash> (file:<repo>/build/lanes/ffm27/)
|
||||
WARNING: Use --enable-final-field-mutation=ALL-UNNAMED to avoid a warning
|
||||
WARNING: Mutating final fields will be blocked in a future release unless final field mutation is enabled
|
||||
field reads : 9090
|
||||
port() returns : 8080
|
||||
|
||||
=== JDK 27, --illegal-final-field-mutation=deny
|
||||
setInt refused : class FinalFieldMutation (in unnamed module @<hash>) cannot set final field FinalFieldMutation$Config.port (in unnamed module @<hash>), unnamed module @<hash> is not allowed to mutate final fields
|
||||
@@ -0,0 +1,40 @@
|
||||
# pom.xml sets maven.compiler.source/target/release to 25 (lanes/upgrade/pom.xml)
|
||||
|
||||
$ mvn package (build JDK 21)
|
||||
[INFO] --- resources:3.3.1:resources (default-resources) @ upgrade-demo ---
|
||||
[INFO] --- compiler:3.13.0:compile (default-compile) @ upgrade-demo ---
|
||||
[INFO] Compiling 1 source file with javac [debug release 25] to target/classes
|
||||
[INFO] BUILD FAILURE
|
||||
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.13.0:compile (default-compile) on project upgrade-demo: Fatal error compiling: error: release version 25 not supported -> [Help 1]
|
||||
|
||||
$ mvn package (build JDK 25)
|
||||
[INFO] --- resources:3.3.1:resources (default-resources) @ upgrade-demo ---
|
||||
[INFO] --- compiler:3.13.0:compile (default-compile) @ upgrade-demo ---
|
||||
[INFO] Compiling 1 source file with javac [debug release 25] to target/classes
|
||||
[INFO] --- resources:3.3.1:testResources (default-testResources) @ upgrade-demo ---
|
||||
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ upgrade-demo ---
|
||||
[INFO] --- surefire:3.2.5:test (default-test) @ upgrade-demo ---
|
||||
[INFO] --- jar:3.4.1:jar (default-jar) @ upgrade-demo ---
|
||||
[INFO] Building jar: <repo>/build/upgrade/mvn25/target/upgrade-demo-1.0.jar
|
||||
[INFO] BUILD SUCCESS
|
||||
|
||||
$ mvn package (build JDK 27, still release 25)
|
||||
[INFO] --- resources:3.3.1:resources (default-resources) @ upgrade-demo ---
|
||||
[INFO] --- compiler:3.13.0:compile (default-compile) @ upgrade-demo ---
|
||||
[INFO] Compiling 1 source file with javac [debug release 25] to target/classes
|
||||
[INFO] --- resources:3.3.1:testResources (default-testResources) @ upgrade-demo ---
|
||||
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ upgrade-demo ---
|
||||
[INFO] --- surefire:3.2.5:test (default-test) @ upgrade-demo ---
|
||||
[INFO] --- jar:3.4.1:jar (default-jar) @ upgrade-demo ---
|
||||
[INFO] Building jar: <repo>/build/upgrade/mvn27/target/upgrade-demo-1.0.jar
|
||||
[INFO] BUILD SUCCESS
|
||||
|
||||
$ javap -v -cp target/classes demo.App | grep 'major version'
|
||||
major version: 69
|
||||
|
||||
$ java -cp target/classes demo.App (JDK 25)
|
||||
running on Java 25
|
||||
|
||||
$ java -cp target/classes demo.App (JDK 21: the class file is newer than the JVM)
|
||||
Error: LinkageError occurred while loading main class demo.App
|
||||
java.lang.UnsupportedClassVersionError: demo/App has been compiled by a more recent version of the Java Runtime (class file version 69.0), this version of the Java Runtime only recognizes class file versions up to 65.0
|
||||
@@ -0,0 +1,12 @@
|
||||
# build.gradle.kts asks for a Java 25 toolchain (lanes/upgrade/build.gradle.kts). Two questions: which JDK compiles, and which JDK runs Gradle itself?
|
||||
|
||||
$ gradle run (Gradle 8.14.3 running on JDK 21, toolchain finds JDK 25)
|
||||
running on Java 25
|
||||
|
||||
$ gradle run (Gradle 8.14.3 running on JDK 25)
|
||||
FAILURE: Build failed with an exception.
|
||||
* What went wrong:
|
||||
25.0.4.1
|
||||
|
||||
$ gradle run (Gradle 9.1.0 running on JDK 25)
|
||||
running on Java 25
|
||||
@@ -0,0 +1,24 @@
|
||||
# ReleaseFlag.java calls String.equalsFoldCase, which is new in Java 26. The compiler is JDK 27's javac both times.
|
||||
|
||||
$ javac --release 25 ReleaseFlag.java
|
||||
<repo>/lanes/src/ReleaseFlag.java:8: error: cannot find symbol
|
||||
System.out.println("ABC".equalsFoldCase("abc"));
|
||||
^
|
||||
symbol: method equalsFoldCase(String)
|
||||
location: class String
|
||||
1 error
|
||||
exit=1
|
||||
|
||||
$ javac -source 25 -target 25 ReleaseFlag.java
|
||||
warning: [options] location of system modules is not set in conjunction with -source 25
|
||||
not setting the location of system modules may lead to class files that cannot run on JDK 25
|
||||
--release 25 is recommended instead of -source 25 -target 25 because it sets the location of system modules automatically
|
||||
1 warning
|
||||
exit=0
|
||||
|
||||
$ java -cp rf-b ReleaseFlag (JDK 25)
|
||||
Exception in thread "main" java.lang.NoSuchMethodError: 'boolean java.lang.String.equalsFoldCase(java.lang.String)'
|
||||
at ReleaseFlag.main(ReleaseFlag.java:8)
|
||||
|
||||
$ java -cp rf-b ReleaseFlag (JDK 27)
|
||||
true
|
||||
@@ -0,0 +1,19 @@
|
||||
# javac LombokProbe.java with -processorpath lombok-<version>.jar, then java LombokProbe. Class: @Getter on one field.
|
||||
Lombok 1.18.34 on JDK 25: javac failed: java.lang.ExceptionInInitializerError
|
||||
Lombok 1.18.34 on JDK 26: javac failed: java.lang.ExceptionInInitializerError
|
||||
Lombok 1.18.34 on JDK 27: javac failed: java.lang.ExceptionInInitializerError
|
||||
Lombok 1.18.40 on JDK 25: compiled; getName() = ankur
|
||||
Lombok 1.18.40 on JDK 26: compiled; getName() = ankur
|
||||
Lombok 1.18.40 on JDK 27: javac failed: java.lang.ExceptionInInitializerError
|
||||
Lombok 1.18.46 on JDK 25: compiled; getName() = ankur
|
||||
Lombok 1.18.46 on JDK 26: compiled; getName() = ankur
|
||||
Lombok 1.18.46 on JDK 27: javac failed: java.lang.ExceptionInInitializerError
|
||||
Lombok 1.18.48 on JDK 25: compiled; getName() = ankur
|
||||
Lombok 1.18.48 on JDK 26: compiled; getName() = ankur
|
||||
Lombok 1.18.48 on JDK 27: compiled; getName() = ankur
|
||||
|
||||
# The same source with the jar on the class path only (no -processorpath), the way a hand-run javac used to find it:
|
||||
JDK 21, Lombok 1.18.48 on the class path only: exit=0 Note: Annotation processing is enabled because one or more processors were found
|
||||
JDK 25, Lombok 1.18.48 on the class path only: exit=1 <repo>/lanes/src/LombokProbe.java:11: error: cannot find symbol
|
||||
JDK 23, Lombok 1.18.48 on the class path only: exit=1 <repo>/lanes/src/LombokProbe.java:11: error: cannot find symbol
|
||||
JDK 24, Lombok 1.18.48 on the class path only: exit=1 <repo>/lanes/src/LombokProbe.java:11: error: cannot find symbol
|
||||
@@ -0,0 +1,15 @@
|
||||
# jdeps --jdk-internals on the class from lanes/src/UnsafeWarning.java (JDK 25's jdeps)
|
||||
|
||||
$ jdeps --jdk-internals --multi-release 25 UnsafeWarning.class
|
||||
UnsafeWarning.class -> jdk.unsupported
|
||||
UnsafeWarning -> sun.misc.Unsafe JDK internal API (jdk.unsupported)
|
||||
|
||||
Warning: JDK internal APIs are unsupported and private to JDK implementation that are
|
||||
subject to be removed or changed incompatibly and could break your application.
|
||||
Please modify your code to eliminate dependence on any JDK internal APIs.
|
||||
For the most recent update on JDK internal API replacements, please check:
|
||||
https://wiki.openjdk.org/display/JDK8/Java+Dependency+Analysis+Tool
|
||||
|
||||
JDK Internal API Suggested Replacement
|
||||
---------------- ---------------------
|
||||
sun.misc.Unsafe See https://openjdk.org/jeps/260
|
||||
@@ -0,0 +1,17 @@
|
||||
# lanes/src/MockitoProbe.java: mock an interface, stub one call. Four Mockito versions, each with the ByteBuddy it declares.
|
||||
Mockito 5.12.0 (ByteBuddy 1.14.15) on JDK 21: works: mock says hi
|
||||
Mockito 5.12.0 (ByteBuddy 1.14.15) on JDK 25: FAILS: Mockito cannot mock this class: interface MockitoProbe$Greeter.
|
||||
Mockito 5.12.0 (ByteBuddy 1.14.15) on JDK 27: FAILS: Mockito cannot mock this class: interface MockitoProbe$Greeter.
|
||||
Mockito 5.17.0 (ByteBuddy 1.15.11) on JDK 21: works: mock says hi
|
||||
Mockito 5.17.0 (ByteBuddy 1.15.11) on JDK 25: FAILS: Mockito cannot mock this class: interface MockitoProbe$Greeter.
|
||||
Mockito 5.17.0 (ByteBuddy 1.15.11) on JDK 27: FAILS: Mockito cannot mock this class: interface MockitoProbe$Greeter.
|
||||
Mockito 5.18.0 (ByteBuddy 1.17.5 ) on JDK 21: works: mock says hi
|
||||
Mockito 5.18.0 (ByteBuddy 1.17.5 ) on JDK 25: works: mock says hi
|
||||
Mockito 5.18.0 (ByteBuddy 1.17.5 ) on JDK 27: works: mock says hi
|
||||
Mockito 5.23.0 (ByteBuddy 1.17.7 ) on JDK 21: works: mock says hi
|
||||
Mockito 5.23.0 (ByteBuddy 1.17.7 ) on JDK 25: works: mock says hi
|
||||
Mockito 5.23.0 (ByteBuddy 1.17.7 ) on JDK 27: works: mock says hi
|
||||
|
||||
# Notices on stderr from the working Mockito 5.23.0 on JDK 25
|
||||
Mockito is currently self-attaching to enable the inline-mock-maker. This will no longer work in future releases of the JDK. Please add Mockito as an agent to your build as described in Mockito's documentation: https://javadoc.io/doc/org.mockito/mockito-core/latest/org.mockito/org/mockito/Mockito.html#0.3
|
||||
WARNING: A Java agent has been loaded dynamically (<repo>/build/upgrade/mockito/5.23.0/lib/byte-buddy-agent-1.17.7.jar)
|
||||
Reference in New Issue
Block a user