Java EE 8: the baseline of Jakarta EE

Java EE 8 and its reference implementation GlassFish 5 will be the baseline for the initial Jakarta EE version (a.k.a. Jakarta EE 8 and Eclipse Glassfish 5.x). Therefore, it is worth to take a deeper look at what is new and noteworthy in Java EE 8 compared to its predecessors.

Java EE 8 advertising mottos

One of the main goals of the JEE 8 specification is to consequently continue what started in JEE 6 and JEE 7, in particular supporting the two mottos “Modern Web Development” and “Ease of Development”.

Topics like HTTP/2 including push instead of pull, advanced JSON support and a reactive programming model are as well on the list of new features as advanced support of new Java 8 lambda and stream APIs or CDI enhancements like asynchronous events.

Brave new Web World

First of all, it is worth mentioning that the JSF managed bean facility is deprecated since JSF version 2.3 (finally!). So please, please use CDI managed beans only in the future: “As of version 2.3 of this specification, use of the managed bean facility as specified in this section is strongly discouraged. A better and more cohesively integrated solution for solving the same problem is to use Contexts and Dependency Injection (CDI), as specified in JSR-365.”

Since the new version 2.3, JSF offers a tag for WebSocket support. Combined with an injectable push context on the server side, it is quite easy to implement the WebSocket protocol inside a JSF application (listing 01 and 02).

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:h="http://xmlns.jcp.org/jsf/html">
    <h:head>
        Websocket Example
    </h:head>
    <h:body>
        <f:websocket channel=”helloWorldChannel" 
            onmessage="function(message){alert(message)}" />
    </h:body>
</html>

Listing 01: JSF view with f:websocket tag

@Named
@RequestScoped
public class SomeBean {
 
    // WebSocket push channel with name “helloWorldChannel”
    @Inject @Push(channel = “helloWorldChannel””
    private PushContext channel;
 
    public void send(){
        channel.send("Hello, push world!");
    }
)

Listing 02: CDI bean with PushContext

In addition, JSF 2.3 offers some convenient producers to allow easy annotation-based access to JSF artifacts like application, session, request or header.

Inject
@SessionMap
private Map<String, Object> SessionMap;

Also interesting is a new JSF tag for class level bean validation <f:validateWholeBean> that in my personal opinion is long overdue. With the help of this tag not only attributes of the CDI backed bean can be validated via BeanValidation but the bean as a whole. This allows checks like the equality of password and password repeat in a very easy manner.

RESTful API Design

The second big block of changes and enhancements addresses the field of RESTful API design.

Even though the new JAX-RS version 2.1 is only a minor release, it offers a lot of new features, first and foremost to support non-blocking I/O and asynchronous request handling.

The JAX-RS client is now able to support the Java 8 CompletionStage. This feature really helps to prevent the problem of nested callback handlers (a.k.a. pyramid of doom). Listing 03 shows a simple example taken from the original JAX-RS 2.1 specification. The example shows a client sending two asynchronous REST calls whose results will be reunited with the help of a CompletionStage.

// async REST call no 1 (via RxInvoker using CompletionStage)
 CompletionStage<String> cs1 = client.target("http://my-domain-one.com/api")
     .request()
     .rx()
     .get(String.class);

// async REST call no 2 (via RxInvoker using CompletionStage)
 CompletionStage<String> cs2 = client.target("http://my-domain-two.com/api")
     .request()
     .rx()
     .get(String.class);

 // combining result of async REST call no 1 and no 2
 CompletionStage<List>String>> list = cs1.thenCombine(cs2, list::of); 

Listing 03: reactive client via RxInvoker

Also new and noteworthy in JAX-RS 2.1 is the support of the Server-Sent Event specification. The new API allows to push DOM events from server to a specific client or – via broadcasting - to a group of registered clients. While listing 04 demonstrates how to establish an SSE connection via JAX-RS client, listing 05 shows the corresponding JAX-RS server that pushes events to all registered clients via broadcast mechanism.

WebTarget target = client.target("http://...");
 try (SseEventSource source = SseEventSource.target(target).build()) {
     source.register(System.out::println);
     source.open();
     Thread.sleep(5000); // Consume events for just 5000 ms
 } catch (InterruptedException e) {
    // do some intelligent exception handling 
        ...
 }

Listing 04: JAX-RS SSE client

@Singleton
public class SseResource {

    @Context
    private Sse sse;

    private SseBroadcaster sseBroadcaster;

    @PostConstruct
    public init() {
        this.sseBroadcaster = sse.newBroadcaster();
    }
    
    @GET
    @Path("register")
    @Produces(MediaType.SERVER_SENT_EVENTS)
    public void register(@Context SseEventSink eventSink) {
        eventSink.send(sse.newEvent("welcome!"));
        sseBroadcaster.register(eventSink);
    }
  
    @POST
    @Path("broadcast")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public void broadcast(@FormParam("event") String event) {
       sseBroadcaster.broadcast(sse.newEvent(event));
    } 
}

Listing 05: JAX-RS SSE broadcast server

With JSON-B 1.0 (JSON Binding API) a missing piece finds its way into the Java Enterprise standard. With the help of the JSON-B API Java objects can be automatically transformed into JSON objects and vice versa. This is a real step forward, because it means that there is no need for the (mis)usage of JAX-B for this task anymore.

To adapt the default mapping behavior various annotations can be used. So, for example, individual fields can be hidden via @JsonbTransient and default attribute names can be overridden via @JsonProperty. These two examples are only a few of many customizing possibilities.

But JSON-B is not the only API indicating the growing importance of REST and JSON for the Java Enterprise standard. The JSON-P API also got some really interesting new features. Besides some minor issues, like the introduction of a JsonCollectors helper class and the alignment with the Java 8 Stream APIs, the added support for JSON pointer and JSON patch are the most outstanding enhancements of JSON-P 1.1.

JSON pointer defines a string expression that identifies a specific value or part within a JSON object. So, it is kind of similar to XPointer (for XML documents). In addition, JSON pointer can be used for JSON manipulation. Listing 06 shows an example where an element is added to an array – named “hobbies” - of a JSON object first and an existing element of the same array is replaced afterwards.

// original json object 
JsonObject jsonObject = (JsonObject) JsonUtil.toJson(
“{
    ‘name’: ‘lars’, 
    ‘hobbies’: [
        ‘swimming’, 
        ‘reading’
    ]
}”

// extract hobbies from JSON structure 
// and insert “biking” as new first element 
JsonPointer pointer = Json.createPointer(“/hobbies/0”); 
pointer.add(jsonObject, Json.createValue(“biking”)); 

// replace 3rd element (reading) with new value (running)
pointer = Json.createPointer(“/hobbies/2”);
JsonObject newJsonObject = pointer.replace(jsonObject, Json.createValue(“running”)); 

// manipulated json object 
// {
//     ‘name’: ‘lars’, 
//     ‘hobbies’: [
//         ‘biking’,
//         ‘swimming’, 
//         ‘running’
//     ] 
// }

Listing 06: JSON manipulation via JSON pointer

The usage of JSON pointer for JSON manipulation can become kind of complex when there are more than one or two operations – add, remove, replace, move copy or test - to fulfill. In a case like this, it would make sense to use JSON patch instead. Listing 07 shows an example where the value of one JSON attribute is copied into another attribute (“name” to “nickname”) and in addition a JSON array is manipulated.

// original json object 
JsonObject targetObject = (JsonObject) JsonUtil.toJson(
    “ {                               “ +
    “   ’name': 'lars,                “ +
    “   ’nickname ': 'mobileLarson',  “ +
    “   ’hobbies': [                  “ +
    “        ’swimming', ’running'    “ +
    “   ]                             “ +
    “ }                               “ ); 

// patch operations to apply  
JsonArray patch = (JsonAray) JsonUtil.toJson(
    “ [                                                            “ +
    “    { ’op': 'copy', 'path': '/nickname', 'from': '/name' },   “ +
    “    { ’op': 'remove', 'path': '/hobbies/1},                   “ +
    “    { ’op': 'add', 'path': '/hobbies/-', 'value': 'cycling' } “ +
    “]                                                             “ ); 
JsonPatch patch = new JsonPatch(patch)

// apply patch will result in: 
// {
//    ‘name’ : ‘lars’
//    ‘nickname’ : ‘lars’
//    ‘hobies’ : [
//       ‘swimming’, ‘cycling‘
//    ]
// }
JsonStructure result = patch.apply(target)

Listing 07: JSON manipulation via JSON patch

Old friends refurbished

In addition to the so far described enhancements, there are two more APIs that got a kind of face-lift: CDI 2.0 and Bean Validation 2.0:

CDI 2.0 is now aligned with Java 8. Features like streams, lambdas or repeating qualifiers can be used in a transparent way. In addition, the order of CDI observer handling at runtime can be forced via @Priority annotation, that is part of Commons Annotations for the Java Platform (JSR 250). Next to these rather minor enhancements, the CDI specification has been split into three parts:

  • Core CDI
  • CDI in Java SE
  • CDI in Java EE

With the help of CDI in Java SE it is now possible to bootstrap a CDI container in a Java SE application in a standardized way and to use all CDI core features, like injection, qualifiers, producers, scopes, stereotypes, observers and so on (listing 08).

public static void main(String... args) {
    SeContainerInitializer containerInit = SeContainerInitializer.newInstance();
    SeContainer container = containerInit.initialize();
    // retrieve a bean and do work with it
    MyWorkerBean myBean = container.select(MyWorkerBean.class).get();
    myBean.doSomeWork();
    // when done
    container.close();
}

Listing 08: CDI bootstrapping in Java SE

The introduction of asynchronous events is another important enhancement of the current CDI specification. CDI events now offer an additional method fireAsync(…) that returns a CompletionStage<T>. To be able to handle the event in an asynchronous way, the corresponding observer must be qualified as @ObservesAsync (listing 09).

@ApplicationScoped 
public class AsyncEventFireBean { 

        @InjectEvent<SomePayload> event;
 

        public void someAsyncBusinessTriggerMethod() { 
 
            // fire (and forget) asynchronous event 
            event.fireAsync(new SomePayload()); 

            // do some additional work in main thread
            ...
        } 
    }

Listing 09: asynchronous CDI event “fire & forget”

@ApplicationScoped 
public class MyAsyncObserverBean { 

    public void callMe(@ObservesAsync SomePayload payload) {
 
       // BTW: this is another thread 
    } 
}

Listing 10: asynchronous CDI observer

As mentioned As mentioned before not only the CDI API but also the BeanValidation API got some face-lift. As most of the Java EE related APIs also BeanValidation supports new Java 8 types (LocalTime and Optional) and features (lambdas, repeating qualifiers, type annotations). In addition, there is a wide range of new BeanValidation constraints available (e.g. @NotBlank, @NotEmpty, @Email, @Past, @Future, @Negative, @Positive, …).

Conclusion

Even if Java EE 8 is not the most innovative and revolutionary release of the Java Enterprise Edition history, it is still an important milestone on a suitable path into the future. Thanks to the consequent focus on the two main mottos “Modern Web Technologies” and “Ease of Development” and the corresponding clearing up and alignment of a lot of APIs, the current edition is one of the most stable JEE releases ever and therefore a perfect baseline for the future: Jakarta EE.

About the Author