Jakarta EE New Features: What Changed in Version 11
Jakarta EE new features in version 11 represent the most significant evolution of enterprise Java since the transition from Java EE to Eclipse Foundation governance. Therefore, understanding these changes is essential for teams maintaining enterprise applications. As a result, this guide covers the key improvements alongside practical migration strategies. Crucially, version 11 also raises the baseline to Java 17 and certifies against Java 21, which unlocks records, sealed types, and virtual threads inside the platform itself.
CDI Lite and Simplified Dependency Injection
CDI Lite provides a trimmed-down dependency injection model optimized for cloud-native deployments. Moreover, it removes rarely-used features like decorators and conversation scope to reduce runtime overhead. Consequently, applications using CDI Lite start faster and consume less memory in containerized environments.
The simplified model retains core injection capabilities including qualifiers, producers, and interceptors. Furthermore, build-time annotation processing replaces much of the runtime reflection, enabling ahead-of-time compilation with GraalVM native images. The distinction matters in practice: CDI Lite defines a build-compatible extension model, while the older Portable Extensions SPI runs only at boot on a full runtime. Frameworks such as Quarkus and Helidon lean on the Lite model precisely because resolving beans at build time eliminates classpath scanning and shaves seconds off cold starts.
Jakarta EE New Features in REST and Data
Jakarta REST 4.0 introduces Server-Sent Events support and improved async processing. Additionally, the entity filtering API allows field-level control over JSON serialization without custom DTOs. For example, you can now annotate entity fields to include or exclude them based on security roles.
// Jakarta REST 4.0 — Server-Sent Events
@Path("/events")
public class EventResource {
@GET
@Produces(MediaType.SERVER_SENT_EVENTS)
public void streamEvents(@Context SseEventSink sink, @Context Sse sse) {
CompletableFuture.runAsync(() -> {
try {
for (int i = 0; i < 10; i++) {
sink.send(sse.newEventBuilder()
.name("update")
.data(String.class, "Event " + i)
.build());
Thread.sleep(1000);
}
} finally {
sink.close();
}
});
}
}
// Jakarta Data 1.0 — Repository pattern
@Repository
public interface ProductRepository extends CrudRepository<Product, UUID> {
@Find
List<Product> findByCategory(@By("category") String cat);
@Query("SELECT p FROM Product p WHERE p.price < :max ORDER BY p.name")
Page<Product> findAffordable(@Param("max") BigDecimal max, PageRequest page);
}
Jakarta Data 1.0 standardizes the repository pattern across persistence providers. Therefore, switching between JPA, NoSQL, and other backends requires only configuration changes.
Jakarta Data 1.0 in Depth
Jakarta Data deserves a closer look because it is the headline addition and the one most likely to change how you write persistence code. Developers coming from Spring Data will recognize the shape immediately: declare an interface, extend a base repository, and let the provider generate the implementation. The novelty is that this is now a vendor-neutral specification, so the same repository definition works whether the provider is EclipseLink over JPA or a document store.
The annotation-driven query methods replace much of the boilerplate that DTOs and hand-written DAOs used to carry. The @Find annotation builds queries from parameter names and @By bindings, while @Query accepts Jakarta Query Language for anything more complex. Pagination is first-class through PageRequest and the returned Page, which exposes total counts and slice metadata without a second query in many providers. One sharp edge worth flagging: not every provider supports every return type or keyword yet, so the portability promise is real but still maturing in practice. The pattern below shows a typical service consuming the repository with cursor-style paging.
@ApplicationScoped
public class CatalogService {
@Inject
ProductRepository products;
public List<Product> cheapestInCategory(String category, BigDecimal ceiling) {
// Sorted, paged query without a hand-written JPQL string
PageRequest first = PageRequest.ofSize(25);
Page<Product> page = products.findAffordable(ceiling, first);
return page.content().stream()
.filter(p -> category.equalsIgnoreCase(p.category()))
.toList();
}
}
Security and Configuration Updates
Jakarta Security 4.0 adds OpenID Connect client support directly into the specification. However, this previously required vendor-specific extensions or external libraries. In contrast to earlier versions, the standardized OIDC client simplifies multi-provider authentication in enterprise applications.
Jakarta Config introduces externalized configuration with type-safe injection, similar to MicroProfile Config but as a full Jakarta EE specification. Specifically, configuration sources follow a priority chain from environment variables through property files to programmatic defaults. The standardized @OpenIdAuthenticationMechanismDefinition annotation lets you wire an identity provider declaratively, as shown below, instead of reaching for a vendor library and gluing callbacks together by hand.
@OpenIdAuthenticationMechanismDefinition(
providerURI = "https://accounts.example.com",
clientId = "${config.oidc.clientId}",
clientSecret = "${config.oidc.clientSecret}",
redirectURI = "${baseURL}/callback"
)
@ApplicationScoped
public class SecurityConfig { }
Migration Path from Jakarta EE 10
Most Jakarta EE 10 applications require minimal changes for version 11 adoption. Additionally, the specification maintains backward compatibility for core APIs while deprecating features targeted for removal in future versions. For instance, applications using standard CDI should add the CDI Lite qualifier to opt into the streamlined model. The one mandatory gate is the runtime: version 11 requires Java 17 as a minimum, so teams still on Java 11 must clear that upgrade first.
A pragmatic migration sequence is to bump the runtime, then update the jakarta.* coordinates, then run the test suite before adopting any new specification. Teams that already completed the javax-to-jakarta namespace move for version 9 will find this step trivial, since the package names do not shift again. The riskiest area tends to be removed or deprecated features rather than the new ones, so audit usage of conversation scope and any deprecated SOAP-era APIs early. Tools like the Eclipse Transformer can automate the bytecode-level rewrites for dependencies that have not yet shipped Jakarta-native artifacts.
Validating the move benefits from the same regression discipline you would apply to any major upgrade. In practice, teams stand up the new runtime in a parallel environment, replay a representative slice of integration tests against it, and compare startup time and memory footprint before and after. Because version 11 leans on build-time processing, a common surprise is that reflection-heavy libraries or custom CDI extensions that worked on a full runtime need adjustment for the Lite model. Consequently, it pays to inventory every Portable Extension and serialization helper up front rather than discovering the gap during a production deploy. Where a dependency genuinely cannot be upgraded, isolating it behind a thin adapter keeps the blast radius small and lets the rest of the application move forward on the new platform.
When NOT to Rush the Upgrade
Adopting the latest platform is not automatically the right call, and an honest assessment saves pain. If your application servers do not yet ship a certified Jakarta EE 11 runtime, upgrading the specification leaves you on unsupported ground; in production teams typically wait for a GA release of their chosen server before committing. Likewise, if a critical third-party library still publishes only javax artifacts, the migration stalls until that dependency catches up, and shimming it is rarely worth the maintenance burden.
There is also a cost-benefit question for stable, low-change applications. A back-office system that rarely deploys gains little from faster cold starts, so the testing and certification effort may not pay back soon. In contrast, latency-sensitive, frequently scaled cloud services benefit most from CDI Lite and the Java 21 baseline. As a rule, weigh the operational upside against regression risk, and stage the move through a non-critical service first.
Related Reading:
- Spring Boot 4 Structured Concurrency
- Spring Boot Best Practices
- GraalVM Native Spring Boot
- Java Pattern Matching Guide
Further Resources:
In conclusion, Jakarta EE new features deliver meaningful improvements for cloud-native enterprise Java while maintaining backward compatibility. Therefore, plan your migration to benefit from CDI Lite, Jakarta Data, and standardized security capabilities, but time the move to your runtime support and dependency readiness.