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
andname
:{ "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
andname
:<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <User> <Id>1234</Id> <Name>Jane Doe</Name> </User>
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:
- 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”). - Specify the Java type to convert to (or from), on the incoming message with the
type
option (required), and on the outgoing message with theoutType
option (optional). - 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.
- Specify the underlying data format implementation (or implementations), using the
jsonDataFormat
option and/or thexmlDataFormat
option (which can be specified on therestConfiguration
builder). - 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
, tofalse
(which can be specified on therestConfiguration
builder). For example, in the XML DSL syntax:<restConfiguration ...> <dataFormatProperty key="xml.out.mustBeJAXBElement" value="false"/> ... </restConfiguration>
- 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>
- 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.
Binding Mode | Description |
---|---|
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 therestConfiguration
builder, as follows:restConfiguration().component("servlet").port(8181).bindingMode(RestBindingMode.json);
- Service definition base part
- You can set the
bindingMode
option immediately following therest()
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.15.1.redhat-621084.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 thecomponent
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:
- 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. - Create an instance of the utility class,
OsgiServletRegisterer
, to register the Servlet component in the HTTP container. TheOsgiServletRegisterer
class is a utility that simplifies managing the lifecycle of the Servlet component. When an instance of this class is created, it automatically calls theregisterServlet
method on theHttpService
OSGi service; and when the instance is destroyed, it automatically calls theunregister
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 tohttp
and the port is set explicitly to8181
. -
/camel-example-servlet-rest-blueprint/rest
- Specified by the
contextPath
attribute of therestConfiguration
element. -
/user
- Specified by the
path
attribute of therest
element. -
/{id}
- Specified by the
uri
attribute of theget
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