CometD 2 JSON Library Pluggability
CometD 2 JSON Library Pluggability
Since version 2.4.0, CometD allows to customize the JSON library that is used to convert incoming JSON into Bayeux messages and generate JSON from Bayeux messages.
There are two implementations available, one based on Jetty's org.eclipse.jetty.util.ajax.JSON class, and the other based on the Jackson library.
The default implementation uses the Jetty library.
The two libraries are among the fastest around and it turns out that, for the CometD specific case, the Jetty library is faster than Jackson in parsing, but slower in generating.
The Jackson library offers a richer API to customize JSON generation and parsing based on annotations, so it may have an advantage if you want to use objects of your custom classes as data of Bayeux messages (instead of using java.util.Map objects). Refer to the Jackson documentation for further details.
Also the Jetty library allows to plug in custom serializers and deserializers, perhaps in a simpler but more invasive way (your custom classes must implement Jetty's library interfaces). Refer to the org.eclipse.jetty.util.ajax.JSON javadocs for further details.
CometD JSONContext API
The JSON library is used by the CometD Java client implementation (see here) to generate JSON from and to parse JSON to org.cometd.bayeux.Message instances.
The JSON library class that performs this generation/parsing on the client must implement org.cometd.common.JSONContext.Client.
Similarly, on the server, a org.cometd.common.JSONContext.Server implementation generates JSON from and parses JSON to org.cometd.bayeux.server.ServerMessage instances.
Client Configuration
On the client, the org.cometd.common.JSONContext.Client instance must be passed directly into the transport configuration; if omitted, the default Jetty library will be used.
For example:
HttpClient httpClient = ...; MapclientOptions = new HashMap (); // Use the Jackson implementation JSONContext.Client jsonContext = new JacksonJSONContextClient(); clientOptions.put(ClientTransport.JSON_CONTEXT, jsonContext); ClientTransport transport = new LongPollingTransport(clientOptions, httpClient); BayeuxClient client = new BayeuxClient(cometdURL, transport);
The org.cometd.common.JSONContext.Client instance may be shared by all client transports (since only one transport will be used at any time).
You can customize the Jackson implementation and add your own serializers/deserializer in the following way:
public class MyJacksonJSONContextClient extends org.cometd.common.JacksonJSONContextClient
{
public MyJacksonJSONContextClient()
{
org.codehaus.jackson.map.ObjectMapper objectMapper = getObjectMapper();
objectMapper.registerModule(new MyModule());
}
private class MyModule extends org.codehaus.jackson.map.module.SimpleModule
{
public MyModule()
{
// Add your custom serializers/deserializers here
addSerializer(Foo.class, new FooSerializer());
}
}
}
Server Configuration
On the server, the full qualified name of a class implementing org.cometd.common.JSONContext.Server may be specified as init-parameter of the CometdServlet (see also here); if omitted, the default Jetty library will be used.
For example:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<servlet>
<servlet-name>cometd</servlet-name>
<servlet-class>org.cometd.server.CometdServlet</servlet-class>
... other parameters
<init-param>
<param-name>jsonContext</param-name>
<param-value>org.cometd.server.JacksonJSONContextServer</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>cometd</servlet-name>
<url-pattern>/cometd/*</url-pattern>
</servlet-mapping>
</web-app>
The class specified must be instantiable using the default parameterless constructor and implement org.cometd.common.JSONContext.Server, and it can be customized by adding serializers/deserializers as explained above.
Portability Considerations
It is possible to switch from one implementation of the JSON library to another - for example from the Jetty library to the Jackson library , provided that the application code is written carefully.
As of version 1.8.4, Jackson can only produce instances of java.util.List when deserializing JSON arrays.
The Jetty library, however, produces Object[] when deserializing JSON arrays.
Similarly, Jackson may produce lava.lang.Integer where the Jetty library produces java.lang.Long.
To write portable application code, use the following code patterns:
Message message = ...; Map<String, Object> data = message.getDataAsMap(); // Expecting a JSON array // WRONGObject[] array = (Object[])data.get("array");// CORRECT Object field = data.get("array"); Object[] array = field instanceof List ? ((List)field).toArray() : (Object[])field; // Expecting a long // WRONGlong value = (Long)data.get("value");// CORRECT long value = ((Number)data.get("value")).longValue();
- Printer-friendly version
- Login to post comments