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 2022/03/12 15:58:03 UTC

[camel] branch CAMEL-17571 updated: CAMEL-17571: camel-jbang - Support for quarkus/cdi annotations in custom beans

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-17571
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/CAMEL-17571 by this push:
     new e1103a1  CAMEL-17571: camel-jbang - Support for quarkus/cdi annotations in custom beans
e1103a1 is described below

commit e1103a1b9fcd350d88fbfb49725ad55bf420b102
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sat Mar 12 16:56:54 2022 +0100

    CAMEL-17571: camel-jbang - Support for quarkus/cdi annotations in custom beans
---
 dsl/camel-kamelet-main/pom.xml                     |  14 +++
 .../camel/main/QuarkusAnnotationSupport.java       | 135 +++++++++++++++++++++
 2 files changed, 149 insertions(+)

diff --git a/dsl/camel-kamelet-main/pom.xml b/dsl/camel-kamelet-main/pom.xml
index 899e154..740db50 100644
--- a/dsl/camel-kamelet-main/pom.xml
+++ b/dsl/camel-kamelet-main/pom.xml
@@ -110,6 +110,7 @@
             <groupId>org.springframework</groupId>
             <artifactId>spring-context</artifactId>
             <version>${spring-version}</version>
+            <optional>true</optional>
             <exclusions>
                 <exclusion>
                     <groupId>org.springframework</groupId>
@@ -125,6 +126,19 @@
                 </exclusion>
             </exclusions>
         </dependency>
+        <!-- optional quarkus annotation support -->
+        <dependency>
+            <groupId>jakarta.enterprise</groupId>
+            <artifactId>jakarta.enterprise.cdi-api</artifactId>
+            <version>2.0.2</version>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.microprofile.config</groupId>
+            <artifactId>microprofile-config-api</artifactId>
+            <version>2.0</version>
+            <optional>true</optional>
+        </dependency>
 
         <dependency>
             <groupId>org.apache.camel</groupId>
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/QuarkusAnnotationSupport.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/QuarkusAnnotationSupport.java
new file mode 100644
index 0000000..fbc7acb
--- /dev/null
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/QuarkusAnnotationSupport.java
@@ -0,0 +1,135 @@
+/*
+ * 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 java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Produces;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.dsl.support.CompilePostProcessor;
+import org.apache.camel.impl.engine.CamelPostProcessorHelper;
+import org.apache.camel.spi.CamelBeanPostProcessor;
+import org.apache.camel.spi.CamelBeanPostProcessorInjector;
+import org.apache.camel.util.ReflectionHelper;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+
+/**
+ * To support quarkus based annotations such as @ApplicationScoped, @Singleton, @Inject, @Produces, @ConfigProperty
+ */
+public final class QuarkusAnnotationSupport {
+
+    private QuarkusAnnotationSupport() {
+    }
+
+    public static void registerSpringSupport(CamelContext context) {
+        context.getRegistry().bind("QuarkusAnnotationCompilePostProcessor", new QuarkusAnnotationCompilePostProcessor());
+        context.adapt(ExtendedCamelContext.class).getBeanPostProcessor()
+                .addCamelBeanPostProjectInjector(new QuarkusBeanPostProcessorInjector(context));
+    }
+
+    private static class QuarkusAnnotationCompilePostProcessor implements CompilePostProcessor {
+
+        @Override
+        public void postCompile(CamelContext camelContext, String name, Class<?> clazz, Object instance) throws Exception {
+            // @ApplicationScoped and @Singleton are considered the same
+            ApplicationScoped as = clazz.getAnnotation(ApplicationScoped.class);
+            Singleton ss = clazz.getAnnotation(Singleton.class);
+            if (as != null || ss != null) {
+                Named named = clazz.getAnnotation(Named.class);
+                if (named != null) {
+                    name = named.value();
+                }
+                CamelBeanPostProcessor bpp = camelContext.adapt(ExtendedCamelContext.class).getBeanPostProcessor();
+                // to support hot reloading of beans then we need to enable unbind mode in bean post processor
+                bpp.setUnbindEnabled(true);
+                try {
+                    // re-bind the bean to the registry
+                    camelContext.getRegistry().unbind(name);
+                    camelContext.getRegistry().bind(name, instance);
+                    // this class is a bean service which needs to be post processed
+                    bpp.postProcessBeforeInitialization(instance, name);
+                    bpp.postProcessAfterInitialization(instance, name);
+                } finally {
+                    bpp.setUnbindEnabled(false);
+                }
+            }
+        }
+    }
+
+    private static class QuarkusBeanPostProcessorInjector implements CamelBeanPostProcessorInjector {
+
+        private final CamelContext context;
+        private final CamelPostProcessorHelper helper;
+
+        public QuarkusBeanPostProcessorInjector(CamelContext context) {
+            this.context = context;
+            this.helper = new CamelPostProcessorHelper(context);
+        }
+
+        @Override
+        public void onFieldInject(Field field, Object bean, String beanName) {
+            Inject inject = field.getAnnotation(Inject.class);
+            if (inject != null) {
+                String name = null;
+                Named named = field.getAnnotation(Named.class);
+                if (named != null) {
+                    name = named.value();
+                }
+
+                ReflectionHelper.setField(field, bean,
+                        helper.getInjectionBeanValue(field.getType(), name));
+            }
+            ConfigProperty cp = field.getAnnotation(ConfigProperty.class);
+            if (cp != null) {
+                ReflectionHelper.setField(field, bean,
+                        helper.getInjectionPropertyValue(field.getType(), cp.name(), cp.defaultValue(), null, bean, beanName));
+            }
+        }
+
+        @Override
+        public void onMethodInject(Method method, Object bean, String beanName) {
+            Produces produces = method.getAnnotation(Produces.class);
+            Named bi = method.getAnnotation(Named.class);
+            if (produces != null || bi != null) {
+                Object instance = helper.getInjectionBeanMethodValue(context, method, bean, beanName);
+                if (instance != null) {
+                    String name = method.getName();
+                    if (bi != null && !bi.value().isBlank()) {
+                        name = bi.value();
+                    }
+                    // to support hot reloading of beans then we need to enable unbind mode in bean post processor
+                    CamelBeanPostProcessor bpp = context.adapt(ExtendedCamelContext.class).getBeanPostProcessor();
+                    bpp.setUnbindEnabled(true);
+                    try {
+                        // re-bind the bean to the registry
+                        context.getRegistry().unbind(name);
+                        context.getRegistry().bind(name, instance);
+                    } finally {
+                        bpp.setUnbindEnabled(false);
+                    }
+                }
+            }
+        }
+    }
+}