Java EE 8 - A Bird's Eye View

Java EE 8 includes a significant amount of changes relevant to Java developers. This is the release that forms the basis for Jakarta EE. In fact, Jakarta EE 8 - released under the stewardship of the Eclipse Foundation - will likely closely mirror Java EE 8. We will overview the changes in Java EE 8 at a high level in this article, including looking at some representative code examples.

A unique characteristic of Java EE 8 is that it has been one of the most community opinion driven major technology release in the history of Java. The scope of Java EE 8 has been determined by not one, but two separate developer surveys - one conducted before Java EE 8 development started and one towards the end of when Java EE 8 was released). As a result, Java EE 8 is a very feature complete release, particularly for applications that do not need fine-grained microservices features on the cloud. Such features have already been brought to the Java EE ecosystem through the Eclipse MicroProfile initiative and might be standardized into Jakarta EE 9 or beyond.

Major Themes

Java EE 8 has several distinguishable themes. Let's briefly look at these themes before we dive into feature details.

  • Web standards alignment
    • HTTP/2, SSE, JSON
  • CDI alignment
    • CDI 2, JSF managed bean pruning, injecting JSF artifacts, CDI support in JPA
  • Simplicity
    • Security, EJB pruning
  • Java SE 8 alignment
    • JSF, JPA, JAX-RS, JMS, Bean Validation, JSON-P, CDI

Java EE alignment with steadily progressing web standards started in Java EE 7 with changes like WebSocket 1.0, JSON-P 1.0, hypermedia support in JAX-RS 2 and JSF 2.2 HTML/5 alignment. The web standards alignment theme continues in Java EE 8 with HTTP/2 support in Servlet 4, SSE (Server-Sent Events) support in JAX-RS 2.1, the introduction of JSON-B and important enhancements to JSON-P.

Since its introduction in Java EE 6, CDI has become a key Java EE technology. The eventual goal is to make CDI the central programming model in Java EE. In Java EE 7, technologies like JSF, JMS, Bean Validation and JTA improved their alignment with CDI. Java EE 8 continues this theme with JSF 2.3, JPA 2.2 and Security 1.0. Also, CDI 2 itself introduces the most significant set of changes to the technology since CDI 1.0 (CDI 1.1 and CDI 1.2 had important but more minor changes).

The simplicity theme started in Java EE 5 and continues with Java EE 8. In each release every remaining possible corner of the platform is simplified as much as possible. The big example of this in Java EE 7 is JMS 2. In Java EE 8 the most significant example is Security 1.0. Thanks to these changes, security is perhaps now simpler in Java EE 8 than any other major server-side technology.

Java EE always takes advantage of as many changes in Java SE as it can. The most obvious example of this is EJB 3/Java EE 5 being the first mainstream technology proving out full-scale adoption of annotations introduced in Java SE 5. There are a number of compelling changes in Java SE 8 and Java EE 8 technologies like JSF 2.3, JPA 2.2, JAX-RS 2.1, Bean Validation 2 and JSON-P 1.1 effectively adapt to these changes.

Servlet 4

Servlet 4 is one of the most important changes in Java EE 8. The principal goal of Servlet 4 is to bring HTTP/2 support to server-side Java. HTTP/2 is a fundamental modernization of the protocol that keeps the internet together.

HTTP was originally designed with a very simple web in mind - a request is expected to produce just one artifact, likely a plain HTML page with some hyperlinks. The web today is far more complex. A single page contains many possible dependent resources - images, style-sheets, scripts, videos and so on. As a result, we currently lose a lot of performance as each dependent resource is retrieved through a separate HTTP request. HTTP/2 is aimed to boost web performance manifolds by fixing this impedance mismatch. HTTP/2 accomplishes this by allowing the transfer of a number of resources from the server over a single initial TCP connection. Each resource is multiplexed into a separate, appropriately prioritized stream within the connection. HTTP/2 also uses binary framing for significantly improved bandwidth usage as well as header sharing/compression across related resources. Lastly HTTP/2 includes a mechanism called server-push to proactively send down all dependent resources from the server with the initial page request without the browser even parsing any HTML.

Because these are largely protocol layer changes, they can be transparently handled by the Servlet 4 runtime without any API changes. The Servlet 4 certification tests that a container properly implements HTTP/2. This is very important since no other certification process for HTTP/2 exists. Servlet 4 does introduce a simple, backward-compatible API change to enable server-push. However even this change is transparently absorbed at a lower level in the case of JSF 2.3/Java EE 8 users.

JSON-B (Java API for JSON Binding)

Making JSON a first-class citizen of the platform has been a goal since Java EE 7. Using JSON should not require installing or configuring yet another library. To that end a low-level parsing API called JSON-P (Java API for JSON Processing) was introduced in Java EE 7. Java EE 8 introduces a higher-level annotation based declarative JSON binding API called JSON-B that really makes it feel like JSON is as native as Java serialization in Java EE. The idea is that converting POJOs to/from JSON should just work by default without needing to add any annotations. JSON-B does include a small number of annotations to customize default mappings such as @JsonbProperty (to rename fields) and @JsonbTransient (for fields to be ignored by serialization). The example below shows these concepts in action.

@GET ... 

@Produces("application/json") 

public Person getPerson(...) { 

    ... 

    Person duke = new Person(); 

    duke.setName("Duke"); 

    duke.setGender("Male"); 

    phones = new HashMap<>(); 

    phones.put("home", "650-123-4567"); 

    phones.put("mobile", "650-234-5678"); 

    duke.setPhones(phones); 

 

    return duke; 

} 

In the example above, the Person POJO does not have any JSON-B annotations. Because JAX-RS 2.1 integrates JSON-B in Java EE 8 (and JSON-P for that matter), the Person POJO will be automatically converted to the JSON below in the HTTP response as the output is specified to be of type "application/json".

{"name":"Duke", 

 "gender":"Male", 

 "phones":{ 

     "home":"650-123-4567", 

     "mobile":"650-234-5678"}}

JSON-P 1.1

JSON-P was fairly feature complete in Java EE 7. In Java EE 8 JSON-P incorporated updates in the web standards space such as JSON-Pointer, JSON-Patch and JSON-Merge/Patch. JSON-Pointer allows looking up values in a JSON structure using a URL like path. JSON-Patch is very similar to the concept of HTTP PATCH. It allows for issuing commands to modify parts of a JSON document in a generic fashion (the commands themselves are JSON objects). JSON-Patch depends on JSON-Pointer to reference locations in a JSON structure. JSON-Merge/Patch is similar to JSON-Patch but offers capabilities to do sophisticated merges and diffs of JSON structures.

The best way to explore some these features is through a simple example. Let's start with the following JSON structure:

[{"name":"Duke", 

  "gender":"Male", 

  "phones":{ 

      "home":"650-123-4567", 

      "mobile":"650-234-5678"}}, 

 {"name":"Jane", 

  "gender":"Female", 

  "phones":{ 

      "mobile":"707-555-9999"}}]

The following shows how two JSON-Patch commands to modify the above JSON structure looks like. The first command updates the mobile phone number for "Duke". The second command removes "Jane" from the list of persons. /0/phones/mobile and /1 are examples of JSON-Pointers. Aside from replace and remove, JSON-Patch supports operations like add, move, copy and test.

[{"op": "replace", "path":"/0/phones/mobile",  

    "value":"650-111-2222"}, 

 {"op": "remove", "path":"/1"}]

The following is how the JSON-P 1.1 code to apply these JSON-Patch operations looks like. The target object holds the JSON-P structure for the persons array. As you can see, the JSON-P API utilizes the builder pattern for usability.

JsonPatchBuilder builder = new JsonPatchBuilder(); 

JsonArray result = builder 

    .replace("/0/phones/mobile", "650-111-2222") 

    .remove("/1") 

    .apply(target);

SSE (Server-Sent Events)

SSE is a lesser-known part of HTML 5. SSE allows for server-to-client streaming of events over HTTP. Under the hood SSE is just a long-lived HTTP connection that uses a specialized content-type: text/event-stream. Events are typically distinct JSON objects sent from the server to the client over time. SSE is useful for "stock ticker" type applications and monitoring consoles. SSE is supported both on the server and client side in Java EE 8 using JAX-RS 2.1. The following is a server-side example:

@Path("tickers") 

public class StockTicker { 

    @Resource ManagedExecutorService executor; 

 

    @GET @Produces("text/event-stream") 

    public void getQuotes( 

            @Context SseEventSink sink,  

            @Context Sse sse) { 

        executor.execute(() -> { 

            ... 

            sink.send(sse.newEvent(stockqoute)); 

            ... 

        }); 

    } 

} 

In the example a browser would connect to the server using the "tickers" endpoint, typically using the JavaScript SSE client API. The JAX-RS 2.1 endpoint produces a series of stock quote updates in a background thread and sends them to the client over an SSE event sink connection pipe using the Sse event builder utility. Aside from a one-to-one connection between an endpoint and a client, JAX-RS 2.1 also supports broadcasting the same SSE event to multiple connected clients.

Java EE Security

Prior to Java EE 8, securing Java EE applications was largely done through configuration tools outside the application geared towards administrators such as console GUI wizards. The principal downside of this approach is that it is not very portable across Java EE implementations, although some security needs are very common. The goal of the new Java EE Security API is to make common, simple security needs portable by introducing fully embeddable authentication and authorization. This is accomplished by fully embracing annotations and CDI. At a high level, three new features are introduced:

  • It is possible to specify through simple annotations whether the application uses basic, form based or custom authentication.
  • It is possible through simple annotations to specify that authentication and authorization (identity) data is stored in the database or LDAP directory. The reference implementation also includes a built-in embedded identity store. If the built-in identity stores are not enough, it is possible to have a simple CDI bean in the application act as an identity store.
  • A universal security context is made available through CDI injection. This context provides a handle to information about the currently logged-in user that can be used anywhere including in custom security interceptors. This is in addition to the existing @RolesAlllowed annotation.

The following annotation example that specifies database security is illustrative of just how simple Java EE 8 security is.

@DataBaseIdentityStoreDefinition ( 

    dataSourceLookup="java:global/MyDB",  

    callerQuery= 

        "SELECT password FROM principals WHERE username=?",  

    groupsQuery="SELECT role FROM roles where username=?", ...)

The further features that could be standardized in a next revision of Java EE Security includes making @RolesAllowed available to any CDI bean, introducing EL-enabled security annotations and standardizing JWT.

CDI 2

One of the key changes in CDI 2 is the standardization of a bootstrap mechanism in plain Java SE environments. This has meant breaking CDI up into three parts - core, Java SE and Java EE. These changes enable CDI to be adopted by more technologies - inside and outside Java EE. For example, these changes have enabled CDI to be used as a core technology for the MicroProfile initiative. Another key change in CDI 2 is making events completely asynchronous. The following example shows the feature.

@Inject @CargoInspected Event<Cargo> cargoInspected; 

... 

public void inspectCargo(TrackingId trackingId) { 

    ... 

    cargoInspected.fireAsync(cargo); 

} 
 
public void onCargoInspected( 

    @ObservesAsync @CargoInspected Cargo cargo) {

The inspectCargo method thread gets control back immediately after the fireAsync method is invoked. The onCargoInspected observer method is invoked on a completely separate thread. As of CDI 2, events can also be assigned priority order. CDI 2 also made several simplifications to its extensibility APIs to further encourage the CDI plugin ecosystem. Lastly, CDI 2 adapts to Java SE 8 features such as lambdas, completable future, streams and repeatable annotations (more on this in the following sections).

Beyond the changes in CDI 2 itself, a number of technologies improved their alignment with CDI in Java EE 8. For example, JSF 2.3 makes key artefacts like the FacesContext CDI injectable and deprecates its own older managed bean model in favor of CDI. JPA 2.2 also improved its alignment with CDI by making artefacts like attribute converters CDI injection capable.

A key piece of CDI alignment had been slated for Java EE 8 through JMS 2.1. JMS 2.1 was aimed at creating a CDI based JMS listener model to replace EJB message driven beans. Similarly, EJB annotations like @Asynchronous and @Schedule could be made available to all CDI beans through the Java EE Concurrency Utilities. Unfortunately, Oracle decided to discontinue this work for Java EE 8. This is likely work that might be done as part of Jakarta EE 9. Fortunately, some work towards deprecating EJB was done in Java EE 8 such as pruning CORBA interoperability.

Adopting Java SE 8

Java SE 8 includes a number of important changes such as lambdas, streams, the date-time API, completable futures and repeatable annotations. Most of these features, especially lambdas, can be used as-is in Java EE applications. In cases where it is needed, a significant theme for Java EE 8 is to adapt to Java SE 8 features.

Repeatable Annotations

Prior to Java SE 8, it was not possible to repeat annotations. As a result, where annotations needed to be repeated, Java EE used wrapper annotations such as in the example below:

@NamedQueries({ 

    @NamedQuery(name=SELECT_ALL, query="..."), 

    @NamedQuery(name=COUNT_ALL, query="...")}) 

public class Customer { 

As of Java SE 8, such annotations have been adapted to be repeatable as below.

@NamedQuery(name=SELECT_ALL, query="...") 

@NamedQuery(name=COUNT_ALL, query="...") 

public class Customer { 

The technologies in Java EE 8 that have adapted to repeatable annotations include JPA, JMS, JavaMail, Bean Validation, EJB and CDI.

Date-Time API

The new Java SE 8 date-time API is more feature complete, easy-to-use and internationalized compared to the older Java SE date and calendar functionality. As the following example shows, both JPA 2.2 and Bean Validation 2 have been updated in Java EE 8 to natively support the date-time API.

@Entity 

public class Accident { 

    ... 

    @Temporal(TemporalType.TIMESTAMP) 

    @Past 

    private Instant when; 

    ... 

} 

JPA 2.2 knows how to properly read the when field of type Instant from the database and write it back. Similarly, all Bean Validation 2 annotations including @Past and @Future correctly validate date-time API types. JSF 2.3 can also correctly convert and validate all date-time types without any additional code.

Completable Future

Java SE 8 completable futures bring JavaScript promises to Java. Compared to the older Java SE Future interface, completable futures are non-blocking, lambda friendly and composable. These characteristics tend to be very important while asynchronously invoking interrelated RESTful endpoints that are part of a microservices based system. These are the reasons the JAX-RS 2.1 client API has been adapted to make use of completable futures. The following example shows the feature.

CompletionStage<Assets> getAssets = client 

                               .target("assets/{ssn}") 
                               .resolveTemplate("ssn", person.getSsn()) 
                               .request("application/json")  
                               .rx() 
                               .get(Assets.class); 

CompletionStage<Liabilities> getLiabilities = client 

                               .target("liabilities/{ssn}") 
                               .resolveTemplate("ssn", person.getSsn()) 
                               .request("application/json")  
                               .rx() 
                               .get(Liabilities.class); 

Coverage coverage = getAssets.thenCombine(getLiabitities,  

    (assets, liabilities) -> underwrite(assets, liabilities)) 

        .toCompletableFuture().join();

Streams

Java SE 8 streams utilize lambdas to provide high performance, concise aggregate operations on collections of objects. Operations include filter, transform, sum, average, min, max and sort. JPA 2.2 query results can now return streams. The following example shows the feature.

Stream<Book> books = entityManager.createQuery( 

    "SELECT b FROM Book b", Book.class).getResultStream(); 

books.map(b -> b.getTitle() + " was published on " + b.getPublishingDate()) 

    .forEach(s -> log.info(s));

JSON-P 1.1 was also adapted to easily convert between JSON arrays and streams.

Aside from these headline features, Java EE 8 contains a lot more that you should look into yourself. For example, JSF 2.3 provides a very easy way to use WebSocket, Bean Validation 2 adds new constraints like @Email, @NotEmpty, @NotBlank, @Positive, @PositiveOrZero, @Negative, @NegativeOrZero, @PastOrPresent, @FutureOrPresent and much more.

MVC

The oldest web framework in the Java space - Struts - was action based. Struts creator Craig McClanahan helped create JSF and supported a highly abstract component-based approach closest to the original Smalltalk MVC pattern. While JSF continues to have a strong following, action-based frameworks continue to move forward even after Craig's recommendation to move to JSF. More recently some developers feel that the action-based approach is particularly well suited to a HTML 5/JavaScript centric web ecosystem. For these reasons, Java EE 8 had been slated to include a new action-based framework - simply called MVC - in addition to JSF.

Constructing MVC in Java EE is relatively simple as most of the basic pieces are already there. CDI, Bean Validation and JPA can be utilized for the model. Facelets and JSP can be used for views (in addition the MVC reference implementation has support for Velocity, FreeMarker, Thymeleaf, etc). A majority of the controller functionality can utilize JAX-RS.

Despite the fact that the MVC specification had been making rapid progress, Oracle decided to discontinue this work. However, Oracle donated the work to the community, MVC is now almost complete via the community and it is also being transferred to the Eclipse Foundation. It is possible Jakarta EE will include MVC although Java EE 8 does not.

Summary

Java EE 8 includes a number of important features important to the community and industry. In addition, Java EE is headed to a far more open future under the Eclipse Foundation as Jakarta EE. The reference implementation, GlassFish 5, is fully Java EE 8 compatible. Because it is based on GlassFish 5, Payara 5 also includes all Java EE 8 functionality. In addition, Open Liberty, WebSphere Liberty and WildFly now all support Java EE 8. It is reasonable to believe JBoss EAP and TomEE are also on their way to supporting either Java EE 8 or Jakarta EE 8. You should consider evaluating and adopting Java EE 8 right now.

About the Author