6.25.2 Using @ClientWebSocket

The @ClientWebSocket annotation can be used in combination with the WebSocketClient interface to define WebSocket clients.

You can inject a reference to the a WebSocketClient instance using the @Client annotation:

  1. @Inject
  2. @Client("http://localhost:8080")
  3. RxWebSocketClient webSocketClient;

This allows you to use the same service discovery and load balancing features for WebSocket clients.

Once you have a reference to the WebSocketClient interface you can use the connect method to obtain a connected instance of a bean annotated with @ClientWebSocket.

For example consider the following implementation:

WebSocket Chat Example

  1. import io.micronaut.http.HttpRequest;
  2. import io.micronaut.websocket.WebSocketSession;
  3. import io.micronaut.websocket.annotation.ClientWebSocket;
  4. import io.micronaut.websocket.annotation.OnMessage;
  5. import io.micronaut.websocket.annotation.OnOpen;
  6. import io.reactivex.Single;
  7. import java.util.Collection;
  8. import java.util.concurrent.ConcurrentLinkedQueue;
  9. import java.util.concurrent.Future;
  10. @ClientWebSocket("/chat/{topic}/{username}") (1)
  11. public abstract class ChatClientWebSocket implements AutoCloseable { (2)
  12. private WebSocketSession session;
  13. private HttpRequest request;
  14. private String topic;
  15. private String username;
  16. private Collection<String> replies = new ConcurrentLinkedQueue<>();
  17. @OnOpen
  18. public void onOpen(String topic, String username, WebSocketSession session, HttpRequest request) { (3)
  19. this.topic = topic;
  20. this.username = username;
  21. this.session = session;
  22. this.request = request;
  23. }
  24. public String getTopic() {
  25. return topic;
  26. }
  27. public String getUsername() {
  28. return username;
  29. }
  30. public Collection<String> getReplies() {
  31. return replies;
  32. }
  33. public WebSocketSession getSession() {
  34. return session;
  35. }
  36. public HttpRequest getRequest() {
  37. return request;
  38. }
  39. @OnMessage
  40. public void onMessage(
  41. String message) {
  42. replies.add(message); (4)
  43. }

WebSocket Chat Example

  1. import io.micronaut.http.HttpRequest
  2. import io.micronaut.websocket.WebSocketSession
  3. import io.micronaut.websocket.annotation.ClientWebSocket
  4. import io.micronaut.websocket.annotation.OnMessage
  5. import io.micronaut.websocket.annotation.OnOpen
  6. import io.reactivex.Single
  7. import java.util.concurrent.ConcurrentLinkedQueue
  8. import java.util.concurrent.Future
  9. @ClientWebSocket("/chat/{topic}/{username}") (1)
  10. abstract class ChatClientWebSocket implements AutoCloseable { (2)
  11. private WebSocketSession session
  12. private HttpRequest request
  13. private String topic
  14. private String username
  15. private Collection<String> replies = new ConcurrentLinkedQueue<>()
  16. @OnOpen
  17. void onOpen(String topic, String username, WebSocketSession session, HttpRequest request) { (3)
  18. this.topic = topic
  19. this.username = username
  20. this.session = session
  21. this.request = request
  22. }
  23. String getTopic() {
  24. topic
  25. }
  26. String getUsername() {
  27. username
  28. }
  29. Collection<String> getReplies() {
  30. replies
  31. }
  32. WebSocketSession getSession() {
  33. session
  34. }
  35. HttpRequest getRequest() {
  36. request
  37. }
  38. @OnMessage
  39. void onMessage(
  40. String message) {
  41. replies.add(message) (4)
  42. }

WebSocket Chat Example

  1. import io.micronaut.http.HttpRequest
  2. import io.micronaut.websocket.WebSocketSession
  3. import io.micronaut.websocket.annotation.ClientWebSocket
  4. import io.micronaut.websocket.annotation.OnMessage
  5. import io.micronaut.websocket.annotation.OnOpen
  6. import io.reactivex.Single
  7. import java.util.concurrent.ConcurrentLinkedQueue
  8. import java.util.concurrent.Future
  9. @ClientWebSocket("/chat/{topic}/{username}") (1)
  10. abstract class ChatClientWebSocket : AutoCloseable { (2)
  11. var session: WebSocketSession? = null
  12. private set
  13. var request: HttpRequest<*>? = null
  14. private set
  15. var topic: String? = null
  16. private set
  17. var username: String? = null
  18. private set
  19. private val replies = ConcurrentLinkedQueue<String>()
  20. @OnOpen
  21. fun onOpen(topic: String, username: String, session: WebSocketSession, request: HttpRequest<*>) { (3)
  22. this.topic = topic
  23. this.username = username
  24. this.session = session
  25. this.request = request
  26. }
  27. fun getReplies(): Collection<String> {
  28. return replies
  29. }
  30. @OnMessage
  31. fun onMessage(
  32. message: String) {
  33. replies.add(message) (4)
  34. }
1The class is abstract (more on that later) and is annotated with @ClientWebSocket
2The client must implement AutoCloseable and you should ensure that the connection is closed at some point.
3You can use the same annotations as on the server, in this case @OnOpen to obtain a reference to the underlying session.
4The @OnMessage annotation can be used to define the method that receives responses from the server.

You can also define abstract methods that start with either send or broadcast and these methods will be implemented for you at compile time. For example:

WebSocket Send Methods

  1. public abstract void send(String message);

Note by returning void this tells Micronaut that the method is a blocking send. You can instead define methods that return either futures or a Publisher:

WebSocket Send Methods

  1. public abstract io.reactivex.Single<String> send(String message);

The above example defines a send method that returns an Single.

WebSocket Send Methods

  1. public abstract java.util.concurrent.Future<String> sendAsync(String message);

The above example defines a send method that executes asynchronously and returns a Future to access the results.

Once you have defined a client class you can connect to the client socket and start sending messages:

Connecting a Client WebSocket

  1. ChatClientWebSocket chatClient = webSocketClient.connect(ChatClientWebSocket.class, "/chat/football/fred").blockingFirst();
  2. chatClient.send("Hello World!");
For illustration purposes we use blockingFirst() to obtain the client, it is however possible to combine connect (which returns an Flowable) to perform non-blocking interaction via WebSocket.
Using the CLI

If you have created your project using the Micronaut CLI and the default (service) profile, you can use the create-websocket-client command to create an abstract class with WebSocketClient.

  1. $ mn create-websocket-client MyChat
  2. | Rendered template WebsocketClient.java to destination src/main/java/example/MyChatClient.java