The Context
The technological landscape of 2026 demands systems that are not just functional but highly resilient and scalable. In this P.o.C. project, we are leveraging the cutting edge: Java 21, Java 25 and Spring Boot 4.0 (which incorporates Spring Framework 7).
The Problem
Understanding the Java 21 – 25 context of these versions is vital as teams migrate from legacy setups, as they introduce paradigms like the “Loom Era” that fundamentally change how we handle concurrency and memory.
On the other hand, Spring Boot 4.X.X further evolves this ecosystem by integrating Spring AI natively, simplifying the orchestration of models like OpenAI and the management of vector stores. It also strictly requires Jakarta EE namespaces, effectively ending the transition away from the old javax.* packages.
The Solution
Important Disclaimer: This is a Proof of Concept (PoC) built for a specific course need. If you find this code useful and decide to use it, you do so entirely at your own risk. The authors decline any responsibility for its use.
Java 21 introduced Virtual Threads, which are lightweight threads managed by the JVM rather than the operating system. This allows applications to scale I/O-bound tasks to millions of concurrent operations without exhausting OS memory. However, it is important to remember that they are not a silver bullet; they should be avoided for CPU-intensive tasks or code that causes “pinning” through synchronized blocks.
Moving to Java 25, we see the stabilization of features like the Flexible Constructor Body, which allows developers to execute code and perform validations before calling super() in a constructor. Additionally, Generational ZGC optimizes garbage collection for large heaps, separating objects by age to allow for microsecond pauses. These enhancements directly impact the performance and stability of high-traffic microservices.
Spring Boot 4.0 further evolves this ecosystem by integrating Spring AI natively, simplifying the orchestration of models like OpenAI and the management of vector stores. It also strictly requires Jakarta EE namespaces, effectively ending the transition away from the old javax.* packages. This version is designed for the “cloud-native” world, supporting features like Project CRaC for millisecond startup times.
Before we dive in, the full source code is available on GitHub: 👉 https://github.com/gabo-gil-playground/java-poc-oauth-jqoo-openai
In the build.gradle file, we explicitly set the Java release to 25 to take advantage of these latest features. The configuration is streamlined using the Kotlin DSL, which provides better type safety and autocompletion compared to traditional Groovy scripts:
plugins {
id 'java'
id 'org.springframework.boot' version '4.0.3'
id 'io.spring.dependency-management' version '1.1.7'
id 'nu.studer.jooq' version '10.1.1'
id 'jacoco'
}
tasks.withType {
options.release.set(25)
}
Pro-tip #1: The Virtual Threads
The application.yml is the heart of our configuration, where we enable the power of Virtual Threads with a single property. We also take advantage of lazy initialization for faster development startups and configure graceful shutdowns to ensure the application terminates cleanly in containerized environments.
spring:
threads:
virtual:
enabled: true
server:
shutdown: graceful
Pro-tip #2: Java 21+ Record and Pattern Matching
Code extracts from the project demonstrate the use of Records for DTOs and Pattern Matching for switch, which significantly reduces boilerplate and improves readability. By deconstructing records directly within a switch statement, we can extract data safely and concisely without manual casting:
public record MessageResponse(String message, String userSubject) {}
public String processResponse(Object obj) {
return switch (obj) {
case MessageResponse(var msg, var sub) -> "User " + sub + ": " + msg;
default -> "Unknown";
};
}
Pro-tip #3: Spring Boot 4.X.X + Spring AI
Code extracts from the project demonstrate the integrating of Spring AI natively:
dependencies {
// spring-boot openai (spring AI)
implementation 'org.springframework.ai:spring-ai-starter-model-openai:2.0.0-M2'
}
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY:openai-dummy-key}
@Service
@Slf4j
public class BlogAIServiceImpl implements BlogAIService {
private final ChatModel chatModel;
/**
* Constructor
* @param chatModel {@link ChatModel} open-ai chat model
*/
public BlogAIServiceImpl(final ChatModel chatModel) {
this.chatModel = chatModel;
}
}
...
SystemMessage systemMessage = new SystemMessage(Constants.OPENAI_SYSTEM_PROMPT);
UserMessage userMessage = new UserMessage(text);
OpenAiChatOptions openAiChatOptions = OpenAiChatOptions.builder()
.model(Constants.OPENAI_MODEL)
.temperature(Constants.OPENAI_TEMPERATURE)
.maxTokens(Constants.OPENAI_OUTPUT_MAX_TOKENS)
.build();
Prompt prompt = Prompt.builder()
.messages(systemMessage, userMessage)
.chatOptions(openAiChatOptions)
.build();
// just for POC purposes - in a real environment it should handle errors and retry logic
ChatResponse chatResponse = chatModel.call(prompt);
String textResponse = getTextFromChatResponse(chatResponse);
...
To run the code, you just need to run gradle bootRun via your terminal or
To run the code, you just need to run gradle bootRun via your terminal or favorite IDE (I personally recommend Intellij). For more details, please, check the README.md file.
Summary of Steps
- Define your dependencies.
- Setup your Java version.
- Configure Java and Spring Boot features at application.yml (or application.properties).
- Migrate old javax.* packages.
- Implement your Java code using Java 21 – 25 + Spring Boot 4.X.X features.
The Results
Migrating to these versions is not just about staying current: it’s about performance. As Software Engineer, I prioritize these updates because a pipeline that drops from 10 minutes to 2 minutes or an API that scales to 10,000 concurrent requests without collapsing is the hallmark of a senior-level architecture. These tools provide the foundation for building the resilient systems required in today’s production environments.
Want to dive deeper into any of these concepts? Drop a comment below and let me know which topic you’d like us to explore in our next Hands-on series!
Do you need help modernizing your legacy applications, optimizing your architecture or improving your development workflows? Let’s connect on LinkedIn or check out my services on Upwork.
Leave a Reply