Skip to content

Latest commit

 

History

History
174 lines (127 loc) · 8.49 KB

java_json.adoc

File metadata and controls

174 lines (127 loc) · 8.49 KB

JSON Libraries

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.

    Refer to the org.eclipse.jetty.util.ajax.JSON javadocs and org.eclipse.jetty.util.ajax.AsyncJSON javadocs for further information.

  • 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 JSON does not expect, and viceversa.

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.

JSONContext API

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.

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 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]
Server Configuration

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.

Oort Configuration

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).

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 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]

Customizing Deserialization of JSON objects

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]