Thursday, April 28, 2022 - 06:00
  • Share this article:

The release of Jakarta EE 10 is just around the corner, and it will be the first version of Jakarta EE with new features since the release of Java EE 8. These features bring many exciting new options! 

I'd like to highlight five that really stand out:

  • Support for multipart media type in REST services
  • New functions in Jakarta Persistence queries
  • Log in using an OpenID Connect provider
  • Create Jakarta Faces views with pure Java
  • Modern asynchronous API with CompletableFuture

Support for Multipart Media Type in REST Services

Jakarta RESTful Web Services API has become so popular that many developers use it not only for writing and calling REST services but also to replace Jakarta Servlets when writing HTTP services. This is because Jakarta REST API can handle HTTP use cases and is easier to use than the Servlet API. However, for years, users needed either Servlets or a vendor-specific REST API to handle the multipart media type. Jakarta REST 3.1 adds full support for this media type and fills this gap in a standard way.

The multipart media type is a special media type, which allows multiple chunks of data with different media types to be transmitted in a single message. This is often used for sending multiple form fields with different media types, or for uploading multiple files.

On the server, you can simply consume either a list of EntityPart instances from the request body or each entity part separately, identified by its name:



public Response postAsList(List<EntityPart> parts) {…}



public Response postAsParts(@FormParam("part1") String part1,

@FormParam("part2") EntityPart part2) {...}

You can also produce data in the HTTP response by returning a list of EntityPart elements.

On the client, you can create an entity from the list of EntityPart instances and send it as the POST request body:

List<EntityPart> parts = ...

WebTarget target ="http://localhost:8080/multipart");

Response response = target.request().post(

Entity.entity(parts, MediaType.MULTIPART_FORM_DATA));

Jakarta RESTful Web Services 3.1 also standardizes configuration of the JSON-B mapper and brings some other enhancements. You can read about all of them in this article by Andy McCright.

New Functions in Jakarta Persistence Queries

Jakarta Persistence 3.1 brings several new functions to the Query Language and Criteria API. Most of them are standard SQL functions that haven’t been standardized in Jakarta Persistence yet. Adding them makes Jakarta Persistence much more versatile and allows users to write more complex queries with the full power of the entity mappings, without resorting to native SQL queries.

The new functions fall into 3 categories:

  • Numeric functions (CEILING, EXP, FLOOR, LN, POWER, ROUND, SIGN)
  • Functions that return the current local date and time using java.time types (LOCAL DATE, LOCAL DATETIME, LOCAL TIME)
  • The EXTRACT function that extracts a numeric part from a given date (YEAR, QUARTER, MONTH, WEEK, DAY, HOUR, MINUTE, SECOND)

Besides these new functions, Jakarta Persistence 3.1 also allows java.util.UUID to be used as a basic type of field, which is very convenient for entity IDs:

@ID @GeneratedValue(strategy=GenerationType.UUID)

private java.util.UUID id;

The complete list of new features and improvements in Jakarta Persistence 3.1 is described in this article by Lukas Jungmann.

Log in Using an OpenID Connect Provider

For many years, username and password was the standard way to authenticate users logging into an application. Today, it’s very common for users to log in using other services like Facebook or Google, so they don’t need to remember a password for each single application or webpage. The OpenID Connect protocol powers this kind of authentication. The good news is that support for it is coming in Jakarta Security 3.0

The API for OpenID Connect supports integration with any kind of an OpenID Connect provider, not just Facebook or Google. Enterprises can even run their own local provider to centralize account management and implement single sign-on for all their internal applications.

To enable OpenID Connect authentication in a Jakarta EE 10 application, it’s enough to add an annotation to any CDI bean (it’s possible to use EL expressions in configuration values, e.g., to supply secrets):

providerURI = "",
clientId = "${config.clientId}",
clientSecret = "${config.clientSecret}",
redirectURI = "${baseURL}/callback",
public class SecurityBean {

The new OpenID Connect API for Jakarta Security is based on the OpenID Connect support in the Payara Platform. It’s been supported in the Payara Platform since 2018 and it’s finally going to make it into Jakarta EE 10 as a standard feature.

Create Jakarta Faces Views With Pure Java

Jakarta Faces 4.0 brings a new API to define the whole view (HTML page) using only Java code, with no need for XHTML facelets or JSP pages. This means you can now use all the features of Java 11 to build a dynamic view based on your data model in Java. Rather than using non-visual JSF components like ui:repeat or ui:composition to create components dynamically, you can just use Java loops, methods, and objects. Instead of using the rendered attribute to hide components under certain conditions, you can use plain if..else statement. An action listener can be a plain Java lambda; there’s no need to reference a method using an EL expression.

This new Java API for building views gives you full control over how views are built and rendered using plain old Java language features, without any workarounds. Here’s an example:

HtmlForm form = components.create(HtmlForm.COMPONENT_TYPE);

HtmlOutputText message = 


HtmlCommandButton actionButton = 


e -> message.setValue("Hello, World"));
actionButton.setValue("Do action");

Jakarta Faces 4.0 also introduces a new @ClientWindowScoped annotation that makes CDI beans living in the scope of the client window (e.g., a browser tab). Unlike the existing @ViewScoped annotation, this annotation ensures CDI beans continue living even after a transition to a new URL if the new page is loaded within the existing window/tab.

You can read the whole story about what’s new in Jakarta Faces 4.0 in this article by Bauke Scholtz, which also covers other features like extensionless mapping of URLs to views, custom cookie attributes, and a lot more. It’s also worth mentioning that support for JSP and other outdated features has been removed in favor of more modern alternatives.

Modern Asynchronous API With CompletableFuture

Jakarta Concurrency 3.0, out of all the Jakarta EE specifications, probably has the biggest number of new features in Jakarta EE 10. It’s hard to pick just one of them for this article. But the one that clearly stands out is the new Asynchronous annotation to execute any CDI method in a new thread. 

The new jakarta.enterprise.concurrent.Asynchronous annotation blends nicely together with a few Jakarta EE features that were available already in Jakarta EE 9 but each of them had some drawbacks. To summarize, this new annotation:

  • Keeps the simplicity of the javax.ejb.Asynchronous, but is not limited only to EJBs
  • Uses a ManagedExecutorService without needing to manually submit the task to it
  • Supports methods that return CompletionStage or CompletableFuture that allow easy chaining of asynchronous completion and error handlers, while javax.ejb.Asynchronous and ManagedExecutorService only support the old-fashioned Future

As a result, we can execute any CDI method asynchronously using a managed executor just with three steps:

  • Add the @Asynchronous annotation
  • Change return type T to CompletionStage<T> or CompletableFuture<T>
  • Return a stage or a future instead of the direct value

Such a method could look like this:


public CompletableFuture<Double> hoursWorked(LocalDate from, LocalDate to) {

return Asynchronous.Result.complete(result);


When we call this method, it returns a CompletableFuture and the body of the method is executed using the associated managed executor service. The calling method can then use the CompletableFuture API to chain callbacks to be executed after the asynchronous method completes:

bean.hoursWorked( from, to )

.thenAccept( hours -> {

log("Worked " + hours + ".");


Jakarta Concurrency 3.0 also adds a lot of other very useful features like:

  • Standard Cron-based and Timezone-based triggers
  • Annotations for resource definitions of concurrency resources in an application
  • Completion stages that are executed in a managed context
  • Support for running ForkJoinPool threads and parallel streams in a managed context

And a whole lot more.

Other Noteworthy Enhancements in Jakarta EE 10

Jakarta EE 10 also brings some general new features:

  • Support for Java 11 is required by all implementations
  • Java Platform Module System (JPMS) support — each specification API defines its own module information
  • Better CDI alignment — CDI becomes the backbone of many specifications, or it is at least much better supported if developers choose to use CDI
  • Many legacy or deprecated features have been replaced by more modern alternatives

Overall, Jakarta EE 10 will be a heavily modernized version of the good old Java EE as you know it, adding a lot of improvements and new features. 

The final release of the entire Jakarta 10 platform is planned for May 2022. Find out more here: Jakarta EE 10 release plan 

At Payara, we plan to have a compatible Payara Platform 6 Community final release around the same time. Read more in our blog on Payara Platform in 2022

Our CEO Steve Millidge also participated in a webinar with the Eclipse Foundation’s Ivar Grimstad and Tanja Obradovic, discussing: Why Jakarta EE Is the Biggest Thing to Happen to Java in 20 Years

About the Author

Ondro Mihályi

Ondro Mihályi

Ondro Mihályi is a senior Payara service engineer and a committer to the Jakarta Batch, Jakarta Config, and Jakarta Messaging projects.