1.概述
Apache Camel是一个功能强大的开源集成框架,实现了许多已知的企业集成模式。
通常,在使用Camel处理消息路由时,我们将要使用许多受支持的可插拔数据格式之一。鉴于JSON在大多数现代API和数据服务中都很流行,因此它成为显而易见的选择。
在本教程中,我们将介绍使用camel-jackson
组件将JSON数组编组为Java对象列表的几种方法。
2.依赖关系
首先,让我们将camel-jackson
依赖项添加到我们的pom.xml
:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jackson</artifactId>
<version>3.6.0</version>
</dependency>
然后,我们还将添加专门用于单元测试的camel-test
依赖项,Maven Central也可以提供它:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-test</artifactId>
<version>3.6.0</version>
</dependency>
3.水果领域类
在整个教程中,我们将使用几个简单的POJO对象来建模我们的水果领域。
让我们继续定义一个带有ID和名称的类,以表示水果:
public class Fruit {
private String name;
private int id;
// standard getter and setters
}
接下来,我们将定义一个容器来保存一个Fruit
对象列表:
public class FruitList {
private List<Fruit> fruits;
public List<Fruit> getFruits() {
return fruits;
}
public void setFruits(List<Fruit> fruits) {
this.fruits = fruits;
}
}
在接下来的两节中,我们将了解如何解组表示这些域类中的水果列表的JSON字符串。最终,我们要寻找的是我们可以使用的List<Fruit>
类型的变量。
4.解组JSON FruitList
在第一个示例中,我们将使用JSON格式表示一个简单的水果列表:
{
"fruits": [
{
"id": 100,
"name": "Banana"
},
{
"id": 101,
"name": "Apple"
}
]
}
最重要的是,我们应该强调,此JSON表示一个对象,该对象包含一个名为fruits,
的属性fruits,
该属性包含我们的array 。
现在,让我们设置我们的Apache Camel路由来执行反序列化:
@Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
@Override
public void configure() throws Exception {
from("direct:jsonInput")
.unmarshal(new JacksonDataFormat(FruitList.class))
.to("mock:marshalledObject");
}
};
}
在此示例中,我们使用名称为jsonInput
direct
端点。接下来,我们调用unmarshal
方法,该方法使用指定的数据格式对Camel交换上的消息正文进行解组。
我们正在将JacksonDataFormat
类与自定义解组类型的**FruitList** .
从本质上讲,这是一个围绕Jackon ObjectMapper
的简单包装器,它使我们能够往返于JSON。
最后,我们将unmarshal
方法的结果发送到名为marshalledObject
的mock
端点。正如我们将要看到的,这就是我们将测试路线以查看其是否正常运行的方式。
考虑到这一点,让我们继续编写我们的第一个单元测试:
public class FruitListJacksonUnmarshalUnitTest extends CamelTestSupport {
@Test
public void givenJsonFruitList_whenUnmarshalled_thenSuccess() throws Exception {
MockEndpoint mock = getMockEndpoint("mock:marshalledObject");
mock.expectedMessageCount(1);
mock.message(0).body().isInstanceOf(FruitList.class);
String json = readJsonFromFile("/json/fruit-list.json");
template.sendBody("direct:jsonInput", json);
assertMockEndpointsSatisfied();
FruitList fruitList = mock.getReceivedExchanges().get(0).getIn().getBody(FruitList.class);
assertNotNull("Fruit lists should not be null", fruitList);
List<Fruit> fruits = fruitList.getFruits();
assertEquals("There should be two fruits", 2, fruits.size());
Fruit fruit = fruits.get(0);
assertEquals("Fruit name", "Banana", fruit.getName());
assertEquals("Fruit id", 100, fruit.getId());
fruit = fruits.get(1);
assertEquals("Fruit name", "Apple", fruit.getName());
assertEquals("Fruit id", 101, fruit.getId());
}
}
让我们遍历测试的关键部分以了解发生了什么:
- 首先,我们首先扩展
CamelTestSupport
类-一个有用的测试实用程序基类 - 然后,我们建立了测试期望。我们的
mock
变量应该只有一条消息,消息类型应该是FruitList
- 现在我们准备将JSON输入文件作为
String
发送到我们先前定义的direct
端点 - 检查我们的模拟期望是否满足后,我们可以自由检索
FruitList
并检查其内容是否符合预期
此测试确认我们的路由正常运行,并且按预期对JSON进行了编组。惊人的!
5.解组JSON Fruit
数组
另一方面,我们要避免使用容器对象来保存我们的Fruit
对象。我们可以修改JSON以直接保存一个水果数组:
[
{
"id": 100,
"name": "Banana"
},
{
"id": 101,
"name": "Apple"
}
]
这次,我们的路由几乎相同,但是我们将其设置为专门用于JSON数组:
@Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
@Override
public void configure() throws Exception {
from("direct:jsonInput")
.unmarshal(new ListJacksonDataFormat(Fruit.class))
.to("mock:marshalledObject");
}
};
}
如我们所见,与上一个示例的唯一区别是,我们将ListJacksonDataFormat
类与定制的非编组类型Fruit
。这是直接准备与列表一起使用的Jackson数据格式类型。
同样,我们的单元测试非常相似:
@Test
public void givenJsonFruitArray_whenUnmarshalled_thenSuccess() throws Exception {
MockEndpoint mock = getMockEndpoint("mock:marshalledObject");
mock.expectedMessageCount(1);
mock.message(0).body().isInstanceOf(List.class);
String json = readJsonFromFile("/json/fruit-array.json");
template.sendBody("direct:jsonInput", json);
assertMockEndpointsSatisfied();
@SuppressWarnings("unchecked")
List<Fruit> fruitList = mock.getReceivedExchanges().get(0).getIn().getBody(List.class);
assertNotNull("Fruit lists should not be null", fruitList);
// more standard assertions
}
但是,与上一节中看到的测试相比,存在两个细微的差异:
- 我们首先要设置模拟期望,
List.class
直接包含一个具有List.class
的主体 - 当我们以
List.class
获取消息正文时,我们将收到有关类型安全的标准警告-因此使用@SuppressWarnings(“unchecked”)
六,结论
在这篇简短的文章中,我们已经看到了两种使用骆驼消息路由和camel-jackson
组件解组JSON数组的简单方法。
0 评论