Apache Camel 迭代列表 [英] Apache Camel iterate over List

查看:35
本文介绍了Apache Camel 迭代列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 Apache Camel 的新手,我在理解如何实现一个简单的集成任务时遇到了问题:

I am new to Apache Camel and I am having problems understanding how to implement a simple integration task:

  1. REST 服务通过 Apache Camel 路由调用 Spring Bean
  2. Spring Bean 返回类的集合(ArrayList)

我需要遍历集合中的每个项目,并通过自定义转换器将其转换为另一种类型.

I need to iterate over each item in the collection and convert it to another type through the custom converter.

似乎我应该使用拆分和聚合器,但是我如何约束聚合器以消耗原始列表中的所有项目,而不是更多,也不是更少.另外,如何将一个项目转换为另一个项目?我应该使用类型转换器吗?

It seems that I should use Split and an Aggregator, but how do I constraint Aggregator to consume all items from the original list, not more, nor less. Also, how can I convert one item to another? Should I use a Type Converter?

谁能给我一个简单的例子?

Can someone provide me a simple example?

更新 1

抱歉,我不得不取消对所提供示例的接受,因为它实际上并没有回答我的问题.这是用例限定:我需要从 to("bean:someBean") 调用拆分和转换方法返回值,而不是从某个端点拆分和转换输入值.

Sorry, I had to undo acceptance of the provided example since it is not actually answering to my question. Here is the use case qualification: I need to split and transform a method return value from to("bean:someBean") invocation rather than split and transform input values from some endpoint.

所以用例是

  1. 调用某个端点;例如对休息服务的 GET 请求,在我的情况下:from("endpoint")
  2. 调用bean并获取它的返回值;如List, to("bean:someBean"))
  3. 将返回值转换为另一个List
  4. 将转换后的List返回给消费者
  1. Call some endpoint; e.g a GET request on rest service, in my case: from("endpoint")
  2. Call a bean and get it's return value; like List, to("bean:someBean"))
  3. Transform returned value to another List
  4. Return transformed List to consumer

更新 2

所以,我可以确认使用 end() 方法并不能解决我的问题.

So, I can confirm than using end() method does not solve my problem.

代码如下:

rest("some/service").get().produces("application/json").to("bean:someBean?method=getListOfObjects").route().split(body(), (oldExchange, newExchange) -> {
                List<ObjectToConvert> oldList = oldExchange.getIn(List.class);
                List<NewObject> convertedList = taskList.stream().map(ObjectToConvert::new).collect(Collectors.toList());
                newExchange.getOut().setBody(convertedList);

                return newExchange;
            }).end();

使用这种路由我在应用服务器上得到以下异常:

Using this kind of route I get the following exception on the application server:

19:30:21,126 ERROR [org.jboss.as.controller.management-operation] (XNIO-1 task-5) JBAS014613: Operation ("full-replace-deployment") failed - address: (undefined) - failure description: {"JBAS014671: Failed services" => {"jboss.undertow.deployment.default-server.default-host./CamundaLearningCamel" => "org.jboss.msc.service.StartException in service jboss.undertow.deployment.default-server.default-host./CamundaLearningCamel: Failed to start service
    Caused by: java.lang.RuntimeException: org.apache.camel.RuntimeCamelException: org.apache.camel.FailedToCreateRouteException: Failed to create route route2 at: >>> Split[{body} -> []] <<< in route: Route(route2)[[From[rest:get:task/all?produces=application%2... because of Definition has no children on Split[{body} -> []]
    Caused by: org.apache.camel.RuntimeCamelException: org.apache.camel.FailedToCreateRouteException: Failed to create route route2 at: >>> Split[{body} -> []] <<< in route: Route(route2)[[From[rest:get:task/all?produces=application%2... because of Definition has no children on Split[{body} -> []]
    Caused by: org.apache.camel.FailedToCreateRouteException: Failed to create route route2 at: >>> Split[{body} -> []] <<< in route: Route(route2)[[From[rest:get:task/all?produces=application%2... because of Definition has no children on Split[{body} -> []]
    Caused by: java.lang.IllegalArgumentException: Definition has no children on Split[{body} -> []]"}}

推荐答案

这里有一个完整的示例,它拆分聚合并转换列表消息.

Here is a complete example that splits aggregates and converts a list message.

  1. camel splitter 提供了一个内置的聚合器,用于聚合原始交换中的所有拆分消息.所以分离器只是聚合每个列表(交换)的消息以直接:开始"发送.您必须提供自定义聚合策略,因为默认会使用原始的交换,在我的例子 InOrder 中.聚合策略是拆分定义的第二个参数.
  2. 类型转换器让我们有机会在数字用户线.您也可以使用 bean、处理器或在自定义聚合策略中执行所有转换来实现这一点.

  1. The camel splitter provides a built-in aggregator which aggregates all split messages in the original exchange. So the splitter is only aggregating the messages of each list(exchange) send in "direct:start". You have to provide a custom aggregation strategy because the default one will use the original exchanges, in my example InOrder. The aggregation strategy is the second argument of the split definition.
  2. The type converter gives us the opportunity to use convertBodyTo in DSL. You cound also achieve that with a bean,processor or do all the transformations in the custom aggregation strategy.

package org.mydemocamel.app;
import org.apache.camel.*;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.processor.aggregate.AggregationStrategy;
import org.apache.camel.processor.aggregate.GroupedExchangeAggregationStrategy;
import org.apache.camel.processor.aggregate.UseLatestAggregationStrategy;
import org.apache.camel.processor.aggregate.UseOriginalAggregationStrategy;
import org.apache.camel.support.TypeConverterSupport;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.apache.camel.util.toolbox.FlexibleAggregationStrategy;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;


public class CamelSplitAggregateConvertTest extends CamelTestSupport {

    @Produce
    private ProducerTemplate template;

    @EndpointInject(uri = "mock:out")
    private MockEndpoint mock;

    @Test
    public void testSplitAggregateConvertOrder(){
        InOrder inOrder1 = new InOrder();
        inOrder1.setId("1");

        InOrder inOrder2 = new InOrder();
        inOrder2.setId("2");

        List<InOrder> inOrderList = new ArrayList<InOrder>();
        inOrderList.add(inOrder1);
        inOrderList.add(inOrder2);

        template.sendBody("direct:start", inOrderList);

        mock.expectedMessageCount(1);
        Exchange outList = mock.getReceivedExchanges().get(0);
        List<OutOrder> outOrderList = outList.getIn().getBody(List.class);

        assertEquals(1, outOrderList.get(0).getId());
        assertEquals(2, outOrderList.get(1).getId());


    }

    @Override
    protected RouteBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder() {
            @Override
            public void configure() throws Exception {

                context.getTypeConverterRegistry().addTypeConverter(OutOrder.class, InOrder.class, new MyOrderTypeConverter());

                from("direct:start")
                .split(body(), new AggregationStrategy() {
                    @Override
                    public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
                        if (oldExchange == null) {
                            List<OutOrder> orders = new ArrayList<OutOrder>();
                            OutOrder newOrder = newExchange.getIn().getBody(OutOrder.class);
                            orders.add(newOrder);
                            newExchange.getIn().setBody(orders);
                            return newExchange;
                        }
                        List<OutOrder> orders = oldExchange.getIn().getBody(List.class);
                        OutOrder newOutOrder = newExchange.getIn().getBody(OutOrder.class);
                        orders.add(newOutOrder);
                        oldExchange.getIn().setBody(orders);
                        return oldExchange;
                    }
                })
                .convertBodyTo(OutOrder.class)
                .end()  //splitter ends here and the exchange body  is now List<OutOrder> 
                .to("mock:out");

            }
        };
    }

    private static class MyOrderTypeConverter extends TypeConverterSupport {

        @SuppressWarnings("unchecked")
        public <T> T convertTo(Class<T> type, Exchange exchange, Object value) {
            // converter from inorder to outorder bean
            OutOrder order = new OutOrder();
            order.setId(Integer.parseInt(((InOrder) value).getId()));
            return (T) order;
        }
    }

    private static class OutOrder {
        private int id;

        public void setId(int id) {
            this.id = id;
        }

        public int getId() {
            return id;
        }
    }

    private static class InOrder {
        private String id;

        public void setId(String id) {
            this.id = id;
        }

        public String getId() {
            return id;
        }
    }
}

这篇关于Apache Camel 迭代列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆