使用camel-jackson解組JSON數組

    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方法的結果發送到名為marshalledObjectmock端點。正如我們將要看到的,這就是我們將測試路線以查看其是否正常運行的方式。

    考慮到這一點,讓我們繼續編寫我們的第一個單元測試:

    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數組的簡單方法。