You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by GitBox <gi...@apache.org> on 2022/03/14 11:16:43 UTC

[GitHub] [camel] davsclaus opened a new pull request #7200: Camel 17571

davsclaus opened a new pull request #7200:
URL: https://github.com/apache/camel/pull/7200


   CAMEL-17571: camel-jbang - Support for quarkus/cdi annotations in custom beans for dependency injection support


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [camel] davsclaus merged pull request #7200: Camel 17571

Posted by GitBox <gi...@apache.org>.
davsclaus merged pull request #7200:
URL: https://github.com/apache/camel/pull/7200


   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [camel] essobedo commented on a change in pull request #7200: Camel 17571

Posted by GitBox <gi...@apache.org>.
essobedo commented on a change in pull request #7200:
URL: https://github.com/apache/camel/pull/7200#discussion_r825850199



##########
File path: 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 an 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 `@Single` 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.

Review comment:
       `@Single`? Did you mean `@Singleton`?

##########
File path: 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 an bean on a class field. `@Qualifier` can be used to specify the bean id.

Review comment:
       ```suggestion
   - `@Autowired` to dependency inject a bean on a class field. `@Qualifier` can be used to specify the bean id.
   ```

##########
File path: dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/AnnotationDependencyInjection.java
##########
@@ -0,0 +1,306 @@
+/*
+ * 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.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.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) {
+        // camel / common
+        context.getRegistry().bind("CamelTypeConverterCompilePostProcessor", new TypeConverterCompilePostProcessor());

Review comment:
       You could keep the registry into a local variable as it is used several times.

##########
File path: dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/AnnotationDependencyInjection.java
##########
@@ -0,0 +1,306 @@
+/*
+ * 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.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.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) {
+        // camel / common
+        context.getRegistry().bind("CamelTypeConverterCompilePostProcessor", new TypeConverterCompilePostProcessor());
+        context.getRegistry().bind("CamelBindToRegistryCompilePostProcessor", new BindToRegistryCompilePostProcessor());
+
+        // spring
+        context.getRegistry().bind("SpringAnnotationCompilePostProcessor", new SpringAnnotationCompilePostProcessor());
+        context.adapt(ExtendedCamelContext.class).getBeanPostProcessor()
+                .addCamelBeanPostProjectInjector(new SpringBeanPostProcessorInjector(context));
+
+        // quarkus
+        context.getRegistry().bind("QuarkusAnnotationCompilePostProcessor", new QuarkusAnnotationCompilePostProcessor());
+        context.adapt(ExtendedCamelContext.class).getBeanPostProcessor()
+                .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.getAnnotation(Converter.class) != null) {

Review comment:
       You could use `isAnnotationPresent` instead to make it easier to read

##########
File path: dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/AnnotationDependencyInjection.java
##########
@@ -0,0 +1,306 @@
+/*
+ * 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.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.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) {
+        // camel / common
+        context.getRegistry().bind("CamelTypeConverterCompilePostProcessor", new TypeConverterCompilePostProcessor());
+        context.getRegistry().bind("CamelBindToRegistryCompilePostProcessor", new BindToRegistryCompilePostProcessor());
+
+        // spring
+        context.getRegistry().bind("SpringAnnotationCompilePostProcessor", new SpringAnnotationCompilePostProcessor());
+        context.adapt(ExtendedCamelContext.class).getBeanPostProcessor()
+                .addCamelBeanPostProjectInjector(new SpringBeanPostProcessorInjector(context));

Review comment:
       Same for the BeanPostProcessor

##########
File path: dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/AnnotationDependencyInjection.java
##########
@@ -0,0 +1,306 @@
+/*
+ * 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.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.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) {
+        // camel / common
+        context.getRegistry().bind("CamelTypeConverterCompilePostProcessor", new TypeConverterCompilePostProcessor());
+        context.getRegistry().bind("CamelBindToRegistryCompilePostProcessor", new BindToRegistryCompilePostProcessor());
+
+        // spring
+        context.getRegistry().bind("SpringAnnotationCompilePostProcessor", new SpringAnnotationCompilePostProcessor());
+        context.adapt(ExtendedCamelContext.class).getBeanPostProcessor()
+                .addCamelBeanPostProjectInjector(new SpringBeanPostProcessorInjector(context));
+
+        // quarkus
+        context.getRegistry().bind("QuarkusAnnotationCompilePostProcessor", new QuarkusAnnotationCompilePostProcessor());
+        context.adapt(ExtendedCamelContext.class).getBeanPostProcessor()
+                .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.getAnnotation(Converter.class) != null) {
+                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);
+                }

Review comment:
       This code seems to be very close to what we have in `JavaRoutesBuilderLoader`, would it make sense to factorize the code to have it in one place?

##########
File path: dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/AnnotationDependencyInjection.java
##########
@@ -0,0 +1,306 @@
+/*
+ * 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.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.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) {
+        // camel / common
+        context.getRegistry().bind("CamelTypeConverterCompilePostProcessor", new TypeConverterCompilePostProcessor());
+        context.getRegistry().bind("CamelBindToRegistryCompilePostProcessor", new BindToRegistryCompilePostProcessor());
+
+        // spring
+        context.getRegistry().bind("SpringAnnotationCompilePostProcessor", new SpringAnnotationCompilePostProcessor());
+        context.adapt(ExtendedCamelContext.class).getBeanPostProcessor()
+                .addCamelBeanPostProjectInjector(new SpringBeanPostProcessorInjector(context));
+
+        // quarkus
+        context.getRegistry().bind("QuarkusAnnotationCompilePostProcessor", new QuarkusAnnotationCompilePostProcessor());
+        context.adapt(ExtendedCamelContext.class).getBeanPostProcessor()
+                .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.getAnnotation(Converter.class) != null) {
+                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 is a bean service which needs to be post processed and registered which 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();
+                }
+                // 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 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() != null && bi.name().length > 0) {

Review comment:
       `bi.name()` cannot be `null`. More generally the value of an element cannot be `null` according to the JLS.

##########
File path: dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/AnnotationDependencyInjection.java
##########
@@ -0,0 +1,306 @@
+/*
+ * 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.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.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) {
+        // camel / common
+        context.getRegistry().bind("CamelTypeConverterCompilePostProcessor", new TypeConverterCompilePostProcessor());
+        context.getRegistry().bind("CamelBindToRegistryCompilePostProcessor", new BindToRegistryCompilePostProcessor());
+
+        // spring
+        context.getRegistry().bind("SpringAnnotationCompilePostProcessor", new SpringAnnotationCompilePostProcessor());
+        context.adapt(ExtendedCamelContext.class).getBeanPostProcessor()
+                .addCamelBeanPostProjectInjector(new SpringBeanPostProcessorInjector(context));
+
+        // quarkus
+        context.getRegistry().bind("QuarkusAnnotationCompilePostProcessor", new QuarkusAnnotationCompilePostProcessor());
+        context.adapt(ExtendedCamelContext.class).getBeanPostProcessor()
+                .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.getAnnotation(Converter.class) != null) {
+                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 is a bean service which needs to be post processed and registered which 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);
+                }
+            }

Review comment:
       Same here, the code could be factorized?

##########
File path: dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/AnnotationDependencyInjection.java
##########
@@ -0,0 +1,306 @@
+/*
+ * 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.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.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) {
+        // camel / common
+        context.getRegistry().bind("CamelTypeConverterCompilePostProcessor", new TypeConverterCompilePostProcessor());
+        context.getRegistry().bind("CamelBindToRegistryCompilePostProcessor", new BindToRegistryCompilePostProcessor());
+
+        // spring
+        context.getRegistry().bind("SpringAnnotationCompilePostProcessor", new SpringAnnotationCompilePostProcessor());
+        context.adapt(ExtendedCamelContext.class).getBeanPostProcessor()
+                .addCamelBeanPostProjectInjector(new SpringBeanPostProcessorInjector(context));
+
+        // quarkus
+        context.getRegistry().bind("QuarkusAnnotationCompilePostProcessor", new QuarkusAnnotationCompilePostProcessor());
+        context.adapt(ExtendedCamelContext.class).getBeanPostProcessor()
+                .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.getAnnotation(Converter.class) != null) {
+                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 is a bean service which needs to be post processed and registered which 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();
+                }
+                // 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);

Review comment:
       You could keep the registry into one local variable




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [camel] davsclaus commented on a change in pull request #7200: Camel 17571

Posted by GitBox <gi...@apache.org>.
davsclaus commented on a change in pull request #7200:
URL: https://github.com/apache/camel/pull/7200#discussion_r826034560



##########
File path: 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 an 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 `@Single` 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.

Review comment:
       yes




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org