Unmarshalling a JSON Array Using camel-jackson – 使用camel-jackson解除对JSON数组的洗牌

最后修改: 2020年 12月 18日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Apache Camel is a powerful open-source integration framework implementing a number of the known Enterprise Integration Patterns.

Apache Camel是一个强大的开源集成框架,实现了许多已知的企业集成模式

Typically when working with message routing using Camel, we’ll want to use one of the many supported pluggable data formats. Given that JSON is popular in most modern APIs and data services, it becomes an obvious choice.

通常情况下,在使用Camel进行消息路由时,我们希望使用众多支持的可插拔数据格式中的一种。鉴于JSON在大多数现代API和数据服务中都很流行,它就成了一个明显的选择。

In this tutorial, we’ll take a look at a couple of ways we can unmarshal a JSON Array into a list of Java objects using the camel-jackson component.

在本教程中,我们将看看有哪些方法可以使用camel-jackson组件将JSON数组解密为一个Java对象的列表。

2. Dependencies

2.依赖性

First, let’s add the camel-jackson dependency to our pom.xml:

首先,让我们将camel-jackson依赖性添加到我们的pom.xml

<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-jackson</artifactId>
    <version>3.6.0</version>
</dependency>

Then, we’ll also add the camel-test dependency specifically for our unit tests, which is available from Maven Central as well:

然后,我们还要为我们的单元测试专门添加camel-test依赖,该依赖也可以从Maven中心获得。

<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-test</artifactId>
    <version>3.6.0</version>
</dependency>

3. Fruit Domain Classes

3.水果领域类

Throughout this tutorial, we’ll use a couple of light POJO objects to model our fruit domain.

在整个教程中,我们将使用几个轻型的POJO对象来为我们的水果领域建模。

Let’s go ahead and define a class with an id and a name to represent a fruit:

让我们继续定义一个带有id和name的类来代表一个水果。

public class Fruit {

    private String name;
    private int id;

    // standard getter and setters
}

Next, we’ll define a container to hold a list of Fruit objects:

接下来,我们将定义一个容器来容纳一个Fruit对象的列表。

public class FruitList {

    private List<Fruit> fruits;

    public List<Fruit> getFruits() {
        return fruits;
    }

    public void setFruits(List<Fruit> fruits) {
        this.fruits = fruits;
    }
}

In the next couple of sections, we’ll see how to unmarshal a JSON string representing a list of fruits into these domain classes. Ultimately what we are looking for is a variable of type List<Fruit> that we can work with.

在接下来的几节中,我们将看到如何将一个代表水果列表的JSON字符串解读为这些域类。最终我们要寻找的是一个我们可以使用的List<Fruit>类型的变量

4. Unmarshalling a JSON FruitList

4.解除对JSON FruitList的洗牌

In this first example, we’re going to represent a simple list of fruit using JSON format:

在这第一个例子中,我们要用JSON格式来表示一个简单的水果列表。

{
    "fruits": [
        {
            "id": 100,
            "name": "Banana"
        },
        {
            "id": 101,
            "name": "Apple"
        }
    ]
}

Above all, we should emphasize that this JSON represents an object which contains a property called fruits, which contains our array.

最重要的是,我们应该强调,这个JSON代表一个对象,其中包含一个名为fruits的属性,其中包含我们的数组

Now let’s set up our Apache Camel route to perform the deserialization:

现在我们来设置我们的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");
        }
    };
}

In this example, we use direct endpoint with the name jsonInput. Next, we call the unmarshal method, which unmarshals the message body on our Camel exchange using the specified data format.

在这个例子中,我们使用direct端点,名称为jsonInput。接下来,我们调用unmarshal方法,该方法使用指定的数据格式对Camel交换的消息体进行解密。

We’re using the JacksonDataFormat class with a custom unmarshal type of FruitList. This is essentially a simple wrapper around the Jackon ObjectMapper and lets us marshal to and from JSON.

我们使用的是JacksonDataFormat类,其自定义的解封类型为FruitList这基本上是一个围绕Jackon ObjectMapper的简单包装,让我们可以从JSON中进行marshal。

Finally, we send the result of the unmarshal method to a mock endpoint called marshalledObject. As we’re going to see, this is how we’ll test our route to see if it is working correctly.

最后,我们将unmarshal方法的结果发送到mock端点,称为marshalledObject。正如我们将要看到的,这就是我们如何测试我们的路由,看它是否工作正常。

With that in mind, let’s go ahead and write our first unit test:

考虑到这一点,让我们继续写我们的第一个单元测试。

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());
    }
}

Let’s walk through the key parts of our test to understand what is going on:

让我们走过我们测试的关键部分,以了解发生了什么。

  • First things first, we start by extending the CamelTestSupport class –  a useful testing utility base class
  • Then we set up our test expectations. Our mock variable should have one message, and the message type should be a FruitList
  • Now we’re ready to send out the JSON input file as a String to the direct endpoint we defined earlier
  • After we check our mock expectations have been satisfied, we are free to retrieve the FruitList and check the contents is as expected

This test confirms that our route is working properly and our JSON is being unmarshalled as expected. Awesome!

这个测试证实了我们的路由工作正常,而且我们的JSON正在按照预期被解调。棒极了!

5. Unmarshalling a JSON Fruit Array

5.解除对JSON Fruit数组的洗牌

On the other hand, we want to avoid using a container object to hold our Fruit objects. We can modify our JSON to hold a fruit array directly:

另一方面,我们想避免使用容器对象来容纳我们的Fruit对象。我们可以修改我们的JSON来直接容纳一个水果数组。

[
    {
        "id": 100,
        "name": "Banana"
    },
    {
        "id": 101,
        "name": "Apple"
    }
]

This time around, our route is almost identical, but we set it up to work specifically with a JSON array:

这一次,我们的路线几乎是相同的,但我们把它设置为专门与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");
        }
    };
}

As we can see, the only difference to our previous example is that we’re using the ListJacksonDataFormat class with a custom unmarshal type of Fruit. This is a Jackson data format type prepared directly to work with lists.

正如我们所看到的,与我们之前的例子唯一不同的是,我们使用的是ListJacksonDataFormat类,其自定义的unmarshal类型为Fruit这是一个Jackson数据格式类型,直接准备用于处理列表

Likewise, our unit test is very similar:

同样地,我们的单元测试也非常类似。

@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
}

However, there are two subtle differences with respect to the test we saw in the previous section:

然而,与我们在上一节看到的测试相比,有两个微妙的区别。

  • We’re first setting up our mock expectation to contain a body with a List.class directly
  • When we retrieve the message body as a List.class, we’ll get a standard warning about type safety – hence the use of @SuppressWarnings(“unchecked”)

6. Conclusion

6.结论

In this short article, we’ve seen two simple approaches for unmarshalling JSON arrays using camel message routing and the camel-jackson component.

在这篇短文中,我们看到了使用骆驼消息路由和camel-jackson组件来解读JSON数组的两种简单方法。

As always, the full source code of the article is available over on GitHub.

一如既往,文章的完整源代码可在GitHub上获得