CometD allows you to customize the JSON library that it uses to convert incoming JSON into Bayeux messages and generate JSON from Bayeux messages.
Two implementations are available, one based on Jetty’s jetty-util-ajax
library, mainly classes org.eclipse.jetty.util.ajax.JSON
and org.eclipse.jetty.util.ajax.AsyncJSON
, and the other based on the Jackson library.
The default implementation uses the Jetty library.
Distinctions between them include:
-
The Jetty library allows you to plug in custom serializers and deserializers, to fine control the conversion from object to JSON and vice versa, via a custom API.
-
The Jackson library offers a rich API based on annotations to customize JSON generation, but less so to customize JSON parsing and obtain objects of custom classes.
Jackson does not support out-of-the-box collections created with the collection factory methods introduced in Java 9, such as
Map.of()
,List.of()
, etc.Jackson may add additional metadata fields and make the JSON messages larger.
Refer to the Jackson documentation for further details.
Important
|
It is recommended that you use the same JSON library on both client and server. Mixed configurations may not work because, for example, Jackson may add additional metadata fields, or change the structure of fields, that Jetty’s Jetty’s JSON is recommended as it typically produces smaller JSON, it is simpler to configure and customize, supports Java 9 and later collections, and it has very good performance. |
The CometD Java client implementation (see also the client section) uses the JSON library 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.server.JSONContextServer
implementation generates JSON from and parses JSON to org.cometd.bayeux.server.ServerMessage
instances.
On the client, the org.cometd.common.JSONContext.Client
instance must be passed directly into the transport configuration; if omitted, the default Jetty JSON library is used.
For example:
link:{doc_code}/JSONDocs.java[role=include]
All client transports can share the org.cometd.common.JSONContext.Client
instance (since only one transport is used at any time).
The JSONContext.Server
and JSONContext.Client
classes also offer methods to obtain a JSON parser (to deserialize JSON into objects) and a JSON generator(to generate JSON from objects), so that the application does not need to hardcode the usage of a specific implementation library.
Class JSONContext.Parser
can be used to convert into objects any JSON that the application needs to read for other purposes, for example from configuration files, and of course convert into custom objects (see also the JSON customization section):
link:{doc_code}/JSONDocs.java[role=include]
Similarly, objects can be converted into JSON:
link:{doc_code}/JSONDocs.java[role=include]
On the server, you can specify the fully qualified name of a class implementing org.cometd.server.JSONContextServer
as init-parameter
of the CometDServlet
(see also the server configuration section); if omitted, the default Jetty library is used.
For example:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<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>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</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 it must implement org.cometd.server.JSONContextServer
.
You can customize it by adding serializers/deserializers as explained above.
In the Oort clustering (see also the Oort section), an Oort
instance need to have both the server and the client JSONContext
: the server one to deserialize messages that other Oort comets send, and the client one to serialize messages to send to other Oort comets.
The Oort
instance will use the JSONContext.Server
already configured for the server, as explained in the JSON server configuration section.
The Oort
instance will use of the JSONContext.Client
specified in the configuration (see also the Oort common configuration section).
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 you write the application code carefully.
Jackson may produce instances of java.util.List
when deserializing JSON arrays.
The Jetty library, however, produces java.lang.Object[]
when deserializing JSON arrays.
Similarly, Jackson may produce java.lang.Integer
where the Jetty library produces java.lang.Long
.
To write portable application code, use the following code patterns:
link:{doc_code}/JSONDocs.java[role=include]
Sometimes it is very useful to be able to obtain objects of application classes instead of just Map<String, Object>
when calling message.getData()
.
You can easily achieve this with the Jetty JSON library.
It is enough that the client formats the JSON object by adding a class
field whose value is the fully qualified class name that you want to convert the JSON to:
cometd.publish("/echo", {
class: "org.cometd.example.EchoInfo",
id: "42",
echo: "cometd"
});
On the server, in the web.xml
file, you register the org.cometd.server.JettyJSONContextServer
as jsonContext
(see also the JSON server configuration section), and at start-up you add a custom converter for the org.cometd.example.EchoInfo
class (see also the services integration section for more details about configuring CometD at start-up).
link:{doc_code}/JSONDocs.java[role=include]
Note also that for historical reasons, Jetty’s JSON
and AsyncJSON
classes deserialize JSON arrays differently, respectively as Object[]
and as List
.
However, it is possible to configure both classes with a custom function that performs array conversion, so that JSON arrays can be represented in the same way by both classes:
link:{doc_code}/JSONDocs.java[role=include]
Finally, these are the EchoInfoConvertor
and EchoInfo
classes:
link:{doc_code}/JSONDocs.java[role=include]
If, instead of using the JavaScript client, you are using the Java client, it is possible to configure the Java client to perform the serialization/deserialization of JSON objects in the same way (see also the JSON client configuration section):
link:{doc_code}/JSONDocs.java[role=include]