Partner – Microsoft – NPI EA (cat = Baeldung)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, visit the documentation page.

You can also ask questions and leave feedback on the Azure Container Apps GitHub page.

Partner – Microsoft – NPI EA (cat= Spring Boot)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, you can get started over on the documentation page.

And, you can also ask questions and leave feedback on the Azure Container Apps GitHub page.

Partner – Orkes – NPI EA (cat=Spring)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag=Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – MongoDB – NPI EA (tag=MongoDB)
announcement - icon

Traditional keyword-based search methods rely on exact word matches, often leading to irrelevant results depending on the user's phrasing.

By comparison, using a vector store allows us to represent the data as vector embeddings, based on meaningful relationships. We can then compare the meaning of the user’s query to the stored content, and retrieve more relevant, context-aware results.

Explore how to build an intelligent chatbot using MongoDB Atlas, Langchain4j and Spring Boot:

>> Building an AI Chatbot in Java With Langchain4j and MongoDB Atlas

Partner – LambdaTest – NPI EA (cat=Testing)
announcement - icon

Accessibility testing is a crucial aspect to ensure that your application is usable for everyone and meets accessibility standards that are required in many countries.

By automating these tests, teams can quickly detect issues related to screen reader compatibility, keyboard navigation, color contrast, and other aspects that could pose a barrier to using the software effectively for people with disabilities.

Learn how to automate accessibility testing with Selenium and the LambdaTest cloud-based testing platform that lets developers and testers perform accessibility automation on over 3000+ real environments:

Automated Accessibility Testing With Selenium

1. Introduction

In this article, we’re going to look at the quarkus-websockets-next extension for the Quarkus framework. This extension is a new, experimental extension to support WebSockets within our applications.

Quarkus WebSockets Next is a new extension that’s intended to replace the older Quarkus WebSockets extension. This will be easier to use and more efficient than the older extension.

However, unusually for Quarkus, it doesn’t support the Jakarta WebSockets API and instead offers a simplified and more modern API for working with WebSockets. It uses its own annotated classes and methods, providing greater flexibility in functionality while also offering built-in features like JSON support.

At the same time, Quarkus WebSockets Next still builds on top of the standard Quarkus core. This means we get all of the expected performance and scalability we expect, while also benefiting from the development experience that Quarkus offers us.

2. Dependencies

If we’re starting a brand new project, we can use Maven to create our structure with the websockets-next extension already installed:

$ mvn io.quarkus.platform:quarkus-maven-plugin:3.16.4:create \
    -DprojectGroupId=com.baeldung.quarkus \
    -DprojectArtifactId=quarkus-websockets-next \
    -Dextensions='websockets-next'

Note that we need to use io.quarkus.platform:quarkus-maven-plugin for this since the extension is still experimental.

Alternatively, if we’re working with an existing project, we can simply add the appropriate dependency to our pom.xml file:

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-websockets-next</artifactId>
</dependency>

3. Server Endpoints

Once we’ve got our application ready and have the websockets-next extension installed, we’re ready to start using WebSockets.

Server endpoints are created in Quarkus by creating a new class annotated with @WebSocket:

@WebSocket(path = "/echo")
public class EchoWebsocket {
    // WebSocket code here.
}

This will create an endpoint listening on the provided path. As always with Quarkus, we can use path parameters within this if we need, as well as fixed paths.

3.1. Message Callbacks

For our WebSocket endpoint to be useful, we need to be able to handle messages.

WebSocket connections support two types of messages – text and binary. We can handle these in our server endpoint by using methods annotated with either @OnTextMessage or @OnBinaryMessage:

@OnTextMessage
public String onMessage(String message) {
    return message;
}

In this case, we receive the message payload as a method parameter and send the method’s return value to the client. As such, this example is all we need for an echo server – we send back every received message exactly as-is.

If necessary, we can also receive binary payloads instead of text ones. This is done by using the @OnBinaryMessage annotation instead:

@OnBinaryMessage
public Buffer onMessage(Buffer message) {
    return message;
}

In this case, we accept and return an io.vertx.core.buffer.Buffer instance. This will contain the raw bytes of the message received.

3.2. Method Parameters and Returns

As well as our handlers receiving the raw payload of the incoming message, there are many other things that Quarkus is able to pass into our callback messages.

All message handlers must have exactly one parameter that represents the payload of the incoming message. The exact type of this parameter determines how we can access it.

As we saw earlier, if we use Buffer or byte[], we’ll be provided with the exact bytes of the incoming message. If we use a String, these bytes will be decoded into a string first.

We can also use richer objects, though. If we use JsonObject or JsonArray, the incoming message will be treated as JSON and decoded as appropriate. Alternatively, if we use any other type that Quarkus doesn’t support, Quarkus will attempt to deserialize the incoming message as JSON into that type:

@OnTextMessage
public Message onTextMessage(Message message) {
    return message;
}
record Message(String message) {}

We can use all of these same types as return values as well, in which case Quarkus will serialize the messages exactly as expected when sending them back to the client. In addition, a message handler can have a void return to indicate that there will be nothing sent back as a response.

In addition to these, there are some other method parameters that we can accept.

As we’ve seen, an unannotated String parameter will be provided with the message payload. However, we can also have a String parameter annotated with @PathParam to receive the value of this parameter in the incoming URL:

@WebSocket(path = "/chat/:user")
public class ChatWebsocket {

    @OnTextMessage(broadcast = true)
    public String onTextMessage(String message, @PathParam("user") String user) {
        return user + ": " + message;
    }
}

We can also accept a parameter of type WebSocketConnection, which will represent this exact connection between the client and our server:

@OnTextMessage
public Map<String, String> onTextMessage(String message, WebSocketConnection connection) {
    return Map.of(
        "message", message,
        "connection", connection.toString()
    );
}

Using this allows us to access details of the network connection between the client and server – including a unique ID for the connection, when the connection was established, and the path parameters from the URL that was used to connect.

We can also use it to interact with the connection more directly, by sending messages down it or even forcibly closing it:

@OnTextMessage
public void onTextMessage(String message, WebSocketConnection connection) {
    if ("close".equals(message)) {
        connection.sendTextAndAwait("Goodbye");
        connection.closeAndAwait();
    }
}

3.3. OnOpen and OnClose Callbacks

In addition to handlers for receiving messages, we can also register handlers for when a new connection is first opened – using @OnOpen, and for when a connection is closed – using @OnClose:

@OnOpen
public void onOpen() {
    LOG.info("Connection opened");
}

@OnClose
public void onClose() {
    LOG.info("Connection closed");
}

These callback handlers can’t receive any message payloads but can receive any other method parameters as described earlier.

In addition, the @OnOpen handler can have a return value that will be serialized and sent to the client. This is useful for sending a message immediately on connection without waiting for the client to send something first. D0ing this follows all the same rules as return values from message handlers:

@OnOpen
public String onOpen(WebSocketConnection connection) {
    return "Hello, " + connection.id();
}

3.4. Accessing Connections

We’ve already seen that we can have the current connection injected into our callback handlers. However, this isn’t the only way we can access connection details.

Quarkus lets us inject a WebSocketConnection object as a CDI session-scoped bean, using @Inject. This can be injected into any other bean in our system, and we can access the current connection from there:

@ApplicationScoped
public class CdiConnectionService {
    @Inject
    WebSocketConnection connection;
}

However, this only works when called from within the context of a WebSocket handler. If we try to access this from any other context, including a regular HTTP call, then we’ll instead get a jakarta.enterprise.context.ContextNotActiveException thrown.

We can also access all currently open WebSocket connections, by injecting an object of type OpenConnections:

@Inject
OpenConnections connections;

We can then use this not only to query all currently open connections but also to send messages to them:

public void sendToAll(String message) {
    connections.forEach(connection -> connection.sendTextAndAwait(message));
}

Unlike injecting a single WebSocketConnection, this will work correctly from any context. This allows us to access WebSocket connections from any other context if needed.

3.5. Error Handling

In some cases, things can go wrong when we’re processing WebSocket callbacks. Quarkus allows us to handle any exceptions thrown out of these methods by writing exception handler methods. These are any methods annotated with @OnError:

@OnError
public String onError(RuntimeException e) {
    return e.toString();
}

These follow the same rules as other callback handlers regarding the parameters they can receive and their return values. In addition, they must have a parameter representing the exception to handle.

We can write as many of these error handlers as we need, as long as they’re all for different exception classes. If we have any that overlap – in other words, if one is a subclass of another – then the most specific one will be called:

@OnError
public String onIoException(IOException e) {
    // Handles IOException and all subclasses.
}

@OnError
public String onException(Exception e) {
    // Handles Exception and all subclasses except for IOException.
}

4. Client API

As well as allowing us to write server endpoints, Quarkus also allows us to write WebSocket clients that can communicate with other servers.

4.1. Basic Connector

The most basic way to write a WebSocket client is to use the BasicWebSocketConnector. This lets us open a connection and send and receive raw messages.

To start with, we need to inject a BasicWebSocketConnector into our code:

@Inject
BasicWebSocketConnector connector;

We can then use this to connect to a remote service:

WebSocketClientConnection connection = connector
  .baseUri(serverUrl)
  .executionModel(BasicWebSocketConnector.ExecutionModel.NON_BLOCKING)
  .onTextMessage((c, m) -> {
      // Handle incoming messages.
  })
  .connectAndAwait();

As part of this connection, we register a lambda to handle any incoming messages received from the server. This is necessary because of the asynchronous, full-duplex nature of WebSockets. We can’t just treat it as a standard HTTP connection with request and response pairs.

Once we’ve opened our connection, we can use it to send messages to the server as well:

connection.sendTextAndAwait("Hello, World!");

We can do this both from inside our callback handler and from outside it. However, remember that the connection isn’t thread-safe, so we need to ensure that we’re never writing to it by multiple threads at the same time.

In addition to the onTextMessage callback, we can also register callbacks for other lifecycle events, including onOpen() and onClose().

4.2. Rich Client Beans

The basic connector works well enough for simple connections, but sometimes, we need something more flexible than that. Quarkus also allows us to write much richer clients similarly to how we wrote the server endpoints.

To do this, we need to write a new class annotated with @WebSocketClient:

@WebSocketClient(path = "/json")
class RichWebsocketClient {
    // Client code here.
}

Within this class, we then write methods annotated in the same way as for our server endpoints, using annotations such as @OnTextMessage, @OnOpen, and so on:

@OnTextMessage
void onMessage(String message, WebSocketClientConnection connection) {
    // Process message here
}

This follows all of the same rules as for server endpoints regarding method parameters and return values, except that we use WebSocketClientConnection instead of WebSocketConnection if we want to access the connection details.

Once we’ve written our client class, we can use it via an injected WebSocketConnector<T> instance:

@Inject
WebSocketConnector<RichWebsocketClient> connector;

Using this, we create our connection similarly to before, only we don’t need to provide any callbacks since our client instance will handle all of that for us:

WebSocketClientConnection connection = connector
  .baseUri(serverUrl)
  .connectAndAwait();

At this point, we have a WebSocketClientConnection that we can use exactly as before.

If we need to get access to our client instance, we do so by injecting an Instance<T> for the appropriate class:

@Inject
Instance<RichWebsocketClient> clients;

However, we need to remember that this client instance will only be available from the correct contexts, and because it’s all asynchronous, we need to make sure that certain events have already happened.

5. Conclusion

In this article, we’ve seen a brief introduction to WebSockets in Quarkus using the websockets-next extension. We’ve seen how to write both server and client components using this. Here, we’ve only discussed the basics of this library, but it’s capable of handling many more advanced scenarios.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

Partner – Microsoft – NPI EA (cat = Baeldung)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, visit the documentation page.

You can also ask questions and leave feedback on the Azure Container Apps GitHub page.

Partner – Microsoft – NPI EA (cat = Spring Boot)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, visit the documentation page.

You can also ask questions and leave feedback on the Azure Container Apps GitHub page.

Partner – Orkes – NPI EA (cat = Spring)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag = Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Partner – MongoDB – NPI EA (tag=MongoDB)
announcement - icon

Traditional keyword-based search methods rely on exact word matches, often leading to irrelevant results depending on the user's phrasing.

By comparison, using a vector store allows us to represent the data as vector embeddings, based on meaningful relationships. We can then compare the meaning of the user’s query to the stored content, and retrieve more relevant, context-aware results.

Explore how to build an intelligent chatbot using MongoDB Atlas, Langchain4j and Spring Boot:

>> Building an AI Chatbot in Java With Langchain4j and MongoDB Atlas

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

eBook Jackson – NPI EA – 3 (cat = Jackson)