This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/master by this push: new 511a773 CAMEL-13582: Camel main - Configuration class should support automatic autowire by type. Made CamelBeanPostProcessor sort the @BindToRegistry methods in a better order so they deal with inter dependencies among themselves. 511a773 is described below commit 511a7730ba4d2a9c27d0d27bb5bd815653d2898b Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Mon May 27 12:28:03 2019 +0200 CAMEL-13582: Camel main - Configuration class should support automatic autowire by type. Made CamelBeanPostProcessor sort the @BindToRegistry methods in a better order so they deal with inter dependencies among themselves. --- .../impl/engine/DefaultCamelBeanPostProcessor.java | 28 +++++- .../main/MainIoCNewRouteBuilderComplexTest.java | 102 +++++++++++++++++++++ 2 files changed, 129 insertions(+), 1 deletion(-) diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java b/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java index cab3f8b..6899089 100644 --- a/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java +++ b/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java @@ -247,6 +247,32 @@ public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor { // sort methods on shortest number of parameters as we want to process the most simplest first methods.sort(Comparator.comparingInt(Method::getParameterCount)); + // then do a more complex sorting where we check inter-dependency among the methods + methods.sort((m1, m2) -> { + Class[] types1 = m1.getParameterTypes(); + Class[] types2 = m2.getParameterTypes(); + + // favour methods that has no parameters + if (types1.length == 0 && types2.length == 0) { + return 0; + } else if (types1.length == 0) { + return -1; + } else if (types2.length == 0) { + return 1; + } + + // okay then compare so we favour methods that does not use parameter types that are returned from other methods + boolean usedByOthers1 = false; + for (Class clazz : types1) { + usedByOthers1 |= methods.stream().anyMatch(m -> m.getParameterCount() > 0 && clazz.isAssignableFrom(m.getReturnType())); + } + boolean usedByOthers2 = false; + for (Class clazz : types2) { + usedByOthers2 |= methods.stream().anyMatch(m -> m.getParameterCount() > 0 && clazz.isAssignableFrom(m.getReturnType())); + } + return Boolean.compare(usedByOthers1, usedByOthers2); + }); + LOG.trace("Discovered {} @BindToRegistry methods", methods.size()); // bind each method @@ -442,7 +468,7 @@ public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor { Set<?> instances = camelContext.getRegistry().findByType(type); if (instances.size() == 1) { parameters[i] = instances.iterator().next(); - } else { + } else if (instances.size() > 1) { // there are multiple instances of the same type, so barf throw new IllegalArgumentException("Multiple beans of the same type: " + type + " exists in the Camel registry. Specify the bean name on @BeanInject to bind to a single bean, at the method: " + method); diff --git a/core/camel-core/src/test/java/org/apache/camel/main/MainIoCNewRouteBuilderComplexTest.java b/core/camel-core/src/test/java/org/apache/camel/main/MainIoCNewRouteBuilderComplexTest.java new file mode 100644 index 0000000..01a90db --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/main/MainIoCNewRouteBuilderComplexTest.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.main; + +import org.apache.camel.BindToRegistry; +import org.apache.camel.CamelContext; +import org.apache.camel.MyFoo; +import org.apache.camel.PropertyInject; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.junit.Assert; +import org.junit.Test; + +public class MainIoCNewRouteBuilderComplexTest extends Assert { + + @Test + public void testMainIoC() throws Exception { + Main main = new Main(); + main.addRouteBuilder(new MyRouteBuilder()); + main.start(); + + CamelContext camelContext = main.getCamelContext(); + assertNotNull(camelContext); + + MockEndpoint endpoint = camelContext.getEndpoint("mock:results", MockEndpoint.class); + endpoint.expectedBodiesReceived("Hi dude"); + + main.getCamelTemplate().sendBody("direct:start", "<message>1</message>"); + + endpoint.assertIsSatisfied(); + + main.stop(); + } + + public static class MyBar { + + private final String name; + + public MyBar(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } + } + + public static class MyDude { + + private final String name; + + public MyDude(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } + } + + public static class MyRouteBuilder extends RouteBuilder { + + @BindToRegistry("foo") + public MyFoo createFoo(MyBar bar) { + // should be invoked #3 + return new MyFoo(bar.toString()); + } + + @BindToRegistry + public MyDude myDude() { + // should be invoked #1 + return new MyDude("dude"); + } + + @BindToRegistry("bar") + public MyBar createBar(@PropertyInject(value = "bye", defaultValue = "Hi") String hello, MyDude dude) { + // should be invoked #2 + return new MyBar(hello + " " + dude.name); + } + + @Override + public void configure() throws Exception { + from("direct:start").bean("foo", "getName").to("mock:results"); + } + } +}