1. 개요

Apache Camel 은 알려진 여러 엔터프라이즈 통합 패턴을 구현하는 강력한 오픈 소스 통합 프레임워크 입니다.

일반적으로 Camel을 사용하여 메시지 라우팅 작업을 할 때 지원되는 많은 플러그형 데이터 형식 중 하나를 사용하려고 합니다 . JSON이 대부분의 최신 API 및 데이터 서비스에서 널리 사용된다는 점을 감안하면 당연한 선택이 됩니다.

이 예제에서는  camel-jackson 구성 요소를 사용하여 JSON 배열 을 Java 객체 List으로 비정렬화할 수 있는 몇 가지 방법을 살펴보겠습니다 .

2. 의존성

먼저 pom.xml에 camel-jackson 의존성  을  추가해 보겠습니다 .

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

그런 다음 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 객체 의 List을 담을 컨테이너를 정의할 것입니다 :

public class FruitList {

    private List<Fruit> fruits;

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

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

다음 두 섹션에서는 과일 List을 나타내는 JSON 문자열을 이러한 도메인 클래스로 비정렬화하는 방법을 볼 것입니다. 궁극적으로 우리가 찾고 있는 것은  작업할 수 있는 List<Fruit> 유형의 변수입니다 .

4. JSON 과일 List 언마샬링

이 첫 번째 예에서는 JSON 형식을 사용하여 간단한 과일 List을 나타낼 것입니다.

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

무엇보다도 이 JSON이 우리의 배열을 포함하는 과일 이라는 속성을 포함하는 객체를 나타낸다는 점을 강조해야 합니다 .

이제 역직렬화를 수행하기 위해 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 인 직접 엔드포인트를 사용합니다 . 다음으로 지정된 데이터 형식을 사용하여 Camel 교환에서 메시지 본문을 비정렬화하는 비 정렬화 메서드를 호출 합니다.

우리는 사용자 정의 비정렬 유형의 FruitList 와 함께 JacksonDataFormat 클래스를 사용하고 있습니다. 이것은 본질적으로 Jackon ObjectMapper를 둘러싼 간단한 래퍼 이며 JSON과 마샬링할 수 있습니다.

마지막으로 unmarshal 메서드 의 결과를 marshalledObject 라는 모의 끝점 으로 보냅니다 . 앞으로 살펴보겠지만 이것이 올바르게 작동하는지 확인하기 위해 경로를 테스트하는 방법입니다.

이를 염두에 두고 첫 번째 단위 테스트를 작성해 보겠습니다.

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 클래스 를 확장하여 시작합니다.
  • 그런 다음 테스트 기대치를 설정합니다. 우리의 모의 변수는 하나의 메시지를 가지고 있어야하고, 메시지 유형은해야 FruitList
  • 이제 우리는이 돼있어로 JSON 입력 파일을 보낼 준비가 문자열 받는 직접 우리가 이전에 정의 된 엔드 포인트
  • 모의 기대치가 충족되었는지 확인한 후 자유롭게 FruitList 를 검색 하고 내용이 예상대로인지 확인합니다.

이 테스트는 경로가 제대로 작동하고 JSON이 예상대로 비정렬화되고 있는지 확인합니다. 엄청난!

5. JSON 과일 배열의 비정렬화

반면에 우리는 과일 객체를 담기 위해 컨테이너 객체를 사용하는 것을 피하고 싶습니다 . 과일 배열을 직접 보유하도록 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 클래스를 사용하고 있다는 것 입니다. 이것은 List 작업을 위해 직접 준비된 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 로 검색하면 유형 안전성에 대한 표준 경고가 표시됩니다. 따라서 @SuppressWarnings("unchecked")를 사용합니다.

6. 결론

이 짧은 기사에서 우리는 낙타 메시지 라우팅과 낙타-잭슨 구성 요소를 사용하여 JSON 배열을 비정렬화하는 두 가지 간단한 접근 방식을 보았습니다 .

항상 그렇듯이 기사의 전체 소스 코드는 GitHub에서 사용할 수  있습니다 .

Generic footer banner