Java WebSocket has the capability to interpret message types beyond the standard java.lang.String
. The way it works is through the registration of encoders and decoders on the endpoint.
Let's review our chat server application again. Instead of using hard corded String on the Java, for the actual commands we can elect to use Java enumerations. This is the replacement code:
public enum ChatCommand { LOGIN("Login"), LOGOUT("Logout"), SEND("Send"), RECEIVE("Receive"), UPDATE("Update"); private String text; ChatCommand( String text) { this.text = text; } public static ChatCommand convert( String str) { if ( str != null ) { for ( ChatCommand item: values() ) { if (item.text.equalsIgnoreCase(str)) { return item; } } } return null; } public String asText() { return text; } }
The ChatCommand
is a Java enum
that accepts a text parameter that corresponds to the JavaScript/HTML5 front end. The method
convert()
attempts to parse a case insensitive string in a ChatCommand
. The method
asText()
returns the text. We use both of these methods in the encoder and decoder types.
We now require a new server endpoint with the registration of encoders and decoders:
@ServerEndpoint(value="/chatserver", encoders = ChatCommandEncoder.class, decoders = ChatCommandDecoder.class) public class ChatServerEndpoint { /* ... */ }
The new ChatServerEndpoint
now informs the WebSocket container so that it accepts two types: ChatCommandEncoder
and ChatCommandDecoder
. What do these types actually look like? Actually they are sub interface implementations of the javax.websocket.Encoder
and javax.websocket.Decoder
. The sub interface Encoder.Text
is used for String text representations. Here is the starting implementation for an encoder:
import javax.websocket.*; public class ChatCommandEncoder implements Encoder.Text<ChatCommand> { @Override public String encode(ChatCommand cmd) { return cmd.asText(); } @Override public void init(EndpointConfig config) { } @Override public void destroy() { } }
The ChatCommandEncoder
is a generic sub type of Encoder.Text
interface and the most important method is encode()
, which simply encodes the Java enumeration as a text String. The function for the encoder is to translate the Java type to the WebSocket message type.
An encoder init()
is called from the WebSocket container when the web application starts up. The EndpointConfig
allows advanced developer to customize the encoder's behavior around the configuration. The container will also call the encoder's destroy()
method when the web application gracefully shuts down.
Let's inspect the decoder implementation, which is relatively straightforward too:
import javax.websocket.*; public class ChatCommandDecoder implements Decoder.Text<ChatCommand> { @Override public ChatCommand decode(String s) throws DecodeException { ChatCommand value = ChatCommand.convert(s); if ( value == null) throw new DecodeException(s, "Cannot decode text"); return value; } @Override public boolean willDecode(String s) { return ChatCommand.convert(s) != null; } @Override public void init(EndpointConfig config) { } @Override public void destroy() { } }
The ChatCommandDecoder
is a type of generic sub interface of Decoder.Text
. The method willDecode()
allows the Java WebSocket container to find out if String can be converted. Here we make use the
ChatCommand.convert()
method from earlier. The decode()
method performs the parsing of the input text. If the String cannot be converted, we throw a DecodeException
, rather than just returning a null reference pointer. Finally, the Decoder
types have the same life-cycle methods.
So far we have seen text message based encoders and decoders. There are other types available in Java WebSocket:
Encoder.TextStream
and Decoder.TextStream
are designed for sending and receiving Java objects to a character stream.Encoder.Binary
and Decoder.Binary
are designed for serializing and de-serializing Java objects to and from binary messages.Encoder.BinaryStream
and Decoder.BinaryStream
are designed for writing and reading Java objects to a binary stream.3.137.183.210