What Will JDK 24 Bring? - JVM Weekly vol. 103
Let's be back with yet another classic edition with Release Radar included.
1. Changes in JNI, Security Manager, G1 - What Will JDK 24 Bring?
It's nice to attend conferences, but we've gathered a bunch of JEPs — as usual, there's a lot going on after a new JDK version release. So, let's take a look at both the announced changes in JDK 24 and those that are just candidates.
JEP 472: Prepare to Restrict the Use of JNI
Let's start with the biggest announcement so far... whose blast radius isn't as large as the name might suggest.
The Java Native Interface (JNI) was introduced with JDK 1.1 in 1999 as the main mechanism allowing Java code to interoperate with native code, usually written in C. Thanks to JNI, developers could call native functions from Java (downcalls), and conversely, native code could communicate with Java code (upcalls). However, over time, it became clear that using JNI carried significant risks, especially in terms of JVM stability, security, and debugging issues that arose from interactions with unmanaged memory. Additionally, maintaining JNI was a nightmare due to its highly complex programming model.
As a result, the need arose for a safer alternative. The FFM API, which became stable in JDK 22, is beginning to replace JNI, offering a more modern, safe, and controlled way to integrate with native code while minimizing risks related to application integrity violations. JNI is slowly (or should be) giving way to the FFM API, and as a result, the entire platform is evolving.
JEP 472: Prepare to Restrict the Use of JNI has a somewhat misleading name because its goal is not to remove this functionality. While JNI is crucial for interoperability between Java and native code, it carries risks such as JVM crashes or security breaches resulting from interactions with unsafe native code. At the same time, many of these issues also apply to code using the FFM API. Therefore, from now on, all native calls, whether using JNI or FFM API, will trigger a warning unless the user explicitly allows them at runtime with the command: java --enable-native-access=*. In the future, this warning will become an Exception. Interestingly, in the case of the FFM API, IllegalCallerException
is already being thrown. To ensure consistency between both approaches, the FFM API will now also only issue warnings instead of exceptions.
JEP 486: Permanently Disable the Security Manager
The above JEP mainly limits/organizes access to old functionalities, but that doesn’t mean nothing ever disappears from JDK, as evidenced by JEP 486. It introduces the permanent disabling of the Security Manager, which—contrary to what its name might suggest—hasn't been the primary tool for securing Java code for years. Although it was important for application security in the past, its complicated model, based on the principle of least privilege, meant it was rarely used.
In Java 17, the Security Manager was deprecated, and now the plan is to remove the ability to enable the Security Manager during JVM startup and to prevent its installation during application runtime. These changes will simplify the maintenance of JDK code, which currently still has to support numerous permission-checking mechanisms, even though the Security Manager is no longer used. The removal of the Security Manager API is also planned for a future Java release.
I’m not sure if you remember the controversy surrounding the deprecation of the Security Manager when JEP 411 was introduced (I member!). The warning about its removal sparked criticism from part of the community, which was concerned that the lack of a sandboxing replacement would force developers to use other, more complex mechanisms. However, the deprecation ultimately passed without much impact, as most applications had long stopped using the Security Manager, and interest in its development was minimal.
JEP 475: Late Barrier Expansion for G1
The next proposal, JEP 475: Late Barrier Expansion for G1, introduces changes in how memory barriers used to track memory operations in the G1 Garbage Collector are expanded. Memory barriers are special instructions added by the JVM in program code to help control memory access and track data changes, allowing mechanisms like the Garbage Collector to safely manage objects. These barriers are crucial in preventing situations where different threads might simultaneously modify the same data, potentially leading to errors or inconsistencies.
Barrier expansion refers to the process where memory barriers are automatically transformed into more complex instructions to meet the specific requirements of the Garbage Collector during program execution. This expansion happens during Just-In-Time (JIT) compilation, which increases the compiler’s workload by about 10-20%. Currently, these barriers are expanded early in the compilation process by the JIT C2 compiler.
The change proposed by this JEP shifts the expansion of G1 barriers from the early stages of compilation (during bytecode parsing) to later stages, right up until machine code generation. Delaying barrier expansion aims to reduce JIT compilation time and simplify the work of GC developers, who will no longer need to deal with the intricate details of C2—where, as they say, "there be dragons." It also allows for better management of memory operation order and reduces the risk of instruction ordering errors. This solution preserves the quality of the generated code, while making barriers easier to understand and manage for HotSpot developers, without negatively impacting application performance.
JEP 484: Class-File API
Now, let’s move on to something we’ve discussed before. As many of you know, the class-file is the binary format in which the JVM stores compiled Java classes. Each Java class is represented as a class-file, which contains information about names, fields, methods, and bytecode (the JVM's machine instructions). This format allows Java to be platform-independent, and tools like ASM or Javassist can parse, generate, and transform class files, which is crucial for creating dynamic functionality in Java applications. Now, Java is finally introducing a stable, native API for class files with JEP 484: Class-File API.
This API was initially introduced as a preview feature in JEP 457 for JDK 22, and then improved in JEP 466 for JDK 23. In JDK 24, it is planned to be finalized, with only minor changes based on user feedback, which will eliminate the need for external libraries like ASM.
JEP 487: Scoped Values (Fourth Preview)
JEP 487 introduces scoped values, which allow methods to share immutable data both with methods they call within the same thread and with their child threads. These scoped values are simpler to use than ThreadLocal and have lower memory and runtime costs, especially when used with virtual threads (JEP 444) and structured concurrency (JEP 480).
As part of Project Loom, scoped values were incubated in JDK 20 (JEP 429) and previewed in JDK 21 (JEP 446), JDK 22 (JEP 464), and JDK 23 (JEP 481). In JDK 24, we get yet another preview version, with minimal changes compared to previous ones. The most significant change is the removal of the callWhere
and runWhere
methods, streamlining the API.
JEP 488: Primitive Types in Patterns, instanceof, and switch (Second Preview)
JEP 488 allows primitive types to be used in patterns, the instanceof operator, and switch constructs. This enables consistent processing of data regardless of whether it is primitive or reference types. The goal is to align the capabilities of patterns for primitive and reference types, eliminating existing limitations in the Java language.
This project was initially proposed in JEP 455 and delivered as a preview feature in JDK 23. JEP 488 continues the preview, with no significant changes compared to the previous version, focusing on gathering more feedback from the community.
As you can see, there aren't many groundbreaking new features, and JDK 24 seems to be another "cleanup" release. If the developers don't surprise us with something new, there might not be much to get excited about (although the list of preview features hints that JDK 25 could be really interesting). I'm waiting, the list is still open, and perhaps something from Project Valhalla will make an appearance.
Interestingly, aside from the candidate and targeted JEPs for JDK 24, we also received an informational JEP with a particularly intriguing proposal: JEP 14: The Tip & Tail Model of Library Development. This JEP describes the "tip & tail" model, which aims to improve the release process for libraries in the Java ecosystem to better meet the needs of different user groups.
Currently, most libraries follow a "one-size-fits-all" approach, assuming that every new release contains new features, bug fixes, and security patches. However, users have different priorities—some are eager for new features, while others focus on stability and only need critical fixes. Additionally, supporting older JDK versions makes it difficult to adopt new APIs, such as Virtual Threads or records, as it would require breaking compatibility. The "tip & tail" model aims to allow for fast innovation while also providing long-term support and stability for existing applications.
In this model, library development is divided into two streams: "tip," where new features and improvements are introduced, including those from new JDK APIs, and "tail," which contains only critical fixes and security patches. This approach reduces the number of backports, as the "tail" stream will not include new features or performance improvements, minimizing the risk of destabilization. Library developers adopting this model would focus on developing new features in the "tip" stream, while users seeking stability could rely on the "tail" stream, confident that updates will not negatively impact their systems.
In theory, this sounds like an interesting concept, but it will be interesting to see how well it is adopted in practice. The real-world test will come from how the community responds to this model. It’s worth watching how large open-source community projects will react.
2. What’s the Spring Team planning for version 7.0?
We’ve discussed JEP proposals and third-party libraries, so now let's take a look at the biggest third-party library—what's Spring planning for us?
Spring Framework 6.2, set for release in November, marks the end of the 6.x branch and the beginning of work on Spring Framework 7.0, announced by Juergen Hoeller and scheduled for release in November 2025. It will support Jakarta EE 11, Tomcat 11, Hibernate ORM 7, and JDK 25 LTS, while still maintaining JDK 17 support to ensure functionality for the broader community. The framework will continue its alignment with GraalVM, Project Leyden, and Spring AOT.
The new version will bring additional improvements, particularly in Kotlin 2 support and the convergence of null safety strategies with JSpecify annotations (which I’ll explain more about shortly). There are also planned changes in JPA and JMS handling, and some older features will be deprecated, with a focus on ensuring a smooth upgrade path. The first milestone for Spring Framework 7.0 is expected in early 2025, with Spring Boot 4.0 and Spring Cloud 2025.1 being based on this major release.
I promised to touch on JSpecify again. It’s a project aiming to standardize null safety mechanisms in Java. Various tools and libraries have tried to address this issue, but the lack of a unified specification has made it difficult to consistently enforce null safety. JSpecify seeks to fill this gap by introducing clear nullability annotations that can be used across the JVM ecosystem, with compatibility for older code and tools.
Spring Framework 7 has announced its migration to JSpecify annotations, which is a huge boost for the project. The new version of the framework will deprecate Spring’s current nullability annotations while adopting the JSpecify specification. This migration will ensure consistency with other libraries, such as Reactor and Micrometer, which also plan to adopt the new standard, helping the JVM ecosystem move towards full null safety during the build process.
If you're curious about what the world would look like if we applied these kinds of tools, I recommend checking out Meta's case study. In their article Retrofitting null-safety onto Java at Meta, Artem Pianykh , Ilya Zorin and Dmitry Lyubarskiy show the application of Nullsafe, a tool for static code analysis used at Meta, demonstrating the real benefits of verifying nullability in code. Meta developed Nullsafe to minimize the occurrence of NullPointerException errors, with the ability to gradually introduce it into legacy codebases. By leveraging this tool across millions of lines of code, Meta significantly reduced NPEs in applications such as Instagram, leading to improved stability.
While Nullsafe itself isn't publicly available, Meta has released a tool called Infer, which forms the core of Nullsafe’s functionality. Infer performs static analysis on code to detect bugs, and although it doesn’t cover all the features of Nullsafe, it provides similar benefits for open-source projects. Meta is also involved in the development of JSpecify, making them a key player in the null safety ecosystem.
New features are always exciting, but that doesn't mean we should expect a complete cutoff from older versions. Take Spring Boot 3 as an example—it was released in November 2022, introducing a modernized foundation with Java 17, the transition from Java EE to Jakarta EE, native compilation via GraalVM, and built-in observability mechanisms as key features throughout the entire Spring ecosystem. Despite these innovations, its adoption only began to surpass that of version 2 after the release of Spring Boot 3.2. Many companies and developers are still in the process of upgrading from version 2 to version 3 due to the scope of changes introduced.
Understanding that the upgrade process can be time-consuming, Spring has extended commercial support for Spring Boot 2.7 and its associated projects until the end of 2026. This extension provides an additional 16 months of support, offering over eight years of support for the Spring Boot 2.x line. This gives companies the flexibility to update at their own pace, without the pressure of immediate migration. For those facing challenges with this process, tools such as OpenRewrite by Moderne and Tanzu Application Advisor can help automate the upgrade process.
3. Release Radar
OpenJDK 23
Let's start with an obligatory mention, but one that comes with a bit of pleasure. Amazon, Azul, and BellSoft have all released their versions of JDK 23. A new version of Temurin from the Eclipse Foundation has also been released.
So, essentially, we’ve got a complete set. See you at JDK 24!
JavaFX 23
Now that we’re back to the latest JDK release, it’s time to look at another project with a "23" in its name. JavaFX 23 announced by Kevin Rushforth has hit the scene and brought with it a warning: "It's time to update." JavaFX has dropped support for older versions and will now require JDK 21.
In terms of functionality, the main changes relate to scrolling. ListView, TreeView, and similar components will now scroll based on the view's length rather than one cell at a time, as in earlier releases. Additionally, new keyboard shortcuts have been added to enhance accessibility, enabling scrolling via the keyboard.
But what if your app doesn’t involve scrolling, and these new features don’t interest you, so you’d prefer to stay on an older version? Unfortunately, the expiration date is nearing here as well. Oracle has announced that support for JavaFX in JDK 8, the last version they released, will end in March next year. A fun fact for nostalgic users.
Visual Studio Code Oracle Java Extension 23.0.0
Wrapping up the "twenty-threes," Oracle Java Extension 23.0.0 for Visual Studio Code announced by Arvind A. is now available, supporting JDK 23 and its new features (including preview ones). This release brings several improvements, such as the ability to set separate JDKs for user projects, a download progress bar for JDKs, and a "Quick fix" feature for managing warnings. Additionally, control over searching parent directories during project scans has been introduced, along with improvements like enhanced refactoring options and import corrections. As a cherry on top, the extension has been localized in Simplified Chinese and Japanese.
Quarkus 3.15
Now for some big and small changes in Quarkus. In July 2023, the project introduced an LTS (Long-Term Support) version policy, aimed at providing a stable version for users who prefer long-term reliability over frequent updates.
LTS versions of Quarkus are supported for 12 months, allowing users to avoid frequent updates that could introduce incompatibilities or regressions. The Quarkus team releases a new LTS version every six months (the last one was Quarkus 3.8), containing critical fixes, security updates, and performance improvements.
Extension maintainers and creators are encouraged to ensure support for LTS versions, ensuring that promised stability is maintained for users. In many cases, this means managing separate branches for LTS and main Quarkus features, which is somewhat similar to the Tip and Tail model mentioned earlier.
So why is this release both big and small? The latest LTS release, Quarkus 3.15, is built on previous versions and doesn’t bring any particularly groundbreaking features in itself (hence the "small").
Graal Development Kit (GDK) for Micronaut 4.6.0
With the release of GraalVM for JDK 23, the Graal Development Kit (GDK) for Micronaut 4.6.0 was also launched. The most notable new feature is integration with Microsoft Azure, enabling seamless portability across cloud platforms—now supporting Oracle Cloud, AWS, Google Cloud, and Azure. This allows developers to build, deploy, and manage Java applications across various cloud services without fear of vendor lock-in. GDK also includes platform-independent APIs and modules for services such as Azure Database for MySQL, Kubernetes Services, Key Vaults, and others, increasing flexibility and possibilities for cloud application development.
In addition to Azure integration, this release places a strong emphasis on supply chain security, following the Supply Chain Levels for Software Artifacts (SLSA) guidelines. By using the Oracle Macaron tool, GDK artifacts are verified for integrity, giving users confidence in the build process. This release also includes an updated version of the Micronaut 4.6.0 framework and a new Bill of Materials (BOM) to simplify dependency management. The CLI and GDK Launcher have also been updated, and new practical labs for Oracle Cloud Infrastructure are now available to users.
Additionally, Fabio Niephaus from the GraalVM team recently published a new graal-languages-demos repository containing a series of demonstrations and guides for GraalPy, GraalJS, and GraalWasm, offering practical applications and detailed instructions for working with Graal languages.
JobRunr 7.3
JobRunr by Ronald Dehuysser is an open-source tool for background task processing in Java applications. It allows developers to easily schedule and run long-running processes asynchronously, without impacting the main application thread. JobRunr is designed to be simple to use while being scalable and includes a built-in dashboard for monitoring and managing tasks. It also has a well-crafted Pro version, which offers additional features such as more advanced scheduling and task queuing.
JobRunr 7.3.0 adds compatibility with Quarkus 3.15 (which we just mentioned) and Kotlin 2.0.20. Among the key changes are improved support for building native executables, better separation of build-time and runtime properties, and the ability to dynamically enable or disable background job servers. Additionally, JobRunr officially ends support for MongoDB 3.6, encouraging users to update to newer versions.
JobRunr Pro v7.3.0 introduces improvements to the control panel, allowing users to more flexibly start and queue recurring tasks, along with a significant performance boost when reinitializing workflows. This version also strengthens integration with Quarkus and MongoDB, offering better startup performance and enhanced monitoring capabilities.
Debezium 3.0
Debezium is a popular open-source tool for implementing CDC (Change Data Capture), enabling real-time tracking of database changes and replicating them. Thanks to its integration with Apache Kafka, Debezium facilitates stream processing and replication of changes across different systems. It supports many popular databases, such as MySQL, PostgreSQL, MongoDB, Oracle, SQL Server, and more, offering a valuable platform for monitoring and processing data changes.
Debezium 3.0, announced by Chris Cranford, now requires Java 17 for all connectors, and for Debezium Server, Operator, and the Quarkus Outbox Extension, Java 21 is required. This version is based on Kafka 3.8, which involves adapting Kafka’s internal APIs but doesn’t directly affect most users. Version 3.0 also removes deprecated fields such as the incremental signal and introduces detailed CRUD metrics at the table level, allowing better tracking of changes and integration with analytical tools. New features, such as monitoring truncate operations for certain databases, help cover additional use cases in data modification monitoring.
Manifold SQL
Now things are getting interesting.
Manifold by Scott McKinney is a Java extension that enriches the language with new capabilities, including dynamic type extensions and metaprogramming support. With Manifold, developers can add new functionality to existing types, create cross-platform libraries, and use native expressions in code without needing code generation or complex configurations. Manifold is compatible with various versions of Java and provides support for dynamic type loading, simplifying the handling of compile-time and runtime types.
Manifold SQL is a new module that allows SQL code to be injected directly into Java code in a type-safe and secure way. This makes it possible to write SQL queries without using ORMs, DSLs, or code generation. Query result types are type-safe and can be automatically mapped to entities from the database, simplifying CRUD (Create, Read, Update, Delete) operations. Manifold SQL uses database metadata to ensure that SQL queries and their results are always fully synchronized with the types defined in the database schema.
Manifold SQL operates via a plugin for the Java compiler that uses the SPI jdk.compiler.Plugin interface. During compilation, Manifold intercepts the type resolution process to generate types on-demand as needed by the compiler. This ensures that entity and query types are generated in real-time, allowing for safe typing and projection of types directly from the database, with schema information retrieved via a standard JDBC connection. This approach guarantees that types are always synchronized with the database's current structure, providing 100% type safety and protection against SQL injection.
Who’s going to try it first?
Ktor 3.0
Ktor, the flagship open-source framework created by JetBrains for building server-side applications and HTTP clients in Kotlin, has released version 3.0, as announced by Anton Arhipov . The biggest change is the transition to the kotlinx-io library, which unifies IO operations in Kotlin and brings significant performance improvements. However, this change may impact users of low-level IO APIs like Input, Output, ByteReadChannel, or ByteWriteChannel. Additionally, the migration to kotlinx-io enables support for multiple data sources and operations such as file compression. Performance tests show impressive results, with some applications experiencing performance gains of over 90%.
The new version of Ktor also introduces support for Server-Sent Events (SSE), allowing the server to send one-way communication to the client via HTTP, which is useful for applications requiring constant updates without frequent polling. It also adds the ability to serve static resources from ZIP archives and includes protection against CSRF attacks. Ktor 3.0 also adds support for the Ktor client on WebAssembly (Wasm), a nice nod towards Kotlin Multiplatform.
Kotlin Money
Continuing with Kotlin, Kotlin Money by Eriksen Costa is a new library designed specifically for handling and manipulating monetary amounts in Kotlin. It allows for precise calculations, percentage operations, and amount allocations, solving rounding issues that often arise with installment payments, currency exchanges, or handling fees and taxes. The library supports both traditional currencies and cryptocurrencies, making it easy to create applications requiring precise monetary operations. Example operations include adding, reducing amounts by percentage discounts, and dividing sums into equal or proportional parts, with the guarantee that the allocation sum will always match the original amount.
The library supports 306 circulating currencies and 2283 cryptocurrencies, making it a versatile tool for handling money in Kotlin-based projects.
Langchain4j 0.35.0
Finally, we have the new release of Langchain4j 0.35.0. As usual, the project brings new integrations: chat models and embeddings from GitHub Models, a document loader from Google Cloud Storage, a ranking model from Google Vertex AI, and ONNX Reranker. Additionally, there’s embedding storage from Tablestore and Voyage AI. Other notable changes include support for embedding models, token counting, and observability support for Ollama. If any of these names ring a bell, you’ll be pleased!
As a parting gift, I want to remind you about that classic.