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

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


The following commit(s) were added to refs/heads/main by this push:
     new 68ea079  Camel 17571 (#7200)
68ea079 is described below

commit 68ea0794002beadbc63482455039004286ef2b7d
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Mon Mar 14 15:51:17 2022 +0100

    Camel 17571 (#7200)
    
    * CAMEL-17571: camel-dsl - Allow to register custom annotation processors 
that can do custom logic after a DSL has compiled source into Java object.
    
    * CAMEL-17571: camel-jbang - Support for spring @Component/@Service 
annotations in custom beans
    
    * CAMEL-17571: camel-dsl - Allow to register custom annotation processors 
that can do custom logic after a DSL has compiled source into Java object.
    
    * CAMEL-17571: camel-dsl - Allow to register custom annotation processors 
that can do custom logic after a DSL has compiled source into Java object.
    
    * CAMEL-17571: camel-jbang - Support for spring @Autowired/@Value 
annotations in custom beans
    
    * CAMEL-17571: camel-jbang - Support for spring @Autowired/@Value 
annotations in custom beans
    
    * CAMEL-17571: camel-jbang - Support for spring @Bean annotations in custom 
beans
    
    * CAMEL-17571: camel-jbang - Support for spring @Bean annotations in custom 
beans
    
    * CAMEL-17571: camel-dsl - Allow to register custom annotation processors 
that can do custom logic after a DSL has compiled source into Java object.
    
    * CAMEL-17571: camel-dsl - Allow to register custom annotation processors 
that can do custom logic after a DSL has compiled source into Java object.
    
    * camel-kamelet-main - Cleanup code
    
    * CAMEL-17571: camel-jbang - Support for quarkus/cdi annotations in custom 
beans
    
    * CAMEL-17571: camel-jbang - Support for quarkus/cdi annotations in custom 
beans
    
    * CAMEL-17571: camel-jbang - Support for quarkus/cdi annotations in custom 
beans
    
    * CAMEL-17571: camel-jbang - docs
    
    * CAMEL-17571: camel-dsl - Allow to register custom annotation processors 
that can do custom logic after a DSL has compiled source into Java object.
    
    * CAMEL-17571: camel-dsl - Allow to register custom annotation processors 
that can do custom logic after a DSL has compiled source into Java object.
    
    * CAMEL-17571: camel-dsl - Allow to register custom annotation processors 
that can do custom logic after a DSL has compiled source into Java object.
    
    * CAMEL-17571: Polished
    
    * CAMEL-17571: Review
    
    * Update docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
    
    Co-authored-by: Nicolas Filotto <essob...@users.noreply.github.com>
    
    Co-authored-by: Nicolas Filotto <essob...@users.noreply.github.com>
---
 camel-dependencies/pom.xml                         |   1 +
 .../apache/camel/spi/CamelBeanPostProcessor.java   |   9 +
 .../camel/spi/CamelBeanPostProcessorInjector.java  |  46 ++++
 .../impl/engine/CamelPostProcessorHelper.java      |  90 ++++++-
 .../impl/engine/DefaultCamelBeanPostProcessor.java | 102 ++------
 .../impl/CamelBeanPostProcessorInjectorTest.java   | 101 ++++++++
 .../modules/ROOT/pages/camel-jbang.adoc            |  34 +++
 .../camel/dsl/support/CompilePostProcessor.java    |  44 ++++
 .../dsl/support/RouteBuilderLoaderSupport.java     |  36 ++-
 .../dsl/java/joor/JavaRoutesBuilderLoader.java     |  57 +---
 dsl/camel-kamelet-main/pom.xml                     |  32 +++
 .../camel/main/AnnotationDependencyInjection.java  | 286 +++++++++++++++++++++
 .../camel/main/DependencyDownloaderKamelet.java    | 111 +++++++-
 .../java/org/apache/camel/main/KameletMain.java    |   3 +
 .../org/apache/camel/main/KameletYamlRoutes.java   | 130 ----------
 parent/pom.xml                                     |   1 +
 16 files changed, 819 insertions(+), 264 deletions(-)

diff --git a/camel-dependencies/pom.xml b/camel-dependencies/pom.xml
index b676108..fcb98e3 100644
--- a/camel-dependencies/pom.xml
+++ b/camel-dependencies/pom.xml
@@ -287,6 +287,7 @@
     <jackson2-version>2.13.2</jackson2-version>
     <jain-sip-ri-bundle-version>1.2.154_2</jain-sip-ri-bundle-version>
     <jakarta-api-version>2.1.5</jakarta-api-version>
+    <jakarta-cdi-api-version>2.0.2</jakarta-cdi-api-version>
     <jakarta-jaxb-version>2.3.3</jakarta-jaxb-version>
     <jakarta-mail-version>1.6.6</jakarta-mail-version>
     <jakarta.el-version>3.0.3</jakarta.el-version>
diff --git 
a/core/camel-api/src/main/java/org/apache/camel/spi/CamelBeanPostProcessor.java 
b/core/camel-api/src/main/java/org/apache/camel/spi/CamelBeanPostProcessor.java
index 0308f54..1fff611 100644
--- 
a/core/camel-api/src/main/java/org/apache/camel/spi/CamelBeanPostProcessor.java
+++ 
b/core/camel-api/src/main/java/org/apache/camel/spi/CamelBeanPostProcessor.java
@@ -83,4 +83,13 @@ public interface CamelBeanPostProcessor {
         return false;
     }
 
+    /**
+     * Adds a custom bean post injector
+     *
+     * @param injector the custom injector
+     */
+    default void 
addCamelBeanPostProjectInjector(CamelBeanPostProcessorInjector injector) {
+        // noop
+    }
+
 }
diff --git 
a/core/camel-api/src/main/java/org/apache/camel/spi/CamelBeanPostProcessorInjector.java
 
b/core/camel-api/src/main/java/org/apache/camel/spi/CamelBeanPostProcessorInjector.java
new file mode 100644
index 0000000..6c70ab2
--- /dev/null
+++ 
b/core/camel-api/src/main/java/org/apache/camel/spi/CamelBeanPostProcessorInjector.java
@@ -0,0 +1,46 @@
+/*
+ * 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.spi;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * Used for custom injection when doing {@link CamelBeanPostProcessor} bean 
post-processing. Can be used to support
+ * 3rd-party annotations for dependency injections.
+ */
+public interface CamelBeanPostProcessorInjector {
+
+    /**
+     * Field injection
+     *
+     * @param field    the field
+     * @param bean     the bean instance where the field is present
+     * @param beanName optional bean id of the bean
+     */
+    void onFieldInject(Field field, Object bean, String beanName);
+
+    /**
+     * Method injection
+     *
+     * @param method   the method
+     * @param bean     the bean instance where the method is present
+     * @param beanName optional bean id of the bean
+     */
+    void onMethodInject(Method method, Object bean, String beanName);
+
+}
diff --git 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/CamelPostProcessorHelper.java
 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/CamelPostProcessorHelper.java
index 04b4f95..533fb49 100644
--- 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/CamelPostProcessorHelper.java
+++ 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/CamelPostProcessorHelper.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.impl.engine;
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.util.LinkedHashMap;
 import java.util.Locale;
@@ -23,6 +24,8 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 
+import org.apache.camel.BeanConfigInject;
+import org.apache.camel.BeanInject;
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.Consume;
@@ -38,12 +41,15 @@ import org.apache.camel.NoSuchBeanException;
 import org.apache.camel.PollingConsumer;
 import org.apache.camel.Producer;
 import org.apache.camel.ProducerTemplate;
+import org.apache.camel.PropertyInject;
 import org.apache.camel.ProxyInstantiationException;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.Service;
+import org.apache.camel.TypeConverter;
 import org.apache.camel.spi.BeanProxyFactory;
 import org.apache.camel.spi.PropertiesComponent;
 import org.apache.camel.spi.PropertyConfigurer;
+import org.apache.camel.spi.Registry;
 import org.apache.camel.support.CamelContextHelper;
 import org.apache.camel.support.PropertyBindingSupport;
 import org.apache.camel.support.service.ServiceHelper;
@@ -51,8 +57,10 @@ import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.apache.camel.support.ObjectHelper.invokeMethod;
+
 /**
- * A helper class for Camel based injector or bean post processing hooks.
+ * A helper class for Camel based injector or bean post-processing hooks.
  */
 public class CamelPostProcessorHelper implements CamelContextAware {
 
@@ -402,6 +410,86 @@ public class CamelPostProcessorHelper implements 
CamelContextAware {
         return bean;
     }
 
+    public Object getInjectionBeanMethodValue(
+            CamelContext context,
+            Method method, Object bean, String beanName) {
+        Class<?> returnType = method.getReturnType();
+        if (returnType == Void.TYPE) {
+            throw new IllegalArgumentException(
+                    "@BindToRegistry on class: " + method.getDeclaringClass()
+                                               + " method: " + 
method.getName() + " with void return type is not allowed");
+        }
+
+        Object value;
+        Object[] parameters = bindToRegistryParameterMapping(context, method);
+        if (parameters != null) {
+            value = invokeMethod(method, bean, parameters);
+        } else {
+            value = invokeMethod(method, bean);
+        }
+        return value;
+    }
+
+    private Object[] bindToRegistryParameterMapping(CamelContext context, 
Method method) {
+        if (method.getParameterCount() == 0) {
+            return null;
+        }
+
+        // map each parameter if possible
+        Object[] parameters = new Object[method.getParameterCount()];
+        for (int i = 0; i < method.getParameterCount(); i++) {
+            Class<?> type = method.getParameterTypes()[i];
+            if (type.isAssignableFrom(CamelContext.class)) {
+                parameters[i] = context;
+            } else if (type.isAssignableFrom(Registry.class)) {
+                parameters[i] = context.getRegistry();
+            } else if (type.isAssignableFrom(TypeConverter.class)) {
+                parameters[i] = context.getTypeConverter();
+            } else {
+                // we also support @BeanInject and @PropertyInject annotations
+                Annotation[] anns = method.getParameterAnnotations()[i];
+                if (anns.length == 1) {
+                    // we dont assume there are multiple annotations on the 
same parameter so grab first
+                    Annotation ann = anns[0];
+                    if (ann.annotationType() == PropertyInject.class) {
+                        PropertyInject pi = (PropertyInject) ann;
+                        Object result = getInjectionPropertyValue(type, 
pi.value(), pi.defaultValue(),
+                                null, null, null);
+                        parameters[i] = result;
+                    } else if (ann.annotationType() == BeanConfigInject.class) 
{
+                        BeanConfigInject pi = (BeanConfigInject) ann;
+                        Object result = getInjectionBeanConfigValue(type, 
pi.value());
+                        parameters[i] = result;
+                    } else if (ann.annotationType() == BeanInject.class) {
+                        BeanInject bi = (BeanInject) ann;
+                        Object result = getInjectionBeanValue(type, 
bi.value());
+                        parameters[i] = result;
+                    }
+                } else {
+                    // okay attempt to default to singleton instances from the 
registry
+                    Set<?> instances = context.getRegistry().findByType(type);
+                    if (instances.size() == 1) {
+                        parameters[i] = instances.iterator().next();
+                    } 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);
+                    }
+                }
+            }
+
+            // each parameter must be mapped
+            if (parameters[i] == null) {
+                int pos = i + 1;
+                throw new IllegalArgumentException("@BindToProperty cannot 
bind parameter #" + pos + " on method: " + method);
+            }
+        }
+
+        return parameters;
+    }
+
     /**
      * Factory method to create a {@link org.apache.camel.ProducerTemplate} to 
be injected into a POJO
      */
diff --git 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java
 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java
index 3a74646..6293b86 100644
--- 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java
+++ 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java
@@ -16,13 +16,11 @@
  */
 package org.apache.camel.impl.engine;
 
-import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 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;
@@ -35,9 +33,8 @@ import org.apache.camel.EndpointInject;
 import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.Produce;
 import org.apache.camel.PropertyInject;
-import org.apache.camel.TypeConverter;
 import org.apache.camel.spi.CamelBeanPostProcessor;
-import org.apache.camel.spi.Registry;
+import org.apache.camel.spi.CamelBeanPostProcessorInjector;
 import org.apache.camel.support.DefaultEndpoint;
 import org.apache.camel.util.ReflectionHelper;
 import org.slf4j.Logger;
@@ -65,6 +62,7 @@ import static org.apache.camel.util.ObjectHelper.isEmpty;
 public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor, 
CamelContextAware {
 
     protected static final Logger LOG = 
LoggerFactory.getLogger(DefaultCamelBeanPostProcessor.class);
+    protected final List<CamelBeanPostProcessorInjector> 
beanPostProcessorInjectors = new ArrayList<>();
     protected CamelPostProcessorHelper camelPostProcessorHelper;
     protected CamelContext camelContext;
     protected boolean enabled = true;
@@ -106,6 +104,11 @@ public class DefaultCamelBeanPostProcessor implements 
CamelBeanPostProcessor, Ca
     }
 
     @Override
+    public void addCamelBeanPostProjectInjector(CamelBeanPostProcessorInjector 
injector) {
+        this.beanPostProcessorInjectors.add(injector);
+    }
+
+    @Override
     public Object postProcessBeforeInitialization(Object bean, String 
beanName) throws Exception {
         LOG.trace("Camel bean processing before initialization for bean: {}", 
beanName);
 
@@ -268,6 +271,11 @@ public class DefaultCamelBeanPostProcessor implements 
CamelBeanPostProcessor, Ca
                 String uri = produce.value().isEmpty() ? produce.uri() : 
produce.value();
                 injectField(field, uri, produce.property(), bean, beanName, 
produce.binding());
             }
+
+            // custom bean injector on the field
+            for (CamelBeanPostProcessorInjector injector : 
beanPostProcessorInjectors) {
+                injector.onFieldInject(field, bean, beanName);
+            }
         });
     }
 
@@ -323,6 +331,11 @@ public class DefaultCamelBeanPostProcessor implements 
CamelBeanPostProcessor, Ca
 
             setterInjection(method, bean, beanName);
             getPostProcessorHelper().consumerInjection(method, bean, beanName);
+
+            // custom bean injector on the method
+            for (CamelBeanPostProcessorInjector injector : 
beanPostProcessorInjectors) {
+                injector.onMethodInject(method, bean, beanName);
+            }
         });
     }
 
@@ -498,12 +511,11 @@ public class DefaultCamelBeanPostProcessor implements 
CamelBeanPostProcessor, Ca
         }
         Object value = ReflectionHelper.getField(field, bean);
 
-        // use dependency injection factory to perform the task of binding the 
bean to registry
         if (value != null) {
-
             if (unbindEnabled) {
                 getOrLookupCamelContext().getRegistry().unbind(name);
             }
+            // use dependency injection factory to perform the task of binding 
the bean to registry
             Runnable task = 
getOrLookupCamelContext().adapt(ExtendedCamelContext.class)
                     .getDependencyInjectionAnnotationFactory()
                     .createBindToRegistryFactory(name, value, beanName, 
beanPostProcess);
@@ -515,26 +527,14 @@ public class DefaultCamelBeanPostProcessor implements 
CamelBeanPostProcessor, Ca
         if (isEmpty(name)) {
             name = method.getName();
         }
-        Class<?> returnType = method.getReturnType();
-        if (returnType == null || returnType == Void.TYPE) {
-            throw new IllegalArgumentException(
-                    "@BindToRegistry on class: " + method.getDeclaringClass()
-                                               + " method: " + 
method.getName() + " with void return type is not allowed");
-        }
+        Object value = getPostProcessorHelper()
+                .getInjectionBeanMethodValue(getOrLookupCamelContext(), 
method, bean, beanName);
 
-        Object value;
-        Object[] parameters = bindToRegistryParameterMapping(method);
-        if (parameters != null) {
-            value = invokeMethod(method, bean, parameters);
-        } else {
-            value = invokeMethod(method, bean);
-        }
-        // use dependency injection factory to perform the task of binding the 
bean to registry
         if (value != null) {
-
             if (unbindEnabled) {
                 getOrLookupCamelContext().getRegistry().unbind(name);
             }
+            // use dependency injection factory to perform the task of binding 
the bean to registry
             Runnable task = 
getOrLookupCamelContext().adapt(ExtendedCamelContext.class)
                     .getDependencyInjectionAnnotationFactory()
                     .createBindToRegistryFactory(name, value, beanName, 
beanPostProcess);
@@ -542,66 +542,6 @@ public class DefaultCamelBeanPostProcessor implements 
CamelBeanPostProcessor, Ca
         }
     }
 
-    private Object[] bindToRegistryParameterMapping(Method method) {
-        if (method.getParameterCount() == 0) {
-            return null;
-        }
-
-        // map each parameter if possible
-        Object[] parameters = new Object[method.getParameterCount()];
-        for (int i = 0; i < method.getParameterCount(); i++) {
-            Class<?> type = method.getParameterTypes()[i];
-            if (type.isAssignableFrom(CamelContext.class)) {
-                parameters[i] = getOrLookupCamelContext();
-            } else if (type.isAssignableFrom(Registry.class)) {
-                parameters[i] = getOrLookupCamelContext().getRegistry();
-            } else if (type.isAssignableFrom(TypeConverter.class)) {
-                parameters[i] = getOrLookupCamelContext().getTypeConverter();
-            } else {
-                // we also support @BeanInject and @PropertyInject annotations
-                Annotation[] anns = method.getParameterAnnotations()[i];
-                if (anns.length == 1) {
-                    // we dont assume there are multiple annotations on the 
same parameter so grab first
-                    Annotation ann = anns[0];
-                    if (ann.annotationType() == PropertyInject.class) {
-                        PropertyInject pi = (PropertyInject) ann;
-                        Object result = 
getPostProcessorHelper().getInjectionPropertyValue(type, pi.value(), 
pi.defaultValue(),
-                                null, null, null);
-                        parameters[i] = result;
-                    } else if (ann.annotationType() == BeanConfigInject.class) 
{
-                        BeanConfigInject pi = (BeanConfigInject) ann;
-                        Object result = 
getPostProcessorHelper().getInjectionBeanConfigValue(type, pi.value());
-                        parameters[i] = result;
-                    } else if (ann.annotationType() == BeanInject.class) {
-                        BeanInject bi = (BeanInject) ann;
-                        Object result = 
getPostProcessorHelper().getInjectionBeanValue(type, bi.value());
-                        parameters[i] = result;
-                    }
-                } else {
-                    // okay attempt to default to singleton instances from the 
registry
-                    Set<?> instances = 
getOrLookupCamelContext().getRegistry().findByType(type);
-                    if (instances.size() == 1) {
-                        parameters[i] = instances.iterator().next();
-                    } 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);
-                    }
-                }
-            }
-
-            // each parameter must be mapped
-            if (parameters[i] == null) {
-                int pos = i + 1;
-                throw new IllegalArgumentException("@BindToProperty cannot 
bind parameter #" + pos + " on method: " + method);
-            }
-        }
-
-        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/CamelBeanPostProcessorInjectorTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/impl/CamelBeanPostProcessorInjectorTest.java
new file mode 100644
index 0000000..dc9793a
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/impl/CamelBeanPostProcessorInjectorTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.PropertyInject;
+import org.apache.camel.impl.engine.CamelPostProcessorHelper;
+import org.apache.camel.spi.CamelBeanPostProcessor;
+import org.apache.camel.spi.CamelBeanPostProcessorInjector;
+import org.apache.camel.spi.CamelLogger;
+import org.apache.camel.support.ObjectHelper;
+import org.apache.camel.util.ReflectionHelper;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class CamelBeanPostProcessorInjectorTest extends ContextTestSupport {
+
+    private CamelBeanPostProcessor postProcessor;
+    private CamelPostProcessorHelper helper;
+
+    @Override
+    @BeforeEach
+    public void setUp() throws Exception {
+        super.setUp();
+        postProcessor = 
context.adapt(ExtendedCamelContext.class).getBeanPostProcessor();
+        postProcessor.addCamelBeanPostProjectInjector(new MyInjector());
+        helper = new CamelPostProcessorHelper(context);
+    }
+
+    private class MyInjector implements CamelBeanPostProcessorInjector {
+
+        @Override
+        public void onFieldInject(Field field, Object bean, String beanName) {
+            if (field.getName().equals("foo")) {
+                ReflectionHelper.setField(field, bean, "changed-foo");
+            }
+        }
+
+        @Override
+        public void onMethodInject(Method method, Object bean, String 
beanName) {
+            if (method.getName().equals("createLogger")) {
+                Object out = ObjectHelper.invokeMethod(method, bean, 
"changed-bar");
+                context.getRegistry().bind(method.getName(), out);
+            }
+        }
+    }
+
+    public class MyService {
+
+        @PropertyInject(value = "myName", defaultValue = "Donald Duck")
+        private String name;
+        @PropertyInject(value = "myFoo", defaultValue = "myDefault")
+        private String foo;
+
+        public String getName() {
+            return name;
+        }
+
+        public String getFoo() {
+            return foo;
+        }
+
+        public CamelLogger createLogger(String name) {
+            return new CamelLogger(name);
+        }
+    }
+
+    @Test
+    public void testBeanPostInjector() throws Exception {
+        MyService service = new MyService();
+
+        postProcessor.postProcessBeforeInitialization(service, "service");
+        postProcessor.postProcessAfterInitialization(service, "service");
+
+        Assertions.assertEquals("Donald Duck", service.getName());
+        Assertions.assertEquals("changed-foo", service.getFoo());
+
+        CamelLogger logger = (CamelLogger) 
context.getRegistry().lookupByName("createLogger");
+        Assertions.assertNotNull(logger);
+    }
+
+}
diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
index 4a58944..ba8a54f 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
@@ -238,6 +238,40 @@ curl http://localhost:8080/hello
 Hello World%
 ----
 
+=== Dependency Injection in Java classes
+
+When running Camel applications with camel-jbang, then the runtime is 
`camel-main` based. This means
+there is no Spring Boot, or Quarkus available. However, we have added support 
for using annotation
+based dependency injection in Java classes.
+
+==== Using Camel dependency injection
+
+You can use the following Camel annotations (they work on all runtimes):
+
+- `@BindToRegistry` on class level to create an instance of the class and 
register in the xref:registry.adoc[Registry].
+- `@BeanInject` to dependency inject a bean on a class field.
+- `@PropertyInject` to inject a xref:using-propertyplaceholder.adoc[property 
placeholder]. Such as a property defined in `application.properties`.
+- `@BindToRegistry` on a method to create a bean by invoking the method.
+- `@Converter` on class level to auto-register the 
xref:type-converter.adoc[type converters] from the class.
+
+==== Using Spring Boot dependency injection
+
+You can use the following Spring Boot annotations:
+
+- `@Component` or `@Service` on class level to create an instance of the class 
and register in the xref:registry.adoc[Registry].
+- `@Autowired` to dependency inject a bean on a class field. `@Qualifier` can 
be used to specify the bean id.
+- `@Value` to inject a xref:using-propertyplaceholder.adoc[property 
placeholder]. Such as a property defined in `application.properties`.
+- `@Bean` on a method to create a bean by invoking the method.
+
+==== Using Quarkus injection
+
+You can use the following Quarkus annotations:
+
+- `@ApplicationScoped` or `@Singleton` on class level to create an instance of 
the class and register in the xref:registry.adoc[Registry]. `@Named` can be 
used to specify the bean id.
+- `@Inject` to dependency inject an bean on a class field. `@Named` can be 
used to specify the bean id.
+- `@ConfigProperty` to inject a xref:using-propertyplaceholder.adoc[property 
placeholder]. Such as a property defined in `application.properties`.
+- `@Produces` on a method to create a bean by invoking the method. `@Named` 
can be used to specify the bean id.
+
 === Debugging
 
 You can debug both camel@apache/camel and your integration scripts by making 
use of the `--debug` flag provided by JBang:
diff --git 
a/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/CompilePostProcessor.java
 
b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/CompilePostProcessor.java
new file mode 100644
index 0000000..021a97f
--- /dev/null
+++ 
b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/CompilePostProcessor.java
@@ -0,0 +1,44 @@
+/*
+ * 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.dsl.support;
+
+import org.apache.camel.CamelContext;
+
+/**
+ * Allows to plugin custom post processors that are processed after the DSL 
has loaded the source and compiled into a
+ * Java object.
+ * <p/>
+ * This is used to detect and handle {@link org.apache.camel.BindToRegistry} 
and {@link org.apache.camel.Converter}
+ * classes.
+ */
+public interface CompilePostProcessor {
+
+    /**
+     * Invoked after the class has been compiled
+     *
+     * @param  camelContext the camel context
+     * @param  name         the name of the resource/class
+     * @param  clazz        the class
+     * @param  instance     the object created as instance of the class (if 
any)
+     * @throws Exception    is thrown if error during post-processing
+     */
+    void postCompile(
+            CamelContext camelContext, String name,
+            Class<?> clazz, Object instance)
+            throws Exception;
+
+}
diff --git 
a/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
 
b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
index 11fbc8f..c961867 100644
--- 
a/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
+++ 
b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
@@ -16,6 +16,10 @@
  */
 package org.apache.camel.dsl.support;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.RoutesBuilder;
@@ -33,7 +37,7 @@ import org.apache.camel.support.RoutesBuilderLoaderSupport;
  */
 public abstract class RouteBuilderLoaderSupport extends 
RoutesBuilderLoaderSupport {
     private final String extension;
-
+    private final List<CompilePostProcessor> compilePostProcessors = new 
ArrayList<>();
     private StartupStepRecorder recorder;
 
     protected RouteBuilderLoaderSupport(String extension) {
@@ -46,6 +50,21 @@ public abstract class RouteBuilderLoaderSupport extends 
RoutesBuilderLoaderSuppo
         return extension;
     }
 
+    /**
+     * Gets the registered {@link CompilePostProcessor}.
+     */
+    public List<CompilePostProcessor> getCompilePostProcessors() {
+        return compilePostProcessors;
+    }
+
+    /**
+     * Add a custom {@link CompilePostProcessor} to handle specific 
post-processing after compiling the source into a
+     * Java object.
+     */
+    public void addCompilePostProcessor(CompilePostProcessor preProcessor) {
+        this.compilePostProcessors.add(preProcessor);
+    }
+
     @Override
     protected void doBuild() throws Exception {
         super.doBuild();
@@ -56,6 +75,21 @@ public abstract class RouteBuilderLoaderSupport extends 
RoutesBuilderLoaderSuppo
     }
 
     @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+
+        if (getCamelContext() != null) {
+            // discover optional compile post-processors to be used
+            Set<CompilePostProcessor> pres = 
getCamelContext().getRegistry().findByType(CompilePostProcessor.class);
+            if (pres != null && !pres.isEmpty()) {
+                for (CompilePostProcessor pre : pres) {
+                    addCompilePostProcessor(pre);
+                }
+            }
+        }
+    }
+
+    @Override
     public RoutesBuilder loadRoutesBuilder(Resource resource) throws Exception 
{
         final RouteBuilder builder = doLoadRouteBuilder(resource);
         if (builder != null) {
diff --git 
a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
 
b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
index dd149db..c29e54d 100644
--- 
a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
+++ 
b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
@@ -21,24 +21,15 @@ import java.io.InputStream;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import org.apache.camel.BindToRegistry;
-import org.apache.camel.CamelConfiguration;
-import org.apache.camel.Configuration;
-import org.apache.camel.Converter;
-import org.apache.camel.ExtendedCamelContext;
-import org.apache.camel.LoggingLevel;
-import org.apache.camel.TypeConverterExists;
 import org.apache.camel.api.management.ManagedResource;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.dsl.support.CompilePostProcessor;
 import org.apache.camel.dsl.support.RouteBuilderLoaderSupport;
-import org.apache.camel.spi.CamelBeanPostProcessor;
 import org.apache.camel.spi.Resource;
-import org.apache.camel.spi.TypeConverterRegistry;
 import org.apache.camel.spi.annotations.RoutesLoader;
 import org.apache.camel.support.ResourceHelper;
 import org.apache.camel.util.FileUtil;
 import org.apache.camel.util.IOHelper;
-import org.apache.camel.util.ObjectHelper;
 import org.joor.Reflect;
 
 @ManagedResource(description = "Managed JavaRoutesBuilderLoader")
@@ -63,51 +54,16 @@ public class JavaRoutesBuilderLoader extends 
RouteBuilderLoaderSupport {
 
             Reflect ref = Reflect.compile(name, content).create();
             Class<?> clazz = ref.type();
+            Object obj = ref.get();
 
-            if (clazz.getAnnotation(Converter.class) != null) {
-                TypeConverterRegistry tcr = 
getCamelContext().getTypeConverterRegistry();
-                TypeConverterExists exists = tcr.getTypeConverterExists();
-                LoggingLevel level = tcr.getTypeConverterExistsLoggingLevel();
-                // force type converter to override as we could be re-loading
-                tcr.setTypeConverterExists(TypeConverterExists.Override);
-                tcr.setTypeConverterExistsLoggingLevel(LoggingLevel.OFF);
-                try {
-                    tcr.addTypeConverters(clazz);
-                } finally {
-                    tcr.setTypeConverterExists(exists);
-                    tcr.setTypeConverterExistsLoggingLevel(level);
-                }
-                return null;
+            // support custom annotation scanning post compilation
+            // such as to register custom beans, type converters, etc.
+            for (CompilePostProcessor pre : getCompilePostProcessors()) {
+                pre.postCompile(getCamelContext(), name, clazz, obj);
             }
 
-            Object obj = ref.get();
             if (obj instanceof RouteBuilder) {
                 return (RouteBuilder) obj;
-            } else if (obj != null) {
-                BindToRegistry bir = 
obj.getClass().getAnnotation(BindToRegistry.class);
-                Configuration cfg = 
obj.getClass().getAnnotation(Configuration.class);
-                if (bir != null || cfg != null || obj instanceof 
CamelConfiguration) {
-                    CamelBeanPostProcessor bpp = 
getCamelContext().adapt(ExtendedCamelContext.class).getBeanPostProcessor();
-                    if (bir != null && ObjectHelper.isNotEmpty(bir.value())) {
-                        name = bir.value();
-                    } else if (cfg != null && 
ObjectHelper.isNotEmpty(cfg.value())) {
-                        name = cfg.value();
-                    }
-                    // to support hot reloading of beans then we need to 
enable unbind mode in bean post processor
-                    bpp.setUnbindEnabled(true);
-                    try {
-                        // this class is a bean service which needs to be post 
processed and registered which happens
-                        // automatic by the bean post processor
-                        bpp.postProcessBeforeInitialization(obj, name);
-                        bpp.postProcessAfterInitialization(obj, name);
-                    } finally {
-                        bpp.setUnbindEnabled(false);
-                    }
-                    if (obj instanceof CamelConfiguration) {
-                        ((CamelConfiguration) 
obj).configure(getCamelContext());
-                    }
-                    return null;
-                }
             }
             return null;
         }
@@ -127,4 +83,5 @@ public class JavaRoutesBuilderLoader extends 
RouteBuilderLoaderSupport {
                 ? matcher.group(1) + "." + name
                 : name;
     }
+
 }
diff --git a/dsl/camel-kamelet-main/pom.xml b/dsl/camel-kamelet-main/pom.xml
index c1b4f9f..9ae5ade 100644
--- a/dsl/camel-kamelet-main/pom.xml
+++ b/dsl/camel-kamelet-main/pom.xml
@@ -105,6 +105,38 @@
             <artifactId>camel-catalog-console</artifactId>
         </dependency>
 
+        <!-- optional spring annotation support -->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
+            <version>${spring-version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework</groupId>
+                    <artifactId>spring-aop</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.springframework</groupId>
+                    <artifactId>spring-core</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.springframework</groupId>
+                    <artifactId>spring-expression</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <!-- optional quarkus annotation support -->
+        <dependency>
+            <groupId>jakarta.enterprise</groupId>
+            <artifactId>jakarta.enterprise.cdi-api</artifactId>
+            <version>${jakarta-cdi-api-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.microprofile.config</groupId>
+            <artifactId>microprofile-config-api</artifactId>
+            <version>${microprofile-config-version}</version>
+        </dependency>
+
         <dependency>
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-timer</artifactId>
diff --git 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/AnnotationDependencyInjection.java
 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/AnnotationDependencyInjection.java
new file mode 100644
index 0000000..6689408
--- /dev/null
+++ 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/AnnotationDependencyInjection.java
@@ -0,0 +1,286 @@
+/*
+ * 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.BindToRegistry;
+import org.apache.camel.CamelConfiguration;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Configuration;
+import org.apache.camel.Converter;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.LoggingLevel;
+import org.apache.camel.NoSuchBeanException;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.TypeConverterExists;
+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.spi.Registry;
+import org.apache.camel.spi.TypeConverterRegistry;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.ReflectionHelper;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Service;
+
+/**
+ * To enable camel/spring/quarkus based annotations for dependency injection 
when loading DSLs.
+ */
+public final class AnnotationDependencyInjection {
+
+    private AnnotationDependencyInjection() {
+    }
+
+    public static void initAnnotationBasedDependencyInjection(CamelContext 
context) {
+        Registry registry = context.getRegistry();
+        CamelBeanPostProcessor cbbp = 
context.adapt(ExtendedCamelContext.class).getBeanPostProcessor();
+
+        // camel / common
+        registry.bind("CamelTypeConverterCompilePostProcessor", new 
TypeConverterCompilePostProcessor());
+        registry.bind("CamelBindToRegistryCompilePostProcessor", new 
BindToRegistryCompilePostProcessor());
+        // spring
+        registry.bind("SpringAnnotationCompilePostProcessor", new 
SpringAnnotationCompilePostProcessor());
+        cbbp.addCamelBeanPostProjectInjector(new 
SpringBeanPostProcessorInjector(context));
+        // quarkus
+        registry.bind("QuarkusAnnotationCompilePostProcessor", new 
QuarkusAnnotationCompilePostProcessor());
+        cbbp.addCamelBeanPostProjectInjector(new 
QuarkusBeanPostProcessorInjector(context));
+    }
+
+    private static class TypeConverterCompilePostProcessor implements 
CompilePostProcessor {
+
+        @Override
+        public void postCompile(CamelContext camelContext, String name, 
Class<?> clazz, Object instance) throws Exception {
+            if (clazz.isAnnotationPresent(Converter.class)) {
+                TypeConverterRegistry tcr = 
camelContext.getTypeConverterRegistry();
+                TypeConverterExists exists = tcr.getTypeConverterExists();
+                LoggingLevel level = tcr.getTypeConverterExistsLoggingLevel();
+                // force type converter to override as we could be re-loading
+                tcr.setTypeConverterExists(TypeConverterExists.Override);
+                tcr.setTypeConverterExistsLoggingLevel(LoggingLevel.OFF);
+                try {
+                    tcr.addTypeConverters(clazz);
+                } finally {
+                    tcr.setTypeConverterExists(exists);
+                    tcr.setTypeConverterExistsLoggingLevel(level);
+                }
+            }
+        }
+
+    }
+
+    private static class BindToRegistryCompilePostProcessor implements 
CompilePostProcessor {
+
+        @Override
+        public void postCompile(CamelContext camelContext, String name, 
Class<?> clazz, Object instance) throws Exception {
+            BindToRegistry bir = 
instance.getClass().getAnnotation(BindToRegistry.class);
+            Configuration cfg = 
instance.getClass().getAnnotation(Configuration.class);
+            if (bir != null || cfg != null || instance instanceof 
CamelConfiguration) {
+                CamelBeanPostProcessor bpp = 
camelContext.adapt(ExtendedCamelContext.class).getBeanPostProcessor();
+                if (bir != null && ObjectHelper.isNotEmpty(bir.value())) {
+                    name = bir.value();
+                } else if (cfg != null && 
ObjectHelper.isNotEmpty(cfg.value())) {
+                    name = cfg.value();
+                }
+                // to support hot reloading of beans then we need to enable 
unbind mode in bean post processor
+                bpp.setUnbindEnabled(true);
+                try {
+                    // this class uses camels own annotations so the bind to 
registry happens
+                    // automatic by the bean post processor
+                    bpp.postProcessBeforeInitialization(instance, name);
+                    bpp.postProcessAfterInitialization(instance, name);
+                } finally {
+                    bpp.setUnbindEnabled(false);
+                }
+                if (instance instanceof CamelConfiguration) {
+                    ((CamelConfiguration) instance).configure(camelContext);
+                }
+            }
+        }
+
+    }
+
+    private static class SpringAnnotationCompilePostProcessor implements 
CompilePostProcessor {
+
+        @Override
+        public void postCompile(CamelContext camelContext, String name, 
Class<?> clazz, Object instance) throws Exception {
+            // @Component and @Service are the same
+            Component comp = clazz.getAnnotation(Component.class);
+            Service service = clazz.getAnnotation(Service.class);
+            if (comp != null || service != null) {
+                CamelBeanPostProcessor bpp = 
camelContext.adapt(ExtendedCamelContext.class).getBeanPostProcessor();
+                if (comp != null && ObjectHelper.isNotEmpty(comp.value())) {
+                    name = comp.value();
+                } else if (service != null && 
ObjectHelper.isNotEmpty(service.value())) {
+                    name = service.value();
+                }
+                bindBean(camelContext, name, instance, true);
+            }
+        }
+    }
+
+    private static class SpringBeanPostProcessorInjector implements 
CamelBeanPostProcessorInjector {
+
+        private final CamelContext context;
+        private final CamelPostProcessorHelper helper;
+
+        public SpringBeanPostProcessorInjector(CamelContext context) {
+            this.context = context;
+            this.helper = new CamelPostProcessorHelper(context);
+        }
+
+        @Override
+        public void onFieldInject(Field field, Object bean, String beanName) {
+            Autowired autowired = field.getAnnotation(Autowired.class);
+            if (autowired != null) {
+                String name = null;
+                Qualifier qualifier = field.getAnnotation(Qualifier.class);
+                if (qualifier != null) {
+                    name = qualifier.value();
+                }
+
+                try {
+                    ReflectionHelper.setField(field, bean,
+                            helper.getInjectionBeanValue(field.getType(), 
name));
+                } catch (NoSuchBeanException e) {
+                    if (autowired.required()) {
+                        throw e;
+                    }
+                    // not required so ignore
+                }
+            }
+            Value value = field.getAnnotation(Value.class);
+            if (value != null) {
+                ReflectionHelper.setField(field, bean,
+                        helper.getInjectionPropertyValue(field.getType(), 
value.value(), null, null, bean, beanName));
+            }
+        }
+
+        @Override
+        public void onMethodInject(Method method, Object bean, String 
beanName) {
+            Bean bi = method.getAnnotation(Bean.class);
+            if (bi != null) {
+                Object instance = helper.getInjectionBeanMethodValue(context, 
method, bean, beanName);
+                if (instance != null) {
+                    String name = method.getName();
+                    if (bi.name().length > 0) {
+                        name = bi.name()[0];
+                    }
+                    bindBean(context, name, instance, false);
+                }
+            }
+        }
+    }
+
+    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();
+                }
+                bindBean(camelContext, name, instance, true);
+            }
+        }
+    }
+
+    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();
+                    }
+                    bindBean(context, name, instance, false);
+                }
+            }
+        }
+    }
+
+    private static void bindBean(CamelContext context, String name, Object 
instance, boolean postProcess) {
+        // to support hot reloading of beans then we need to enable unbind 
mode in bean post processor
+        Registry registry = context.getRegistry();
+        CamelBeanPostProcessor bpp = 
context.adapt(ExtendedCamelContext.class).getBeanPostProcessor();
+        bpp.setUnbindEnabled(true);
+        try {
+            // re-bind the bean to the registry
+            registry.unbind(name);
+            registry.bind(name, instance);
+            if (postProcess) {
+                bpp.postProcessBeforeInitialization(instance, name);
+                bpp.postProcessAfterInitialization(instance, name);
+            }
+        } catch (Exception e) {
+            throw RuntimeCamelException.wrapRuntimeException(e);
+        } finally {
+            bpp.setUnbindEnabled(false);
+        }
+    }
+
+}
diff --git 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/DependencyDownloaderKamelet.java
 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/DependencyDownloaderKamelet.java
index f4155e3..269088b 100644
--- 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/DependencyDownloaderKamelet.java
+++ 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/DependencyDownloaderKamelet.java
@@ -16,21 +16,36 @@
  */
 package org.apache.camel.main;
 
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.kamelet.KameletComponent;
+import org.apache.camel.dsl.yaml.YamlRoutesBuilderLoaderSupport;
 import org.apache.camel.spi.Resource;
 import org.apache.camel.spi.RouteTemplateLoaderListener;
 import org.apache.camel.support.service.ServiceHelper;
 import org.apache.camel.support.service.ServiceSupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.snakeyaml.engine.v2.nodes.Node;
+import org.snakeyaml.engine.v2.nodes.NodeType;
+import org.snakeyaml.engine.v2.nodes.ScalarNode;
+import org.snakeyaml.engine.v2.nodes.SequenceNode;
+
+import static org.apache.camel.dsl.yaml.common.YamlDeserializerSupport.nodeAt;
 
 /**
  * To automatic downloaded dependencies that Kamelets requires.
  */
 final class DependencyDownloaderKamelet extends ServiceSupport implements 
CamelContextAware, RouteTemplateLoaderListener {
 
-    private final KameletYamlRoutes downloader = new KameletYamlRoutes("yaml");
+    private final KameletDependencyDownloader downloader = new 
KameletDependencyDownloader("yaml");
     private CamelContext camelContext;
 
     @Override
@@ -77,4 +92,98 @@ final class DependencyDownloaderKamelet extends 
ServiceSupport implements CamelC
             }
         }
     }
+
+    /**
+     * To automatic downloaded dependencies that Kamelets requires.
+     */
+    private static class KameletDependencyDownloader extends 
YamlRoutesBuilderLoaderSupport implements CamelContextAware {
+
+        private static final Logger LOG = 
LoggerFactory.getLogger(KameletDependencyDownloader.class);
+        private CamelContext camelContext;
+        private final Set<String> downloaded = new HashSet<>();
+
+        public KameletDependencyDownloader(String extension) {
+            super(extension);
+        }
+
+        @Override
+        public CamelContext getCamelContext() {
+            return camelContext;
+        }
+
+        @Override
+        public void setCamelContext(CamelContext camelContext) {
+            this.camelContext = camelContext;
+        }
+
+        @Override
+        protected RouteBuilder builder(Node node, Resource resource) {
+            final List<String> dependencies = new ArrayList<>();
+
+            Node deps = nodeAt(node, "/spec/dependencies");
+            if (deps != null && deps.getNodeType() == NodeType.SEQUENCE) {
+                SequenceNode sn = (SequenceNode) deps;
+                for (Node child : sn.getValue()) {
+                    if (child.getNodeType() == NodeType.SCALAR) {
+                        ScalarNode scn = (ScalarNode) child;
+                        String dep = scn.getValue();
+                        if (dep != null) {
+                            LOG.trace("Kamelet dependency: {}", dep);
+                            dependencies.add(dep);
+                        }
+                    }
+                }
+            }
+
+            downloadDependencies(dependencies);
+
+            // need to fool and return an empty route builder
+            return new RouteBuilder() {
+                @Override
+                public void configure() throws Exception {
+                    // noop
+                }
+            };
+        }
+
+        private void downloadDependencies(List<String> dependencies) {
+            final List<String> gavs = new ArrayList<>();
+            for (String dep : dependencies) {
+                String gav = dep;
+                if (dep.startsWith("camel:")) {
+                    // it's a known camel component
+                    gav = "org.apache.camel:camel-" + dep.substring(6) + ":" + 
camelContext.getVersion();
+                }
+                if (isValidGav(gav)) {
+                    gavs.add(gav);
+                }
+            }
+
+            if (!gavs.isEmpty()) {
+                for (String gav : gavs) {
+                    MavenGav mg = MavenGav.parseGav(camelContext, gav);
+                    DownloaderHelper.downloadDependency(camelContext, 
mg.getGroupId(), mg.getArtifactId(), mg.getVersion());
+                    downloaded.add(gav);
+                }
+            }
+        }
+
+        private boolean isValidGav(String gav) {
+            if (downloaded.contains(gav)) {
+                // already downloaded
+                return false;
+            }
+
+            // skip camel-core and camel-kamelet as they are already included
+            if (gav.contains("org.apache.camel:camel-core") || 
gav.contains("org.apache.camel:camel-kamelet:")) {
+                return false;
+            }
+
+            MavenGav mg = MavenGav.parseGav(camelContext, gav);
+            boolean exists = DownloaderHelper.alreadyOnClasspath(camelContext, 
mg.getArtifactId(), mg.getVersion());
+            // valid if not already on classpath
+            return !exists;
+        }
+
+    }
 }
diff --git 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
index 665c872..48a7167 100644
--- 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
+++ 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
@@ -31,6 +31,7 @@ import 
org.apache.camel.startup.jfr.FlightRecorderStartupStepRecorder;
  * A Main class for booting up Camel with Kamelet in standalone mode.
  */
 public class KameletMain extends MainCommandLineSupport {
+
     public static final String DEFAULT_KAMELETS_LOCATION = 
"classpath:/kamelets,github:apache:camel-kamelets/kamelets";
 
     private static ClassLoader kameletClassLoader;
@@ -163,6 +164,8 @@ public class KameletMain extends MainCommandLineSupport {
         answer.setRegistry(registry);
         // load camel component and custom health-checks
         answer.setLoadHealthChecks(true);
+        // annotation based dependency injection for camel/spring/quarkus 
annotations in DSLs and Java beans
+        
AnnotationDependencyInjection.initAnnotationBasedDependencyInjection(answer);
 
         // embed HTTP server if port is specified
         Object port = 
getInitialProperties().get("camel.jbang.platform-http.port");
diff --git 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletYamlRoutes.java
 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletYamlRoutes.java
deleted file mode 100644
index a57422c..0000000
--- 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletYamlRoutes.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * 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.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.apache.camel.CamelContext;
-import org.apache.camel.CamelContextAware;
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.dsl.yaml.YamlRoutesBuilderLoaderSupport;
-import org.apache.camel.spi.Resource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.snakeyaml.engine.v2.nodes.Node;
-import org.snakeyaml.engine.v2.nodes.NodeType;
-import org.snakeyaml.engine.v2.nodes.ScalarNode;
-import org.snakeyaml.engine.v2.nodes.SequenceNode;
-
-import static org.apache.camel.dsl.yaml.common.YamlDeserializerSupport.nodeAt;
-
-/**
- * Reuse the YAML DSL support for parsing Kamelets
- */
-class KameletYamlRoutes extends YamlRoutesBuilderLoaderSupport implements 
CamelContextAware {
-
-    private static final Logger LOG = 
LoggerFactory.getLogger(KameletYamlRoutes.class);
-    private CamelContext camelContext;
-    private final Set<String> downloaded = new HashSet<>();
-
-    public KameletYamlRoutes(String extension) {
-        super(extension);
-    }
-
-    @Override
-    public CamelContext getCamelContext() {
-        return camelContext;
-    }
-
-    @Override
-    public void setCamelContext(CamelContext camelContext) {
-        this.camelContext = camelContext;
-    }
-
-    @Override
-    protected RouteBuilder builder(Node node, Resource resource) {
-        final List<String> dependencies = new ArrayList<>();
-
-        Node deps = nodeAt(node, "/spec/dependencies");
-        if (deps != null && deps.getNodeType() == NodeType.SEQUENCE) {
-            SequenceNode sn = (SequenceNode) deps;
-            for (Node child : sn.getValue()) {
-                if (child.getNodeType() == NodeType.SCALAR) {
-                    ScalarNode scn = (ScalarNode) child;
-                    String dep = scn.getValue();
-                    if (dep != null) {
-                        LOG.trace("Kamelet dependency: {}", dep);
-                        dependencies.add(dep);
-                    }
-                }
-            }
-        }
-
-        downloadDependencies(dependencies);
-
-        // need to fool and return an empty route builder
-        return new RouteBuilder() {
-            @Override
-            public void configure() throws Exception {
-                // noop
-            }
-        };
-    }
-
-    private void downloadDependencies(List<String> dependencies) {
-        final List<String> gavs = new ArrayList<>();
-        for (String dep : dependencies) {
-            String gav = dep;
-            if (dep.startsWith("camel:")) {
-                // it's a known camel component
-                gav = "org.apache.camel:camel-" + dep.substring(6) + ":" + 
camelContext.getVersion();
-            }
-            if (isValidGav(gav)) {
-                gavs.add(gav);
-            }
-        }
-
-        if (!gavs.isEmpty()) {
-            for (String gav : gavs) {
-                MavenGav mg = MavenGav.parseGav(camelContext, gav);
-                DownloaderHelper.downloadDependency(camelContext, 
mg.getGroupId(), mg.getArtifactId(), mg.getVersion());
-                downloaded.add(gav);
-            }
-        }
-    }
-
-    private boolean isValidGav(String gav) {
-        if (downloaded.contains(gav)) {
-            // already downloaded
-            return false;
-        }
-
-        // skip camel-core and camel-kamelet as they are already included
-        if (gav.contains("org.apache.camel:camel-core") || 
gav.contains("org.apache.camel:camel-kamelet:")) {
-            return false;
-        }
-
-        MavenGav mg = MavenGav.parseGav(camelContext, gav);
-        boolean exists = DownloaderHelper.alreadyOnClasspath(camelContext, 
mg.getArtifactId(), mg.getVersion());
-        // valid if not already on classpath
-        return !exists;
-    }
-
-}
diff --git a/parent/pom.xml b/parent/pom.xml
index d7f50a1..927c622 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -288,6 +288,7 @@
         <javax-annotation-api-version>1.3.2</javax-annotation-api-version>
         <jakarta-mail-version>1.6.6</jakarta-mail-version>
         <javax-servlet-api-version>3.1.0</javax-servlet-api-version>
+        <jakarta-cdi-api-version>2.0.2</jakarta-cdi-api-version>
         <jakarta-api-version>2.1.5</jakarta-api-version>
         <jakarta.el-version>3.0.3</jakarta.el-version>
         <jakarta-jaxb-version>2.3.3</jakarta-jaxb-version>

Reply via email to