You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2020/03/13 15:52:06 UTC

[camel] 02/04: CAMEL-14670: @BeanConfigInject for injecting bean configuration classes that are pre configured from properties files.

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

commit 640cbb707a9f4704f87c5bf6fff67dbe640d7b06
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Mar 13 15:39:39 2020 +0100

     CAMEL-14670: @BeanConfigInject for injecting bean configuration classes that are pre configured from properties files.
---
 .../impl/engine/CamelPostProcessorHelper.java      | 63 ++++++++++++++++++++++
 .../impl/engine/DefaultCamelBeanPostProcessor.java | 15 +++++-
 .../test/java/org/apache/camel/impl/FooBar.java    |  4 ++
 .../camel/impl/{FooBar.java => FooBarConfig.java}  | 21 ++++++--
 .../impl/engine/CamelPostProcessorHelperTest.java  | 35 ++++++++++++
 5 files changed, 132 insertions(+), 6 deletions(-)

diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/engine/CamelPostProcessorHelper.java b/core/camel-base/src/main/java/org/apache/camel/impl/engine/CamelPostProcessorHelper.java
index da743bc..fc94c42 100644
--- a/core/camel-base/src/main/java/org/apache/camel/impl/engine/CamelPostProcessorHelper.java
+++ b/core/camel-base/src/main/java/org/apache/camel/impl/engine/CamelPostProcessorHelper.java
@@ -17,8 +17,12 @@
 package org.apache.camel.impl.engine;
 
 import java.lang.reflect.Method;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Properties;
 import java.util.Set;
 
+import org.apache.camel.BeanConfigInject;
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.Consume;
@@ -38,8 +42,10 @@ import org.apache.camel.ProxyInstantiationException;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.Service;
 import org.apache.camel.spi.BeanProxyFactory;
+import org.apache.camel.spi.GeneratedPropertyConfigurer;
 import org.apache.camel.spi.PropertiesComponent;
 import org.apache.camel.support.CamelContextHelper;
+import org.apache.camel.support.PropertyBindingSupport;
 import org.apache.camel.support.service.ServiceHelper;
 import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
@@ -302,6 +308,63 @@ public class CamelPostProcessorHelper implements CamelContextAware {
         }
     }
 
+    public Object getInjectionBeanConfigValue(Class<?> type, String name) {
+        ExtendedCamelContext ecc = (ExtendedCamelContext) getCamelContext();
+
+        // create an instance of type
+        Object bean;
+        Set<?> instances = ecc.getRegistry().findByType(type);
+        if (instances.size() == 1) {
+            bean = instances.iterator().next();
+        } else if (instances.size() > 1) {
+            return null;
+        } else {
+            // attempt to create a new instance
+            try {
+                bean = ecc.getInjector().newInstance(type);
+            } catch (Throwable e) {
+                // ignore
+                return null;
+            }
+        }
+
+        // root key
+        String rootKey = name;
+        // clip trailing dot
+        if (rootKey.endsWith(".")) {
+            rootKey = rootKey.substring(0, rootKey.length() - 1);
+        }
+
+        // get all properties and transfer to map
+        Properties props = ecc.getPropertiesComponent().loadProperties();
+        Map<String, Object> map = new LinkedHashMap<>();
+        for (String key : props.stringPropertyNames()) {
+            map.put(key, props.getProperty(key));
+        }
+
+        // lookup configurer if there is any
+        // use FQN class name first, then simple name, and root key last
+        GeneratedPropertyConfigurer configurer = null;
+        String[] names = new String[]{type.getName() + "-configurer", type.getSimpleName() + "-configurer", rootKey + "-configurer"};
+        for (String n : names) {
+            configurer = ecc.getConfigurerResolver().resolvePropertyConfigurer(n, ecc);
+            if (configurer != null) {
+                break;
+            }
+        }
+
+        new PropertyBindingSupport.Builder()
+                .withCamelContext(ecc)
+                .withIgnoreCase(true)
+                .withTarget(bean)
+                .withConfigurer(configurer)
+                .withOptionPrefix(rootKey + ".")
+                .withProperties(map)
+                .bind();
+
+        return bean;
+    }
+
     /**
      * Factory method to create a {@link org.apache.camel.ProducerTemplate} to
      * be injected into a POJO
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 ae90f08..489fcc1 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
@@ -199,6 +199,11 @@ public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor {
                 injectFieldBean(field, beanInject.value(), bean, beanName);
             }
 
+            BeanConfigInject beanConfigInject = field.getAnnotation(BeanConfigInject.class);
+            if (beanConfigInject != null) {
+                injectFieldBeanConfig(field, beanConfigInject.value(), bean, beanName);
+            }
+
             EndpointInject endpointInject = field.getAnnotation(EndpointInject.class);
             if (endpointInject != null) {
                 @SuppressWarnings("deprecation")
@@ -241,6 +246,11 @@ public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor {
                 getPostProcessorHelper().getInjectionBeanValue(field.getType(), name));
     }
 
+    public void injectFieldBeanConfig(Field field, String name, Object bean, String beanName) {
+        ReflectionHelper.setField(field, bean,
+                getPostProcessorHelper().getInjectionBeanConfigValue(field.getType(), name));
+    }
+
     public void injectFieldProperty(Field field, String propertyName, String propertyDefaultValue, Object bean, String beanName) {
         ReflectionHelper.setField(field, bean,
                 getPostProcessorHelper().getInjectionPropertyValue(field.getType(), propertyName, propertyDefaultValue,
@@ -465,6 +475,7 @@ public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor {
                 // we also support @BeanInject and @PropertyInject annotations
                 Annotation[] anns = method.getParameterAnnotations()[i];
                 if (anns.length == 1) {
+                    // TODO: Use helper getInjectionPropertyValue
                     // we dont assume there are multiple annotations on the same parameter so grab first
                     Annotation ann = anns[0];
                     if (ann.annotationType() == PropertyInject.class) {
@@ -487,10 +498,10 @@ public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor {
                         // build key with default value included as this is supported during resolving
                         // it may be a configuration class which we want to instantiate and configure with
                         // project inject as base keys
-                        ExtendedCamelContext ecc = (ExtendedCamelContext) getOrLookupCamelContext();
-                        Object result = resolveBeanConfigInject(ecc, pi, type);
+                        Object result = getPostProcessorHelper().getInjectionBeanConfigValue(type, pi.value());
                         parameters[i] = result;
                     } else if (ann.annotationType() == BeanInject.class) {
+                        // TODO: Use helper
                         BeanInject bi = (BeanInject) ann;
                         String key = bi.value();
                         Object value;
diff --git a/core/camel-core/src/test/java/org/apache/camel/impl/FooBar.java b/core/camel-core/src/test/java/org/apache/camel/impl/FooBar.java
index 0b38d95..bb404ae 100644
--- a/core/camel-core/src/test/java/org/apache/camel/impl/FooBar.java
+++ b/core/camel-core/src/test/java/org/apache/camel/impl/FooBar.java
@@ -23,4 +23,8 @@ public class FooBar {
     public String hello(String name) {
         return greeting + " " + name;
     }
+
+    public void setGreeting(String greeting) {
+        this.greeting = greeting;
+    }
 }
diff --git a/core/camel-core/src/test/java/org/apache/camel/impl/FooBar.java b/core/camel-core/src/test/java/org/apache/camel/impl/FooBarConfig.java
similarity index 72%
copy from core/camel-core/src/test/java/org/apache/camel/impl/FooBar.java
copy to core/camel-core/src/test/java/org/apache/camel/impl/FooBarConfig.java
index 0b38d95..0df9b03 100644
--- a/core/camel-core/src/test/java/org/apache/camel/impl/FooBar.java
+++ b/core/camel-core/src/test/java/org/apache/camel/impl/FooBarConfig.java
@@ -16,11 +16,24 @@
  */
 package org.apache.camel.impl;
 
-public class FooBar {
+public class FooBarConfig {
 
-    private String greeting = "Hello";
+    private int age = 42;
+    private String name;
 
-    public String hello(String name) {
-        return greeting + " " + name;
+    public int getAge() {
+        return age;
+    }
+
+    public void setAge(int age) {
+        this.age = age;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
     }
 }
diff --git a/core/camel-core/src/test/java/org/apache/camel/impl/engine/CamelPostProcessorHelperTest.java b/core/camel-core/src/test/java/org/apache/camel/impl/engine/CamelPostProcessorHelperTest.java
index 4ee2a62..fedf639 100644
--- a/core/camel-core/src/test/java/org/apache/camel/impl/engine/CamelPostProcessorHelperTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/impl/engine/CamelPostProcessorHelperTest.java
@@ -21,6 +21,7 @@ import java.lang.reflect.Method;
 import java.util.Properties;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.camel.BeanConfigInject;
 import org.apache.camel.BeanInject;
 import org.apache.camel.CamelContext;
 import org.apache.camel.Consume;
@@ -40,6 +41,7 @@ import org.apache.camel.ResolveEndpointFailedException;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.impl.FooBar;
+import org.apache.camel.impl.FooBarConfig;
 import org.apache.camel.spi.Registry;
 import org.apache.camel.support.DefaultExchange;
 import org.apache.camel.support.DefaultRegistry;
@@ -464,6 +466,27 @@ public class CamelPostProcessorHelperTest extends ContextTestSupport {
     }
 
     @Test
+    public void testBeanConfigInjectByType() throws Exception {
+        Properties initial = new Properties();
+        initial.put("foobar.name", "Donald");
+        initial.put("foobar.age", "33");
+        context.getPropertiesComponent().setInitialProperties(initial);
+
+        CamelPostProcessorHelper helper = new CamelPostProcessorHelper(context);
+
+        MyBeanConfigInjectByTypeBean bean = new MyBeanConfigInjectByTypeBean();
+        Field field = bean.getClass().getField("config");
+
+        BeanConfigInject beanInject = field.getAnnotation(BeanConfigInject.class);
+        Class<?> type = field.getType();
+        Object value = helper.getInjectionBeanConfigValue(type, beanInject.value());
+        field.set(bean, value);
+
+        String out = bean.doSomething("Camel");
+        assertEquals("Donald (age: 33) likes Camel", out);
+    }
+
+    @Test
     public void testFluentProducerTemplateWithNoInjection() throws Exception {
         CamelPostProcessorHelper helper = new CamelPostProcessorHelper(context);
         NoBeanInjectionTestClass myBean = new NoBeanInjectionTestClass();
@@ -742,4 +765,16 @@ public class CamelPostProcessorHelperTest extends ContextTestSupport {
         }
     }
 
+    public class MyBeanConfigInjectByTypeBean {
+
+        @BeanConfigInject("foobar")
+        public FooBarConfig config;
+
+        public String doSomething(String body) {
+            FooBar bean = new FooBar();
+            bean.setGreeting(config.getName() + " (age: " + config.getAge() + ") likes");
+            return bean.hello(body);
+        }
+    }
+
 }