4.3. Marshalling to and from Java Objects

Marshalling Java objects for transmission over HTTP

One of the most common ways to use the REST protocol is to transmit the contents of a Java bean in the message body. In order for this to work, you need to have a mechanism for marshalling the Java object to and from a suitable data format. The following data formats, which are suitable for encoding Java objects, are supported by the REST DSL:
JSON
JSON (JavaScript object notation) is a lightweight data format that can easily be mapped to and from Java objects. The JSON syntax is compact, lightly typed, and easy for humans to read and write. For all of these reasons, JSON has become popular as a message format for REST services.
For example, the following JSON code could represent a User bean with two property fields, id and name:
{
    "id" : 1234,
    "name" : "Jane Doe"
}
JAXB
JAXB (Java Architecture for XML Binding) is an XML-based data format that can easily be mapped to and from Java objects. In order to marshal the XML to a Java object, you must also annotate the Java class that you want to use.
For example, the following JAXB code could represent a User bean with two property fields, id and name:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<User>
  <Id>1234</Id>
  <Name>Jane Doe</Name>
</User>
Note
From Camel 2.17.0, JAXB data format and type converter supports the conversion from XML to POJO for classes, that use ObjectFactory instead of XmlRootElement. Also, the camel context should include the CamelJaxbObjectFactory property with value true. However, due to optimization the default value is false.

Integration of JSON and JAXB with the REST DSL

You could, of course, write the required code to convert the message body to and from a Java object yourself. But the REST DSL offers the convenience of performing this conversion automatically. In particular, the integration of JSON and JAXB with the REST DSL offers the following advantages:
  • Marshalling to and from Java objects is performed automatically (given the appropriate configuration).
  • The REST DSL can automatically detect the data format (either JSON or JAXB) and perform the appropriate conversion.
  • The REST DSL provides an abstraction layer, so that the code you write is not specific to a particular JSON or JAXB implementation. So you can switch the implementation later on, with minimum impact to your application code.

Supported data format components

Apache Camel provides a number of different implementations of the JSON and JAXB data formats. The following data formats are currently supported by the REST DSL:
  • JSON
    • Jackson data format (camel-jackson) (default)
    • GSon data format (camel-gson)
    • XStream data format (camel-xstream)
  • JAXB
    • JAXB data format (camel-jaxb)

How to enable object marshalling

To enable object marshalling in the REST DSL, observe the following points:
  1. Enable binding mode, by setting the bindingMode option (there are several levels at which you can set the binding mode—for details, see the section called “Configuring the binding mode”).
  2. Specify the Java type to convert to (or from), on the incoming message with the type option (required), and on the outgoing message with the outType option (optional).
  3. If you want to convert your Java object to and from the JAXB data format, you must remember to annotate the Java class with the appropriate JAXB annotations.
  4. Specify the underlying data format implementation (or implementations), using the jsonDataFormat option and/or the xmlDataFormat option (which can be specified on the restConfiguration builder).
  5. If your route provides a return value in JAXB format, you are normally expected to set the Out message of the exchange body to be an instance of a class with JAXB annotations (a JAXB element). If you prefer to provide the JAXB return value directly in XML format, however, set the dataFormatProperty with the key, xml.out.mustBeJAXBElement, to false (which can be specified on the restConfiguration builder). For example, in the XML DSL syntax:
    <restConfiguration ...>
      <dataFormatProperty key="xml.out.mustBeJAXBElement"
                          value="false"/>
      ...
    </restConfiguration>
  6. Add the required dependencies to your project build file. For example, if you are using the Maven build system and you are using the Jackson data format, you would add the following dependency to your Maven POM file:
    <?xml version="1.0" encoding="UTF-8"?>
    <project ...>
      ...
      <dependencies>
        ...
        <!-- use for json binding -->
        <dependency>
          <groupId>org.apache.camel</groupId>
          <artifactId>camel-jackson</artifactId>
        </dependency>
        ...
      </dependencies>
    </project>
  7. When deploying your application to the OSGi container, remember to install the requisite feature for your chosen data format. For example, if you are using the Jackson data format (the default), you would install the camel-jackson feature, by entering the following Karaf console command:
    JBossFuse:karaf@root> features:install camel-jackson
    Alternatively, if you are deploying into a Fabric environment, you would add the feature to a Fabric profile. For example, if you are using the profile, MyRestProfile, you could add the feature by entering the following console command:
    JBossFuse:karaf@root> fabric:profile-edit --features camel-jackson MyRestProfile

Configuring the binding mode

The bindingMode option is off by default, so you must configure it explicitly, in order to enable marshalling of Java objects. TABLE shows the list of supported binding modes.
Note
From Camel 2.16.3 onwards the binding from POJO to JSon/JAXB will only happen if the content-type header includes json or xml. This allows you to specify a custom content-type if the message body should not attempt to be marshalled using the binding. This is useful if, for example, the message body is a custom binary payload.

Table 4.2. REST DSL BInding Modes

Binding ModeDescription
off
Binding is turned off (default).
auto
Binding is enabled for JSON and/or XML. In this mode, Camel auto-selects either JSON or XML (JAXB), based on the format of the incoming message. You are not required to enable both kinds of data format, however: either a JSON implementation, an XML implementation, or both can be provided on the classpath.
json
Binding is enabled for JSON only. A JSON implementation must be provided on the classpath (by default, Camel tries to enable the camel-jackson implementation).
xml
Binding is enabled for XML only. An XML implementation must be provided on the classpath (by default, Camel tries to enable the camel-jaxb implementation).
json_xml
Binding is enabled for both JSON and XML. In this mode, Camel auto-selects either JSON or XML (JAXB), based on the format of the incoming message. You are required to provide both kinds of data format on the classpath.
In Java, these binding mode values are represented as instances of the following enum type:
org.apache.camel.model.rest.RestBindingMode
There are several different levels at which you can set the bindingMode, as follows:
REST DSL configuration
You can set the bindingMode option from the restConfiguration builder, as follows:
restConfiguration().component("servlet").port(8181).bindingMode(RestBindingMode.json);
Service definition base part
You can set the bindingMode option immediately following the rest() keyword (before the verb clauses), as follows:
rest("/user").bindingMode(RestBindingMode.json).get("/{id}").VerbClause
Verb clause
You can set the bindingMode option in a verb clause, as follows:
rest("/user")
    .get("/{id}").bindingMode(RestBindingMode.json).to("...");

Example

For a complete code example, showing how to use the REST DSL, using the Servlet component as the REST implementation, take a look at the Apache Camel camel-example-servlet-rest-blueprint example. You can find this example by installing the standalone Apache Camel distribution, apache-camel-2.17.0.redhat-630187.zip, which is provided in the extras/ subdirectory of your JBoss Fuse installation.
After installing the standalone Apache Camel distribution, you can find the example code under the following directory:
ApacheCamelInstallDir/examples/camel-example-servlet-rest-blueprint

Configure the Servlet component as the REST implementation

In the camel-example-servlet-rest-blueprint example, the underlying implementation of the REST DSL is provided by the Servlet component. The Servlet component is configured in the Blueprint XML file, as shown in Example 4.1, “Configure Servlet Component for REST DSL”.

Example 4.1. Configure Servlet Component for REST DSL

<?xml version="1.0" encoding="UTF-8"?>
<blueprint ...>

  <!-- to setup camel servlet with OSGi HttpService -->
  <reference id="httpService" interface="org.osgi.service.http.HttpService"/>

  <bean class="org.apache.camel.component.servlet.osgi.OsgiServletRegisterer"
        init-method="register"
        destroy-method="unregister">
    <property name="alias" value="/camel-example-servlet-rest-blueprint/rest"/>
    <property name="httpService" ref="httpService"/>
    <property name="servlet" ref="camelServlet"/>
  </bean>

  <bean id="camelServlet" class="org.apache.camel.component.servlet.CamelHttpTransportServlet"/>
  ...
  <camelContext xmlns="http://camel.apache.org/schema/blueprint">

    <restConfiguration component="servlet"
                       bindingMode="json"
                       contextPath="/camel-example-servlet-rest-blueprint/rest"
                       port="8181">
      <dataFormatProperty key="prettyPrint" value="true"/>
    </restConfiguration>
    ...
  </camelContext>

</blueprint>
To configure the Servlet component with REST DSL, you need to configure a stack consisting of the following three layers:
REST DSL layer
The REST DSL layer is configured by the restConfiguration element, which integrates with the Servlet component by setting the component attribute to the value, servlet.
Servlet component layer
The Servlet component layer is implemented as an instance of the class, CamelHttpTransportServlet, where the example instance has the bean ID, camelServlet.
HTTP container layer
The Servlet component must be deployed into a HTTP container. The Karaf container is normally configured with a default HTTP container (a Jetty HTTP container), which listens for HTTP requests on the port, 8181. To deploy the Servlet component to the default Jetty container, you need to do the following:
  1. Get an OSGi reference to the org.osgi.service.http.HttpService OSGi service, where this service is a standardised OSGi interface that provides access to the default HTTP server in OSGi.
  2. Create an instance of the utility class, OsgiServletRegisterer, to register the Servlet component in the HTTP container. The OsgiServletRegisterer class is a utility that simplifies managing the lifecycle of the Servlet component. When an instance of this class is created, it automatically calls the registerServlet method on the HttpService OSGi service; and when the instance is destroyed, it automatically calls the unregister method.

Required dependencies

This example has two dependencies which are of key importance to the REST DSL, as follows:
Servlet component
Provides the underlying implementation of the REST DSL. This is specified in the Maven POM file, as follows:
<dependency>
  <groupId>org.apache.camel</groupId>
  <artifactId>camel-servlet</artifactId>
  <version>${camel-version}</version>
</dependency>
And before you deploy the application bundle to the OSGi container, you must install the Servlet component feature, as follows:
JBossFuse:karaf@root> features:install camel-servlet
Jackson data format
Provides the JSON data format implementation. This is specified in the Maven POM file, as follows:
<dependency>
  <groupId>org.apache.camel</groupId>
  <artifactId>camel-jackson</artifactId>
  <version>${camel-version}</version>
</dependency>
And before you deploy the application bundle to the OSGi container, you must install the Jackson data format feature, as follows:
JBossFuse:karaf@root> features:install camel-jackson

Java type for responses

The example application passes User type objects back and forth in HTTP Request and Response messages. The User Java class is defined as shown in Example 4.2, “User Class for JSON Response”.

Example 4.2. User Class for JSON Response

// Java
package org.apache.camel.example.rest;

public class User {

    private int id;
    private String name;

    public User() {
    }

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
The User class has a relatively simple representation in the JSON data format. For example, a typical instance of this class expressed in JSON format is:
{
    "id" : 1234,
    "name" : "Jane Doe"
}

Sample REST DSL route with JSON binding

The REST DSL configuration and the REST service definition for this example are shown in Example 4.3, “REST DSL Route with JSON Binding”.

Example 4.3. REST DSL Route with JSON Binding

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           ...>
  ...
  <!-- a bean for user services -->
  <bean id="userService" class="org.apache.camel.example.rest.UserService"/>

  <camelContext xmlns="http://camel.apache.org/schema/blueprint">

    <restConfiguration component="servlet"
                       bindingMode="json"
                       contextPath="/camel-example-servlet-rest-blueprint/rest"
                       port="8181">
      <dataFormatProperty key="prettyPrint" value="true"/>
    </restConfiguration>

    <!-- defines the REST services using the  base path, /user -->
    <rest path="/user" consumes="application/json" produces="application/json">
      <description>User rest service</description>

      <!-- this is a rest GET to view a user with the given id -->
      <get uri="/{id}" outType="org.apache.camel.example.rest.User">
        <description>Find user by id</description>
        <to uri="bean:userService?method=getUser(${header.id})"/>
      </get>

      <!-- this is a rest PUT to create/update a user -->
      <put type="org.apache.camel.example.rest.User">
        <description>Updates or create a user</description>
        <to uri="bean:userService?method=updateUser"/>
      </put>

      <!-- this is a rest GET to find all users -->
      <get uri="/findAll" outType="org.apache.camel.example.rest.User[]">
        <description>Find all users</description>
        <to uri="bean:userService?method=listUsers"/>
      </get>

    </rest>

  </camelContext>

</blueprint>

REST operations

The REST service from Example 4.3, “REST DSL Route with JSON Binding” defines the following REST operations:
GET /camel-example-servlet-rest-blueprint/rest/user/{id}
Get the details for the user identified by {id}, where the HTTP response is returned in JSON format.
PUT /camel-example-servlet-rest-blueprint/rest/user
Create a new user, where the user details are contained in the body of the PUT message, encoded in JSON format (to match the User object type).
GET /camel-example-servlet-rest-blueprint/rest/user/findAll
Get the details for all users, where the HTTP response is returned as an array of users, in JSON format.

URLs to invoke the REST service

By inspecting the REST DSL definitions from Example 4.3, “REST DSL Route with JSON Binding”, you can piece together the URLs required to invoke each of the REST operations. For example, to invoke the first REST operation, which returns details of a user with a given ID, the URL is built up as follows:
http://localhost:8181
In restConfiguration, the protocol defaults to http and the port is set explicitly to 8181.
/camel-example-servlet-rest-blueprint/rest
Specified by the contextPath attribute of the restConfiguration element.
/user
Specified by the path attribute of the rest element.
/{id}
Specified by the uri attribute of the get verb element.
Hence, it is possible to invoke this REST operation with the curl utility, by entering the following command at the command line:
curl -X GET -H "Accept: application/json" http://localhost:8181/camel-example-servlet-rest-blueprint/rest/user/123
Similarly, the remaining REST operations could be invoked with curl, by entering the following sample commands:
curl -X GET -H "Accept: application/json" http://localhost:8181/camel-example-servlet-rest-blueprint/rest/user/findAll

curl -X PUT -d "{ \"id\": 666, \"name\": \"The devil\"}" -H "Accept: application/json" http://localhost:8181/camel-example-servlet-rest-blueprint/rest/user