Java Platform, Enterprise Edition (Java EE) 8 The Java EE Tutorial

## Using Encoders and Decoders

The Java API for WebSocket provides support for converting between WebSocket messages and custom Java types using encoders and decoders. An encoder takes a Java object and produces a representation that can be transmitted as a WebSocket message; for example, encoders typically produce JSON, XML, or binary representations. A decoder performs the reverse function; it reads a WebSocket message and creates a Java object.

This mechanism simplifies WebSocket applications, because it decouples the business logic from the serialization and deserialization of objects.

The following topics are addressed here:

- Implementing Encoders to Convert Java Objects into WebSocket Messages

- Implementing Decoders to Convert WebSocket Messages into Java Objects

### Implementing Encoders to Convert Java Objects into WebSocket Messages

The procedure to implement and use encoders in endpoints follows.

1. Implement one of the following interfaces:

   - `Encoder.Text<T>` for text messages

   - `Encoder.Binary<T>` for binary messages

     These interfaces specify the `encode` method. Implement an encoder class for each custom Java type that you want to send as a WebSocket message.

2. Add the names of your encoder implementations to the `encoders` optional parameter of the `ServerEndpoint` annotation.

3. Use the `sendObject(Object data)` method of the `RemoteEndpoint.Basic` or `RemoteEndpoint.Async` interfaces to send your objects as messages. The container looks for an encoder that matches your type and uses it to convert the object to a WebSocket message.

For example, if you have two Java types (`MessageA` and `MessageB`) that you want to send as text messages, implement the `Encoder.Text<MessageA>` and `Encoder.Text<MessageB>` interfaces as follows:

    public class MessageATextEncoder implements Encoder.Text<MessageA> {
       @Override
       public void init(EndpointConfig ec) { }
       @Override
       public void destroy() { }
       @Override
       public String encode(MessageA msgA) throws EncodeException {
          // Access msgA's properties and convert to JSON text...
          return msgAJsonString;
       }
    }

Implement `Encoder.Text<MessageB>` similarly. Then, add the `encoders` parameter to the `ServerEndpoint` annotation as follows:

    @ServerEndpoint(
       value = "/myendpoint",
       encoders = { MessageATextEncoder.class, MessageBTextEncoder.class }
    )
    public class EncEndpoint { ... }

Now, you can send `MessageA` and `MessageB` objects as WebSocket messages using the `sendObject` method as follows:

    MessageA msgA = new MessageA(...);
    MessageB msgB = new MessageB(...);
    session.getBasicRemote.sendObject(msgA);
    session.getBasicRemote.sendObject(msgB);

As in this example, you can have more than one encoder for text messages and more than one encoder for binary messages. Like endpoints, encoder instances are associated with one and only one WebSocket connection and peer, so there is only one thread executing the code of an encoder instance at any given time.

### Implementing Decoders to Convert WebSocket Messages into Java Objects

The procedure to implement and use decoders in endpoints follows.

1. Implement one of the following interfaces:

   - `Decoder.Text<T>` for text messages

   - `Decoder.Binary<T>` for binary messages

     These interfaces specify the `willDecode` and `decode` methods.

     Note: Unlike with encoders, you can specify at most one decoder for binary messages and one decoder for text messages.

2. Add the names of your decoder implementations to the `decoders` optional parameter of the `ServerEndpoint` annotation.

3. Use the `OnMessage` annotation in the endpoint to designate a method that takes your custom Java type as a parameter. When the endpoint receives a message that can be decoded by one of the decoders you specified, the container calls the method annotated with `@OnMessage` that takes your custom Java type as a parameter if this method exists.

For example, if you have two Java types (`MessageA` and `MessageB`) that you want to send and receive as text messages, define them so that they extend a common class (`Message`). Because you can only define one decoder for text messages, implement a decoder for the `Message` class as follows:

    public class MessageTextDecoder implements Decoder.Text<Message> {
       @Override
       public void init(EndpointConfig ec) { }
       @Override
       public void destroy() { }
       @Override
       public Message decode(String string) throws DecodeException {
          // Read message...
          if ( /* message is an A message */ )
             return new MessageA(...);
          else if ( /* message is a B message */ )
             return new MessageB(...);
       }
       @Override
       public boolean willDecode(String string) {
          // Determine if the message can be converted into either a
          // MessageA object or a MessageB object...
          return canDecode;
       }
    }

Then, add the `decoder` parameter to the `ServerEndpoint` annotation as follows:

    @ServerEndpoint(
       value = "/myendpoint",
       encoders = { MessageATextEncoder.class, MessageBTextEncoder.class },
       decoders = { MessageTextDecoder.class }
    )
    public class EncDecEndpoint { ... }

Now, define a method in the endpoint class that receives `MessageA` and `MessageB` objects as follows:

    @OnMessage
    public void message(Session session, Message msg) {
       if (msg instanceof MessageA) {
          // We received a MessageA object...
       } else if (msg instanceof MessageB) {
          // We received a MessageB object...
       }
    }

Like endpoints, decoder instances are associated with one and only one WebSocket connection and peer, so there is only one thread executing the code of a decoder instance at any given time.

Copyright © 2017, Oracle and/or its affiliates. All rights reserved.