Feature Freeze for JDK 20 – what will the new edition bring? – JVM Weekly 116

As we’ve been covering the big announcements for a couple of editions, we’ve stacked up a series of interesting releases that we didn’t get a chance to tell you about: Gradle, Wildfly, Resillience4j, Async-Profiler and Spring. The main course, however, remains Feature Freeze for the new JDK 20.

Article cover

1. Feature Freeze for JDK 20 – what will the new edition bring?

When the previous Java consisted mainly of Preview, there was something fascinating about it. After all, it was JDK 19 that gave us a glimpse into the future of how the platform would evolve in the coming years and a taste of the results of some long-awaited projects. I have to admit, however, that it’s hard for me to summon up similar enthusiasm for JDK 20. Once again, we’re dealing with the Preview set, but these are rather minor iterations (with exceptions about which in a moment) of already existing APIs. And with today, the new Java enters the Rampdown phase – it means that the list of features has been frozen and no further ones can be expected.

So the final list of new features in JDK 20 is as follows:

As you can see, completely new things are in short supply. Yeah, the mere fact that the APIs in the preview version are undergoing changes is something positive. For example, additions in the Foreign Function & Memory API are pretty nice – you can read about them, for example, at Per Minborg blog, where he published the text Java 20: A Sneak Peek on the Panama FFM API (Second Preview). And if you’re curious about the changes to new record proposals and pattern matching, I’ve already wrote about Record Patterns (Second Preview) and Pattern Matching for switch (Fourth Preview) in a previous edition of this newsletter. I also had the opportunity to cover Loom-related JEPs – Virtual Threads (Second Preview) and Structured Concurrency (Second Incubator).

Since then, 437: Structured Concurrency (Second Incubator) has lived to support the only change that can be considered a really interesting addition introduced in JDK 20 – support for Scope Values. And these are the ones we will deal with now.

About Scope Locals

The need for local values is due to the changes made to the JVM for Loom. Due to the fact that Loom is based on very lightweight – virtual – threads, and it becomes possible to create an essentially unlimited number of them, we have to be very careful about the size of the structures created for each thread (a very cool article on this topic can be found here).

The popular Thread Locals (variables pinned to a thread) have been a stone in the shoe of virtual thread developers from the beginning. The solution they come up with are mentioned Scope Values – effectively final, non-mutable local variables that can be safely shared between threads as needed, reducing the amount of memory required. Each child thread has access to the full context of its parent. The idea of accomplishing this task was stolen from Common Lisp and its “special variables.”


You can think of Scope Values as invisible parameters that are passed to each method. They have the ability to assign a value to a local variable only for the purpose of a specific scope – when the scope ends, the values of the variables originally set in it will be automatically restored. This behavior allows, for example, to shadow the values of x and y, in any of the “children”, without affecting all other threads using them.

The source code from JEP illustrates this quite well:

final static ScopedValue<...> x = new ScopedValue<>();
final static ScopedValue<...> y = new ScopedValue<>();

    ScopedValue.where(x, expr1)
        .where(y, expr2)
        .run(() -> ... code that uses x.get() and y.get() ...);

As you can see, the syntax is a bit like the all-too-familiar “atomics” on steroids. The values x and y can be passed from the “parent” thread to the “child” thread. The run() method, on the other hand, “binds” x and y to the values of expr1 and expr2. During the execution of the run() method, any calls to x.get() and y.get() return them. When it is exited, the values revert to the previous versions inherited from the parent.

Of course, as it happens with Loom, the syntax can still change many times (especially since we are dealing with nothing but incubation). I also make no secret of the fact that my fondness for this JEP certainly comes from the fact that subconsciously I’m a bit of a crypto-clojurist, so any reference to Lisp in the JDK is welcomed with open arms.

In general, it seems to me that the key word to describe the new Java release is “stability”. Which may be a better direction – I’d rather get a small amount of stable, large features in the next LTS than a large amount of trivia. I’m certainly glad that with the addition of Scope Values, virtual threads are becoming more complete and useful.

And as if you were wondering what JEP 435 – a hole in the list of targeted JEPs – we’re talking about JEP 435: Asynchronous Stack Trace VM API, which simply didn’t make it into the new release. You can read more about it in a Weekly’s previous edition.
Discover more IT content selected for you
In Vived, you will find articles handpicked by devs. Download the app and read the good stuff!

phone newsletter image

2. Release Radar – Gradle, Wildfly, Resillience4j, Async-Profiler and Spring

It’s been a long time since the last Release Radar, so today we’re going to devote a lot of space to the launches of recent weeks – and there have been some.

Resilience4j 2.0

There was a time when there was only one king of the so-called “Fault Tolerance” within the JVM – this world was indivisibly ruled by Hystrix from Netflix. At some point, however, the company abandoned the project and it evolved into Resilience4j as a result of community efforts. Resilience4j has been rather quiet lately, but I figured it was worth reminding people about it, especially since a good opportunity arose – the project’s version 2.0 was released. What happened that made it deserve a major version bump?

In addition to support for Java 17, Spring Boot 2.7 (too bad it’s not 3.0 right away) and Kotlin 1.7.20, the new Resilience4J is some significant change under the hood – the project got rid of dependencies on the Vavr library. For those who are not familiar with Vavr, it is a collection of functional “utils”, somewhat reminiscent of Guava and Kotlin’s own Arrow, and at one time quite a popular library. The project itself has a rather tumultuous history, having once called itself Javaslang, but Oracle accused the developers of violating their trademark on the word Java, which forced a rebranding.

This is another example of how not only Jakarta EE has been historically hit in this way

The developers of Resilience4j decided to get rid of Vavr from the project because it was an additional transitive dependency for all projects using Resilience4j. More context can be found in the Github discussion.

If you want to learn more about the solutions for Fault Tolerance and what alternatives to Resilience4j are available in Java I invite you to read A tentative comparison of fault tolerance libraries on the JVM – a very good overview from Nicolas Fränkel.

Gradle 7.6

Another release I’d like to tell you about today is the new Gradle. The popular Build Tool spits out releases fairly regularly, but just about every one of them brings something interesting. It’s no different with the latest edition 7.6.

This is the first edition that allows us to compile to Java 19, so if you haven’t been able to (very responsibly) port your production projects to the new Preview API from the current JDK, Gradle is finally no longer an obstacle for you. Besides, Gradle will download the JDK on its own thanks to the Java Toolchain. The tool introduced a couple of editions ago enabled the ability to define the specific source from which you want to download the JDK. Therefore, users of DragonFly JDK or Liberica JDK will no longer be doomed to Adoptium. And that there are many JDK variants. as can be seen at whichjdk.com, which describes the differences between them.

Fans of strong typing and Kotlin DSL, meanwhile, received much better code completion. What’s more, incremental compilation in error situations has been improved, and in addition, the “rerun” of a single shuffle has also been made possible. And the last big thing is the ability to connect to the Gradle debugger not only from the local machine but also over the network, which can be useful, for example, in CI/CD environments.

WildFly 27

Moving on, this time I have something for Jakarta EE users. “The cool people” application server – WildFly.

WildFly – Modern application server

You may laugh at the above sentence as long as you want, but it is WildFly, of all the tools with any ties to the old Java EE world, that is certainly the one most experimenting with modern technologies. Let it serve as an example that the new release is compatible with the fresh Jakarta EE 10 – and that includes the freshly added Core Profile, a competitor to MicroProfile. That alone would herald an interesting release, but WildFly 27 brings quite a bit more.

For one thing, it’s another of the technologies integrating heavily with Micrometer, though for now only as a Tech Preview. WildFly is also investing heavily in cloud support and being cloud-native in general. This is evidenced not only by the continued active development of “blessed” Docker images, but also by the new architecture for WildFly S2I. Under this insanely enigmatic acronym is WildFly Source-to-Image, a tool for deploying applications to application servers in the cloud. S2I serves as a method for building reproducible Docker images directly from source code. In the new release of WildFly, the architecture of the entire tool has been changed. There are a lot of changes, so if you use S2I, I recommend checking out the announcement dedicated to the tool.

Async-Profiler 2.9

Recently I wrote about the Async-Profiler tool in the context of JEP 435: Asynchronous Stack Trace VM API, which aimed to standardize the API for Stack Trace VM. Today I came to revisit the topic because the best JVM profiler got a new version, and with it one very big change: Heap Leak Profiler.

Behind this inconspicuous name lies a powerful tool, capable of detecting memory leaks in real-time. Importantly, the whole thing is designed to have minimal overhead on the process being run, being based on data sampling, which significantly reduces resource consumption. This makes async-profiler suitable for detecting memory leaks in a production environment.

Jeżeli jesteście ciekawi detali, całość została dobrze opracowana przez Krzysztofa Ślusarskiego w jego tekście Finding heap memory leaks with Async-profiler. Tam też znajdziecie konkretne przypadki użycia.

Spring Batch 5.0

There has already been a lot about Spring in our summaries recently, but since then there have been two pretty big releases.

The first of these is Spring Batch version 5.0, which boasts quite an impressive number of changes. Spring Batch provides features needed for processing large volumes of records, such as logging, transaction management, restarting and skipping jobs, as well as resource management.

Of course, in 5.0 we’re dealing with an alignment to the current versions of the Spring Framework, so as a freebie there is, for example, support for Jakarta EE 9 and GraalVM. The latter, due to Spring Batch’s runtime characteristics (running on multiple but short-lived threads), brings up to ten times speedup of batch processing in some workload, at least according to posted benchmarks. You can see the full list of changes (and as I mentioned – there are some) in the official announcement.

Spring Integration 6.0

And finally, Spring Integration 6.0. Spring Integration is a framework for building wide-ranging “integrations,” (thank you captain) mostly used by so-call “enterprises”.

If you are familiar with the book Enterprise Integration Patterns – this is its “applied” version.

In addition to the improvements that are standard for recent Spring announcements, the new Spring Integration brings first and foremost support for GraphQL, which is based on the spring-graphql project. In addition to this, Kotlin fans will be happy to know that project finally supports Coroutines. Bigger or smaller changes or migrations have also touched the integration with most providers, such as Apache Camel (new integration), Hazelcast, MQTT or RabbitMQ.

Discover more IT content selected for you
In Vived, you will find articles handpicked by devs. Download the app and read the good stuff!

phone newsletter image

3. Log4Shell – We Remember 🕯️!

We have just passed one year since one of the biggest incidents in Java history, the so-called Log4Shell – if you weren’t with us then (lucky you) you can read more here. It seems to me that its memory should be honored in a way worthy of such an anniversary, for example by recalling the wave of bitter humor that accompanied the community during those difficult days.

So let me recommend my favorite meme, which further puts the issue in a slightly broader context:

Log4Shell, you will always be in our hearts as the one thing that united Java Developers around the world in shared emotions (if only the emotions of horror and sadness) ❤️

You’ll find more like this at log4jmemes.com – there’s been so much of them, they lived up to see their own place in the web.