如何在AggregationStrategy中优雅地将newExchange从JSON解组为POJO

时间:2018-02-17 00:31:11

标签: json apache-camel unmarshalling

使用自定义聚合策略,是否有一种优雅的方法可以在Apache Camel中将JSON解组为POJO?

我的简单路由从SQS接收消息,消息是JSON。此消息用作另一个服务的输入,而另一个服务又基于消息内容将让我知道应将原始消息发布到的服务的URL。

使用AggregationStrategy丰富EIP是完美的。但是,我不知道如何在路线中优雅地将JSON解组为POJO。我可以通过ObjectMapper来做到这一点,但这看起来很难看。有没有更好的处理方式?我还没见过一些神奇的骆驼酱吗?

public RouteBuilder route() {
    return new RouteBuilder() {
        @Override
        public void configure() throws Exception {
            from("aws-sqs://" + sqsName + "?amazonSQSClient")
            .setHeader("Content-Type",simple("application/json"))
            .enrich()
            .simple("http4://localhost:8080/getUrl")
            .aggregationStrategy(new AggregationStrategy() {
                @Override
                public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
                    String aPojoStr =  newExchange.getIn().getBody(String.class);
                    ObjectMapper mapper = new ObjectMapper();
                    RestAnswererResponse responosePojo;
                    try {
                        responosePojo = mapper.readValue(aPojoStr, RestAnswererResponse.class);
                    } catch (JsonParseException e) {
                        throw new RuntimeException("Error parsing response to pojo", e);

                    } catch (JsonMappingException e) {
                        throw new RuntimeException("Error parsing response to pojo", e);
                    } catch (IOException e) {
                        throw new RuntimeException("Error parsing response to pojo", e);
                    }
                    oldExchange.getIn().setHeader("URL", responosePojo.getURL());
                    return oldExchange;
                }
            })
            .toD("http4://${header" + "URL + "}/postToAck);
        }
    };
}

编辑: 只是为了澄清我的路线需要如何工作:

  1. SQS包含JSON消息
  2. 需要将JSON消息的内容发布到服务,该服务基于原始消息的上下文确定应该发布消息的最终URL(这是特定于上下文的发现服务)。发现服务仅返回最终目标的URL。

    {"url":"somehost:port"}
    
  3. 一旦从服务发现中检索到最终目的地,原始消息(从SQS检索)将被发布到该最终目的地。

2 个答案:

答案 0 :(得分:2)

您可以使用JSON data format解组邮件,而不是弄乱ObjectMapper

使用rich时,我发现创建一个它调用的direct路由很有用。我发现这更容易理解,模拟,测试,你可以给它不同的错误处理和重新传递策略。

    from("aws-sqs://" + sqsName + "?amazonSQSClient")
        .setHeader("Content-Type",simple("application/json"))
        .enrich("direct:other", strategy)
        .toD("http4://${header" + "URL + "}/postToAck);

    from("direct:other")
        .to("http4://localhost:8080/getUrl")
        .unmarshal().json(JsonLibrary.Jackson, RestAnswererResponse.class);

所有策略需要做的是提取URL并根据需要设置标题。

答案 1 :(得分:0)

您不需要聚合策略来实现您想要的效果。这可以使用jsonpath

完成
 from("aws-sqs://" + sqsName + "?amazonSQSClient")
            .setHeader("Content-Type",simple("application/json"))
            .setHeader("Accept", simple("application/json"))
            .setHeader(Exchange.HTTP_METHOD, constant("GET"))
            .toD("http4://localhost:8080/getUrl")
            .transform().jsonpath("url")
            .toD("http4://${body}/postToAck");

考虑到您从localhost:8080/getUrl获得的json响应中有一个字段 url

最后要使用jsonpath,你需要这种依赖。

<!-- https://mvnrepository.com/artifact/org.apache.camel/camel-jsonpath -->
  <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-jsonpath</artifactId>
      <version>yourcamelversion</version>
  </dependency>

更新:

from("aws-sqs://" + sqsName + "?amazonSQSClient")
            .setHeader("Content-Type",simple("application/json"))
            .setHeader("Accept", simple("application/json"))
            .setHeader(Exchange.HTTP_METHOD, constant("POST"))
            .toD("http4://localhost:8080/getUrl")
            .convertBodyTo(String.class)
            .unmarshal().json(JsonLibrary.Jackson, RestAnswererResponse.class)
            .setHeader("url", simple("${body.url}"))
            .setBody(simple("${body.originalBody}"))
            .toD("${header.url}" + "/postToAck");

考虑

public class RestAnswererResponse {
  String url;
  String originalBody;
}

http4://localhost:8080/getUrl端点中,您应该设置originalBody然后返回。像这样的东西

class SomeController {

 @PostMapping("/getUrl")
  public RestResponse getUrl (@RequestBody String body) {
   // based on the body object decide what is the url
    return new RestResponse("url", body);// set the body it recieves as originalBody.     
}

对于json unmarshalling,你需要

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