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 8bc1cf2 CAMEL-14955: camel-core - @PropertyInject with primitive types should be injected first 8bc1cf2 is described below commit 8bc1cf288ad77cf3c354942c343a71a95bef5d7c Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Thu Apr 23 10:13:16 2020 +0200 CAMEL-14955: camel-core - @PropertyInject with primitive types should be injected first --- .../impl/engine/DefaultCamelBeanPostProcessor.java | 74 +++++++++++++++------ ...efaultCamelBeanPostProcessorFieldFirstTest.java | 76 ++++++++++++++++++++++ 2 files changed, 131 insertions(+), 19 deletions(-) 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 ad395ca..426f21f 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 @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Set; +import java.util.function.Function; import org.apache.camel.BeanConfigInject; import org.apache.camel.BeanInject; @@ -85,15 +86,9 @@ public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor { return bean; } - if (bindToRegistrySupported()) { - injectClass(bean, beanName); - injectNestedClasses(bean, beanName); - injectBindToRegistryFields(bean, beanName); - injectBindToRegistryMethods(bean, beanName); - } - - injectFields(bean, beanName); - injectMethods(bean, beanName); + // do bean binding on simple types first, and then afterwards on complex types + injectFirstPass(bean, beanName, type -> !isComplexUserType(type)); + injectSecondPass(bean, beanName, type -> isComplexUserType(type)); if (bean instanceof CamelContextAware && canSetCamelContext(bean, beanName)) { CamelContextAware contextAware = (CamelContextAware)bean; @@ -174,14 +169,38 @@ public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor { return true; } - /** - * A strategy method to allow implementations to perform some custom JBI - * based injection of the POJO - * - * @param bean the bean to be injected - */ - protected void injectFields(final Object bean, final String beanName) { + protected void injectFirstPass(Object bean, String beanName, Function<Class, Boolean> filter) { + // on first pass do field and methods first + injectFields(bean, beanName, filter); + injectMethods(bean, beanName, filter); + + if (bindToRegistrySupported()) { + injectClass(bean, beanName); + injectNestedClasses(bean, beanName); + injectBindToRegistryFields(bean, beanName, filter); + injectBindToRegistryMethods(bean, beanName, filter); + } + } + + protected void injectSecondPass(Object bean, String beanName, Function<Class, Boolean> filter) { + // on second pass do bind to registry beforehand as they may be used by field/method injections below + if (bindToRegistrySupported()) { + injectClass(bean, beanName); + injectNestedClasses(bean, beanName); + injectBindToRegistryFields(bean, beanName, filter); + injectBindToRegistryMethods(bean, beanName, filter); + } + + injectFields(bean, beanName, filter); + injectMethods(bean, beanName, filter); + } + + protected void injectFields(final Object bean, final String beanName, Function<Class, Boolean> accept) { ReflectionHelper.doWithFields(bean.getClass(), field -> { + if (accept != null && !accept.apply(field.getType())) { + return; + } + PropertyInject propertyInject = field.getAnnotation(PropertyInject.class); if (propertyInject != null) { injectFieldProperty(field, propertyInject.value(), propertyInject.defaultValue(), bean, beanName); @@ -213,8 +232,12 @@ public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor { }); } - protected void injectBindToRegistryFields(final Object bean, final String beanName) { + protected void injectBindToRegistryFields(final Object bean, final String beanName, Function<Class, Boolean> accept) { ReflectionHelper.doWithFields(bean.getClass(), field -> { + if (accept != null && !accept.apply(field.getType())) { + return; + } + BindToRegistry bind = field.getAnnotation(BindToRegistry.class); if (bind != null) { bindToRegistry(field, bind.value(), bean, beanName, bind.beanPostProcess()); @@ -250,18 +273,26 @@ public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor { field.getName(), bean, beanName)); } - protected void injectMethods(final Object bean, final String beanName) { + protected void injectMethods(final Object bean, final String beanName, Function<Class, Boolean> accept) { ReflectionHelper.doWithMethods(bean.getClass(), method -> { + if (accept != null && !accept.apply(method.getReturnType())) { + return; + } + setterInjection(method, bean, beanName); getPostProcessorHelper().consumerInjection(method, bean, beanName); }); } - protected void injectBindToRegistryMethods(final Object bean, final String beanName) { + protected void injectBindToRegistryMethods(final Object bean, final String beanName, Function<Class, Boolean> accept) { // sort the methods so the simplest are used first final List<Method> methods = new ArrayList<>(); ReflectionHelper.doWithMethods(bean.getClass(), method -> { + if (accept != null && !accept.apply(method.getReturnType())) { + return; + } + BindToRegistry bind = method.getAnnotation(BindToRegistry.class); if (bind != null) { methods.add(method); @@ -521,4 +552,9 @@ public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor { return parameters; } + private static boolean isComplexUserType(Class type) { + // lets consider all non java, as complex types + return type != null && !type.isPrimitive() && !type.getName().startsWith("java."); + } + } diff --git a/core/camel-core/src/test/java/org/apache/camel/impl/DefaultCamelBeanPostProcessorFieldFirstTest.java b/core/camel-core/src/test/java/org/apache/camel/impl/DefaultCamelBeanPostProcessorFieldFirstTest.java new file mode 100644 index 0000000..447fa90 --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/impl/DefaultCamelBeanPostProcessorFieldFirstTest.java @@ -0,0 +1,76 @@ +/* + * 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.impl; + +import java.util.Properties; + +import org.apache.camel.BindToRegistry; +import org.apache.camel.ContextTestSupport; +import org.apache.camel.ExtendedCamelContext; +import org.apache.camel.PropertyInject; +import org.apache.camel.spi.CamelBeanPostProcessor; +import org.junit.Before; +import org.junit.Test; + +public class DefaultCamelBeanPostProcessorFieldFirstTest extends ContextTestSupport { + + private CamelBeanPostProcessor postProcessor; + + @Test + public void testPostProcessor() throws Exception { + FooService foo = new FooService(); + + Properties prop = new Properties(); + prop.setProperty("foo", "Donald Duck"); + context.getPropertiesComponent().setInitialProperties(prop); + + postProcessor.postProcessBeforeInitialization(foo, "foo"); + postProcessor.postProcessAfterInitialization(foo, "foo"); + + // should register the beans in the registry via @BindRegistry + Object bean = context.getRegistry().lookupByName("myCoolBean"); + assertNotNull(bean); + MySerialBean msb = assertIsInstanceOf(MySerialBean.class, bean); + + assertEquals(123, msb.getId()); + assertEquals("Donald Duck", msb.getName()); + } + + @Override + @Before + public void setUp() throws Exception { + super.setUp(); + postProcessor = context.adapt(ExtendedCamelContext.class).getBeanPostProcessor(); + } + + @BindToRegistry + public class FooService { + + // should inject simple types first such as this property + @PropertyInject("foo") + private String foo; + + @BindToRegistry("myCoolBean") + public MySerialBean myBean() { + MySerialBean myBean = new MySerialBean(); + myBean.setId(123); + myBean.setName(foo); + return myBean; + } + + } +}