4.3. Marshalling to and from Java Objects
Marshalling Java 对象用于通过 HTTP 传输
使用 REST 协议的最常见方法是传输消息正文中 Java bean 的内容。为了实现此目的,您需要有一个机制来划分 Java 对象到合适的数据格式。REST DSL 支持以下数据格式,适用于编码 Java 对象:
- JSON
JSON (JavaScript 对象表示法)是一种轻量级数据格式,可轻松映射到 Java 对象或从 Java 对象进行映射。JSON 语法是紧凑、易于输入的,方便人类读取和写入。因此,JSON 被视为 REST 服务的消息格式。
例如,以下 JSON 代码可以代表一个
User
bean,它有两个属性字段id
和name
:{ "id" : 1234, "name" : "Jane Doe" }
- JAXB
JAXB (用于 XML 绑定的 Java 架构)是一种基于 XML 的数据格式,可以轻松地映射到 Java 对象或从 Java 对象进行映射。要将 XML 放入 Java 对象,您还必须注解要使用的 Java 类。
例如,以下 JAXB 代码可以代表一个
User
bean,它有两个属性字段id
和name
:<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <User> <Id>1234</Id> <Name>Jane Doe</Name> </User>
注意从 Camel 2.17.0 开始,JAXB 数据格式和类型转换器支持从 XML 转换到 POJO (使用
ObjectFactory
而不是XmlRootElement
)。另外,camel 上下文应包含值为 true 的CamelJaxbObjectFactory
属性。但是,由于优化,默认值为 false。
JSON 和 JAXB 与 REST DSL 集成
当然,您可以编写所需的代码,以自行将消息正文转换为 Java 对象或从 Java 对象转换。但是 REST DSL 提供了自动执行此转换的方便。特别是,JSON 和 JAXB 与 REST DSL 集成具有以下优点:
- Marshalling to 和 from Java 对象会自动执行(给定配置)。
- REST DSL 可以自动检测数据格式(JSON 或 JAXB),并执行适当的转换。
- REST DSL 提供了一个抽象层,因此您编写的代码不特定于特定的 JSON 或 JAXB 实施。因此,您可以稍后切换实施,且对应用程序代码的影响最小。
支持的数据格式组件
Apache Camel 提供了很多不同的 JSON 和 JAXB 数据格式实现。REST DSL 目前支持以下数据格式:
JSON
-
Jackson 数据格式(
camel-jackson
) (默认) -
Gson 数据格式(
camel-gson
) -
xstream 数据格式(
camel-xstream
)
-
Jackson 数据格式(
JAXB
-
JAXB 数据格式(
camel-jaxb
)
-
JAXB 数据格式(
如何启用对象划分
要在 REST DSL 中启用对象 marshalling,请观察以下点:
-
启用绑定模式,通过设置
bindingMode
选项(它是多个级别,您可以在其中设置绑定模式来设定详情,请参阅 “配置绑定模式”一节)。 -
在传入消息中使用
type
选项(必需),以及在传出消息中使用outType
选项(可选)指定要转换为的 Java 类型。 - 如果要将 Java 对象转换为 JAXB 数据格式或从 JAXB 数据格式转换,您必须记得使用适当的 JAXB 注释来注释 Java 类。
-
使用
jsonDataFormat
选项和/或xmlDataFormat
选项(可在restConfiguration
构建器中指定),指定底层数据格式实现(或实现实现)。 如果您的路由以 JAXB 格式提供返回值,您通常预期将交换正文的 Out 消息设置为具有 JAXB 注释的类实例(一个 JAXB 元素)。如果您希望以 XML 格式直接提供 JAXB 返回值,但是,请使用键
xml.out.mustBeJAXBElement
设置dataFormatProperty
,使其为false
(可在restConfiguration
构建器中指定)。例如,在 XML DSL 语法中:<restConfiguration ...> <dataFormatProperty key="xml.out.mustBeJAXBElement" value="false"/> ... </restConfiguration>
将所需的依赖项添加到项目构建文件中。例如,如果您使用 Maven 构建系统,并且您使用 Jackson 数据格式,您可以在 Maven POM 文件中添加以下依赖项:
<?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>
将应用程序部署到 OSGi 容器时,请记住要为您选择的数据格式安装必要的功能。例如,如果您使用 Jackson 数据格式(默认),则通过输入以下 Karaf 控制台命令来安装
camel-jackson
功能:JBossFuse:karaf@root> features:install camel-jackson
或者,如果您要部署到 Fabric 环境中,您可以将该功能添加到 Fabric 配置集中。例如,如果您使用配置集
MyRestProfile
,您可以输入以下 console 命令来添加该功能:JBossFuse:karaf@root> fabric:profile-edit --features camel-jackson MyRestProfile
配置绑定模式
bindingMode
选项默认为 off
,因此您必须明确配置它,以便启用 Java 对象的 marshalling。TABLE 显示支持的绑定模式列表。
从 Camel 2.16.3 开始,只有在 content-type 标头包含 json 或 xml 时,才会从 POJO 绑定到 JSon/JAXB。如果消息正文不应尝试使用绑定来总结,这允许您指定自定义 content-type。例如,当消息正文是一个自定义二进制有效负载时,这非常有用。
绑定模式 | 描述 |
---|---|
| 绑定关闭 (默认) |
| 为 JSON 和/或 XML 启用绑定。在此模式中,Camel 根据传入消息的格式自动选择 JSON 或 XML (JAXB)。但是,您不需要 启用这两种类型的数据格式:JSON 实现、XML 实现,也可以在 classpath 上提供。 |
|
仅为 JSON 启用绑定。必须在 classpath 上提供 JSON 实现(默认为 Camel 会尝试启用 |
|
仅为 XML 启用绑定。必须在 classpath 上提供 XML 实现(默认情况下,Camel 会尝试启用 |
| 为 JSON 和 XML 启用绑定。在此模式中,Camel 根据传入消息的格式自动选择 JSON 或 XML (JAXB)。您需要在 classpath 中 提供两种数据格式。 |
在 Java 中,这些绑定模式值以以下 enum
类型的实例表示:
org.apache.camel.model.rest.RestBindingMode
您可以在多个不同的级别设置 bindingMode
,如下所示:
- REST DSL 配置
您可以从
restConfiguration
构建器设置bindingMode
选项,如下所示:restConfiguration().component("servlet").port(8181).bindingMode(RestBindingMode.json);
- 服务定义基础部分
您可以在
rest ()
关键字后面立即设置bindingMode
选项(在 verb 子句前面),如下所示:rest("/user").bindingMode(RestBindingMode.json).get("/{id}").VerbClause
- verb 子句
您可以在 verb 子句中设置
bindingMode
选项,如下所示:rest("/user") .get("/{id}").bindingMode(RestBindingMode.json).to("...");
示例
如需完整的代码示例,演示了如何使用 REST DSL,将 Servlet 组件用作 REST 实施,请仔细查看 Apache Camel camel-example-servlet-rest-blueprint
示例。您可以通过安装独立 Apache Camel 分发 apache-camel-2.21.0.fuse-770013-redhat-00001.zip
来查找这个示例,它在 Fuse 安装的 extras/
子目录中提供。
安装独立 Apache Camel 分发后,您可以在以下目录中找到示例代码:
ApacheCamelInstallDir/examples/camel-example-servlet-rest-blueprint
将 Servlet 组件配置为 REST 实施
在 camel-example-servlet-rest-blueprint
示例中,REST DSL 的底层实现由 Servlet 组件提供。Servlet 组件在 Blueprint XML 文件中配置,如 例 4.1 “为 REST DSL 配置 Servlet 组件” 所示。
例 4.1. 为 REST DSL 配置 Servlet 组件
<?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>
要使用 REST DSL 配置 Servlet 组件,您需要配置由以下三个层组成的堆栈:
- REST DSL 层
-
REST DSL 层由
restConfiguration
元素配置,它通过将 component 属性设置为servlet
的值来
与 Servlet 组件集成。 - Servlet 组件层
-
Servlet 组件层作为类实例实施,
CamelHttpTransportServlet
,其中示例实例具有 bean IDcamelServlet
。 - HTTP 容器层
Servlet 组件必须部署到 HTTP 容器中。Karaf 容器通常配置有默认的 HTTP 容器(Jetty HTTP 容器),该容器侦听端口 8181 上的 HTTP 请求。要将 Servlet 组件部署到默认的 Jetty 容器,您需要执行以下操作:
-
获取对
org.osgi.service.http.HttpService
OSGi 服务的 OSGi 参考,其中此服务是一个标准化的 OSGi 接口,提供对 OSGi 中默认 HTTP 服务器的访问。 -
创建 utility 类
OsgiServletRegisterer
实例,以在 HTTP 容器中注册 Servlet 组件。OsgiServletRegisterer
类是简化 Servlet 组件生命周期的实用程序。创建此类实例时,它会自动在HttpService
OSGi 服务上调用registerServlet
方法;当实例被销毁时,它会自动调用unregister
方法。
-
获取对
所需的依赖项
本例有两个依赖项,它们对 REST DSL 至关重要,如下所示:
- Servlet 组件
提供 REST DSL 的底层实施。这在 Maven POM 文件中指定,如下所示:
<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-servlet</artifactId> <version>${camel-version}</version> </dependency>
在将应用程序捆绑包部署到 OSGi 容器之前,您必须安装 Servlet 组件功能,如下所示:
JBossFuse:karaf@root> features:install camel-servlet
- jackson 数据格式
提供 JSON 数据格式实现。这在 Maven POM 文件中指定,如下所示:
<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-jackson</artifactId> <version>${camel-version}</version> </dependency>
在将应用程序捆绑包部署到 OSGi 容器之前,您必须安装 Jackson 数据格式功能,如下所示:
JBossFuse:karaf@root> features:install camel-jackson
用于响应的 Java 类型
示例应用在 HTTP Request 和 Response 消息中返回 User
type 对象。用户
Java 类定义,如 例 4.2 “用于 JSON 响应的用户类” 所示。
例 4.2. 用于 JSON 响应的用户类
// 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; } }
用户
类以 JSON 数据格式具有相对简单的表示。例如,此类的典型实例以 JSON 格式表示:
{ "id" : 1234, "name" : "Jane Doe" }
使用 JSON 绑定的 REST DSL 路由示例
本例中的 REST DSL 配置和 REST 服务定义显示在 例 4.3 “使用 JSON 绑定的 REST DSL 路由” 中。
例 4.3. 使用 JSON 绑定的 REST DSL 路由
<?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 操作
例 4.3 “使用 JSON 绑定的 REST DSL 路由” 中的 REST 服务定义以下 REST 操作:
GET /camel-example-servlet-rest-blueprint/rest/user/{id}
-
获取
{id}
标识的用户详情,其中 HTTP 响应以 JSON 格式返回。 PUT /camel-example-servlet-rest-blueprint/rest/user
-
创建新用户,其中用户详情包含在 PUT 消息的正文中,以 JSON 格式编码(与
User
对象类型匹配)。 GET /camel-example-servlet-rest-blueprint/rest/user/findAll
- 获取 所有用户 的详情,其中 HTTP 响应以 JSON 格式返回为一组用户。
调用 REST 服务的 URL
通过检查来自 例 4.3 “使用 JSON 绑定的 REST DSL 路由” 的 REST DSL 定义,您可以将调用每个 REST 操作所需的 URL 组合在一起。例如,要调用第一个 REST 操作,它返回具有给定 ID 的用户详情,URL 如下:
http://localhost:8181
-
在
restConfiguration
中,协议默认为http
,端口明确设置为8181
。 /camel-example-servlet-rest-blueprint/rest
-
由
restConfiguration
元素的contextPath
属性指定。 /user
-
由
rest
元素的path
属性指定。 /{id}
-
由
get
verb 元素的uri
属性指定。
因此,可以在命令行中输入以下命令来使用 curl
工具调用此 REST 操作:
curl -X GET -H "Accept: application/json" http://localhost:8181/camel-example-servlet-rest-blueprint/rest/user/123
同样,剩余的 REST 操作可以通过 curl
调用,方法是输入以下示例命令:
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