Create real-time applications with Jakarta EE WebSocket

Last Updated:  November 14, 2019 | Published: November 14, 2019

If your application has real-time requirements like within a chat, the WebSocket technology might be a good fit. With WebSockets, you can create two-way communication channels between a server and a client. The JSR 356 specification defines a standard way of creating and managing WebSocket clients and servers for Java. It's also part of Jakarta EE as Jakarta EE WebSocket with the current version 1.1. Learn how to use the Jakarta EE WebSocket specification within this blog post while writing a small stock exchange application.

Jakarta EE 8 project setup

To create the sample application I make use of one of my Maven Archetypes. The Maven project uses Java 11 and the Jakarta EE platform dependency with version 8.0.0:

Next, I'm using Open Liberty for the runtime. The server.xml to configure Open Liberty is straightforward:

As we are using our own server configuration, the open-liberty:kernel-java11 Docker image fits perfect for the base image:

Creating a WebSocket endpoint

We have two options to create WebSocket endpoints. First, we can create them programmatically while extending the javax.websocket.Endpoint class. Second, we can use the @ServerEndpoint annotation.

For this example, I'm using the approach with annotations. This allows us to use further annotations like @OnOpen, @OnMessage, etc. on methods of our endpoint class. With these we can define how to handle the different lifecycle phases of establishing a connection, sending a message, and closing the connection:

In the example above, I've added a method for each of these lifecycle phases. As we want to broadcast messages to all of our subscribers, later on, we can store all active sessions in a Set. Once a message arrives at our WebSocket endpoint, I'm replying with the same message to the sender using session.getBasicRemote().sendObject(message).

With this setup, our WebSocket endpoint is now available at ws://localhost:9080/stocks and waiting for clients to connect.

Adding support to encode and decode JSON with Jakarta EE

The specification defines only two default data formats for WebSocket messages: Text and Binary.  Fortunately,  Jakarta EE WebSocket allows us to add custom decoders and encoders for our messages. To demonstrate this, I'll create a decoder and encoder for JSON based messages.

Creating a custom encoder is done by implementing either Encoder.Text<T> or Encoder.Binary<T> (or their streaming equivalents). A naive text-based JSON encoder might look like the following:

Writing a custom decoder works similarly. You just have to implement one additional method willDecode(String s) to determine whether or not your decoder is able to decode an incoming message. To determine this, I'm trying to parse the incoming message to a JSON object (there might be better solutions):

Once your custom decoder and encoder are ready to use, you have to configure them in your server endpoint like the following:

With this configuration, we can now accept JsonObject as a message type for our @OnMessage method and also send JsonObject data to our clients.

Connecting to the WebSocket endpoint using Jakarta EE

If you want to connect to a WebSocket endpoint from a different Jakarta EE application, you can create a class with @ClientEndpoint. Within this class you can now use the same lifecycle annotations that you've already seen in the server endpoint (@OnMessage, etc.):

Also, make sure to add your custom decoders and encoders.

Next, to connect the client to an actual endpoint, you can use the WebSocketContainer class and connect to a given URL:

In this example, as I'm printing each client connection and the incoming message to the client, the output looks like the following:

Furthermore, I'm using an EJB timer to broadcast a new WebSocket message every five seconds:

Connecting to the WebSocket endpoint with JavaScript

In addition, we can now connect to our WebSocket endpoint using JavaScript. The WebSocket standard API is part of every browser and can be used right out-of-the-box.

For a short demo, I'm creating a frontend to connect to the endpoint, send messages with a form and display all incoming messages like the following:

Jakarta EE WebSocket example application

Lastly, the JavaScript part to make this work is the following:

You can find the HTML markup for this example on GitHub.

Have fun writing applications with Jakarta EE WebSocket,

Phil

>