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 36bcd627785 CAMEL-19693: camel-main - Base package scan should detect 
@BindToRegi… (#10968)
36bcd627785 is described below

commit 36bcd6277854b8e69ca91a8d51845a306b1c2136
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Wed Aug 2 17:56:09 2023 +0200

    CAMEL-19693: camel-main - Base package scan should detect @BindToRegi… 
(#10968)
    
    CAMEL-19693: camel-main - Base package scan should detect @BindToRegistry 
beans
---
 .../main/camel-main-configuration-metadata.json    |   2 +-
 .../org/apache/camel/ExtendedCamelContext.java     |  12 ++-
 .../camel-main-configuration-metadata.json         |   2 +-
 core/camel-main/src/main/docs/main.adoc            |   2 +-
 .../org/apache/camel/main/BaseMainSupport.java     |  13 ++-
 .../camel/main/MainConfigurationProperties.java    |  10 +-
 .../java/org/apache/camel/main/MainScan2Test.java  |  44 +++++++++
 .../org/apache/camel/main/scan2/MyProcessor.java   |  31 +++++++
 .../apache/camel/main/scan2/MyRouteBuilder.java    |  28 ++++++
 .../camel/support/scan/PackageScanHelper.java      | 103 +++++++++++++++++++++
 .../camel/dsl/xml/io/XmlRoutesBuilderLoader.java   |  64 +------------
 11 files changed, 235 insertions(+), 76 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
index 1ff621ee9d8..7e4a2e04b05 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
@@ -24,7 +24,7 @@
     { "name": "camel.main.backlogTracing", "description": "Sets whether 
backlog tracing is enabled or not. Default is false.", "sourceType": 
"org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.main.backlogTracingStandby", "description": "Whether to 
set backlog tracing on standby. If on standby then the backlog tracer is 
installed and made available. Then the backlog tracer can be enabled later at 
runtime via JMX or via Java API. Default is false.", "sourceType": 
"org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.main.backlogTracingTemplates", "description": "Whether 
backlog tracing should trace inner details from route templates (or kamelets). 
Turning this on increases the verbosity of tracing by including events from 
internal routes in the templates or kamelets. Default is false.", "sourceType": 
"org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false" },
-    { "name": "camel.main.basePackageScan", "description": "Package name to 
use as base (offset) for classpath scanning of RouteBuilder , and 
org.apache.camel.TypeConverter classes. If you are using Spring Boot then it is 
instead recommended to use Spring Boots component scanning and annotate your 
route builder classes with Component. In other words only use this for Camel 
Main in standalone mode.", "sourceType": 
"org.apache.camel.main.MainConfigurationProperties", "type": "string", "jav 
[...]
+    { "name": "camel.main.basePackageScan", "description": "Package name to 
use as base (offset) for classpath scanning of RouteBuilder , 
org.apache.camel.TypeConverter , CamelConfiguration classes, and also classes 
annotated with org.apache.camel.Converter , or org.apache.camel.BindToRegistry 
. If you are using Spring Boot then it is instead recommended to use Spring 
Boots component scanning and annotate your route builder classes with 
Component. In other words only use this for Camel M [...]
     { "name": "camel.main.basePackageScanEnabled", "description": "Whether 
base package scan is enabled.", "sourceType": 
"org.apache.camel.main.MainConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": true },
     { "name": "camel.main.beanIntrospectionExtendedStatistics", "description": 
"Sets whether bean introspection uses extended statistics. The default is 
false.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", 
"type": "boolean", "javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.main.beanIntrospectionLoggingLevel", "description": "Sets 
the logging level used by bean introspection, logging activity of its usage. 
The default is TRACE.", "sourceType": 
"org.apache.camel.main.DefaultConfigurationProperties", "type": "object", 
"javaType": "org.apache.camel.LoggingLevel", "enum": [ "ERROR", "WARN", "INFO", 
"DEBUG", "TRACE", "OFF" ] },
diff --git 
a/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java 
b/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java
index e5205dbe25a..e14101b4f23 100644
--- a/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java
+++ b/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java
@@ -445,16 +445,18 @@ public interface ExtendedCamelContext {
     String resolvePropertyPlaceholders(String text, boolean 
keepUnresolvedOptional);
 
     /**
-     * Package name to use as base (offset) for classpath scanning of custom 
{@link CamelConfiguration},
-     * {@link Configuration}, and {@link TypeConverter}.
+     * Package name to use as base (offset) for classpath scanning of 
RouteBuilder,
+     * {@link org.apache.camel.TypeConverter}, {@link CamelConfiguration} 
classes, and also classes annotated with
+     * {@link org.apache.camel.Converter}, or {@link 
org.apache.camel.BindToRegistry}.
      *
-     * @return the base package name (can bre null if not configured)
+     * @return the base package name (can be null if not configured)
      */
     String getBasePackageScan();
 
     /**
-     * Package name to use as base (offset) for classpath scanning of custom 
{@link CamelConfiguration},
-     * {@link Configuration}, and {@link TypeConverter}.
+     * Package name to use as base (offset) for classpath scanning of 
RouteBuilder,
+     * {@link org.apache.camel.TypeConverter}, {@link CamelConfiguration} 
classes, and also classes annotated with
+     * {@link org.apache.camel.Converter}, or {@link 
org.apache.camel.BindToRegistry}.
      *
      * @param basePackageScan the base package name
      */
diff --git 
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
 
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
index 1ff621ee9d8..7e4a2e04b05 100644
--- 
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
+++ 
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
@@ -24,7 +24,7 @@
     { "name": "camel.main.backlogTracing", "description": "Sets whether 
backlog tracing is enabled or not. Default is false.", "sourceType": 
"org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.main.backlogTracingStandby", "description": "Whether to 
set backlog tracing on standby. If on standby then the backlog tracer is 
installed and made available. Then the backlog tracer can be enabled later at 
runtime via JMX or via Java API. Default is false.", "sourceType": 
"org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.main.backlogTracingTemplates", "description": "Whether 
backlog tracing should trace inner details from route templates (or kamelets). 
Turning this on increases the verbosity of tracing by including events from 
internal routes in the templates or kamelets. Default is false.", "sourceType": 
"org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false" },
-    { "name": "camel.main.basePackageScan", "description": "Package name to 
use as base (offset) for classpath scanning of RouteBuilder , and 
org.apache.camel.TypeConverter classes. If you are using Spring Boot then it is 
instead recommended to use Spring Boots component scanning and annotate your 
route builder classes with Component. In other words only use this for Camel 
Main in standalone mode.", "sourceType": 
"org.apache.camel.main.MainConfigurationProperties", "type": "string", "jav 
[...]
+    { "name": "camel.main.basePackageScan", "description": "Package name to 
use as base (offset) for classpath scanning of RouteBuilder , 
org.apache.camel.TypeConverter , CamelConfiguration classes, and also classes 
annotated with org.apache.camel.Converter , or org.apache.camel.BindToRegistry 
. If you are using Spring Boot then it is instead recommended to use Spring 
Boots component scanning and annotate your route builder classes with 
Component. In other words only use this for Camel M [...]
     { "name": "camel.main.basePackageScanEnabled", "description": "Whether 
base package scan is enabled.", "sourceType": 
"org.apache.camel.main.MainConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": true },
     { "name": "camel.main.beanIntrospectionExtendedStatistics", "description": 
"Sets whether bean introspection uses extended statistics. The default is 
false.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", 
"type": "boolean", "javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.main.beanIntrospectionLoggingLevel", "description": "Sets 
the logging level used by bean introspection, logging activity of its usage. 
The default is TRACE.", "sourceType": 
"org.apache.camel.main.DefaultConfigurationProperties", "type": "object", 
"javaType": "org.apache.camel.LoggingLevel", "enum": [ "ERROR", "WARN", "INFO", 
"DEBUG", "TRACE", "OFF" ] },
diff --git a/core/camel-main/src/main/docs/main.adoc 
b/core/camel-main/src/main/docs/main.adoc
index 02157749c5f..fff84225c33 100644
--- a/core/camel-main/src/main/docs/main.adoc
+++ b/core/camel-main/src/main/docs/main.adoc
@@ -35,7 +35,7 @@ The camel.main supports 120 options, which are listed below.
 | *camel.main.backlogTracing* | Sets whether backlog tracing is enabled or 
not. Default is false. | false | boolean
 | *camel.main.backlogTracing{zwsp}Standby* | Whether to set backlog tracing on 
standby. If on standby then the backlog tracer is installed and made available. 
Then the backlog tracer can be enabled later at runtime via JMX or via Java 
API. Default is false. | false | boolean
 | *camel.main.backlogTracing{zwsp}Templates* | Whether backlog tracing should 
trace inner details from route templates (or kamelets). Turning this on 
increases the verbosity of tracing by including events from internal routes in 
the templates or kamelets. Default is false. | false | boolean
-| *camel.main.basePackageScan* | Package name to use as base (offset) for 
classpath scanning of RouteBuilder , and org.apache.camel.TypeConverter 
classes. If you are using Spring Boot then it is instead recommended to use 
Spring Boots component scanning and annotate your route builder classes with 
Component. In other words only use this for Camel Main in standalone mode. |  | 
String
+| *camel.main.basePackageScan* | Package name to use as base (offset) for 
classpath scanning of RouteBuilder , org.apache.camel.TypeConverter , 
CamelConfiguration classes, and also classes annotated with 
org.apache.camel.Converter , or org.apache.camel.BindToRegistry . If you are 
using Spring Boot then it is instead recommended to use Spring Boots component 
scanning and annotate your route builder classes with Component. In other words 
only use this for Camel Main in standalone mode. |   [...]
 | *camel.main.basePackageScan{zwsp}Enabled* | Whether base package scan is 
enabled. | true | boolean
 | *camel.main.beanIntrospection{zwsp}ExtendedStatistics* | Sets whether bean 
introspection uses extended statistics. The default is false. | false | boolean
 | *camel.main.beanIntrospection{zwsp}LoggingLevel* | Sets the logging level 
used by bean introspection, logging activity of its usage. The default is 
TRACE. |  | LoggingLevel
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java 
b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
index 9fe3bb74c92..ee60e0c621c 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
@@ -71,6 +71,7 @@ import org.apache.camel.support.PluginHelper;
 import org.apache.camel.support.PropertyBindingSupport;
 import org.apache.camel.support.ResourceHelper;
 import org.apache.camel.support.SimpleEventNotifierSupport;
+import org.apache.camel.support.scan.PackageScanHelper;
 import org.apache.camel.support.service.BaseService;
 import org.apache.camel.support.startup.LoggingStartupStepRecorder;
 import org.apache.camel.util.FileUtil;
@@ -263,6 +264,14 @@ public abstract class BaseMainSupport extends BaseService {
         listeners.remove(listener);
     }
 
+    protected void loadCustomBeans(CamelContext camelContext) throws Exception 
{
+        // auto-detect custom beans via base package scanning
+        String basePackage = 
camelContext.getCamelContextExtension().getBasePackageScan();
+        if (basePackage != null) {
+            PackageScanHelper.registerBeans(getCamelContext(), 
Set.of(basePackage));
+        }
+    }
+
     protected void loadConfigurations(CamelContext camelContext) throws 
Exception {
         // auto-detect camel configurations via base package scanning
         String basePackage = 
camelContext.getCamelContextExtension().getBasePackageScan();
@@ -429,9 +438,9 @@ public abstract class BaseMainSupport extends BaseService {
         // configure from main configuration properties
         doConfigureCamelContextFromMainConfiguration(camelContext, 
mainConfigurationProperties, autoConfiguredProperties);
 
+        // try to load custom beans/configuration classes via package scanning
         configurePackageScan(camelContext);
-
-        // try to load configuration classes
+        loadCustomBeans(camelContext);
         loadConfigurations(camelContext);
 
         if (mainConfigurationProperties.isAutoConfigurationEnabled()) {
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java
 
b/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java
index 77e58d187b4..99236072390 100644
--- 
a/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java
+++ 
b/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java
@@ -333,8 +333,9 @@ public class MainConfigurationProperties extends 
DefaultConfigurationProperties<
     }
 
     /**
-     * Package name to use as base (offset) for classpath scanning of {@link 
RouteBuilder}, and
-     * {@link org.apache.camel.TypeConverter} classes.
+     * Package name to use as base (offset) for classpath scanning of {@link 
RouteBuilder},
+     * {@link org.apache.camel.TypeConverter}, {@link CamelConfiguration} 
classes, and also classes annotated with
+     * {@link org.apache.camel.Converter}, or {@link 
org.apache.camel.BindToRegistry}.
      *
      * If you are using Spring Boot then it is instead recommended to use 
Spring Boots component scanning and annotate
      * your route builder classes with `@Component`. In other words only use 
this for Camel Main in standalone mode.
@@ -588,8 +589,9 @@ public class MainConfigurationProperties extends 
DefaultConfigurationProperties<
     }
 
     /**
-     * Package name to use as base (offset) for classpath scanning of {@link 
RouteBuilder}, and
-     * {@link org.apache.camel.TypeConverter} classes.
+     * Package name to use as base (offset) for classpath scanning of {@link 
RouteBuilder},
+     * {@link org.apache.camel.TypeConverter}, {@link CamelConfiguration} 
classes, and also classes annotated with
+     * {@link org.apache.camel.Converter}, or {@link 
org.apache.camel.BindToRegistry}.
      *
      * If you are using Spring Boot then it is instead recommended to use 
Spring Boots component scanning and annotate
      * your route builder classes with `@Component`. In other words only use 
this for Camel Main in standalone mode.
diff --git 
a/core/camel-main/src/test/java/org/apache/camel/main/MainScan2Test.java 
b/core/camel-main/src/test/java/org/apache/camel/main/MainScan2Test.java
new file mode 100644
index 00000000000..7c5f42dd51d
--- /dev/null
+++ b/core/camel-main/src/test/java/org/apache/camel/main/MainScan2Test.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.main;
+
+import org.apache.camel.CamelContext;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class MainScan2Test {
+
+    @Test
+    public void testScan2() throws Exception {
+        Main main = new Main();
+        main.configure().withBasePackageScan("org.apache.camel.main.scan2");
+        main.start();
+
+        CamelContext camelContext = main.getCamelContext();
+        assertNotNull(camelContext);
+        assertEquals(1, camelContext.getRoutes().size());
+
+        String out = 
camelContext.createProducerTemplate().requestBody("direct:start", "Camel", 
String.class);
+        Assertions.assertEquals("Hello Camel", out);
+
+        main.stop();
+    }
+
+}
diff --git 
a/core/camel-main/src/test/java/org/apache/camel/main/scan2/MyProcessor.java 
b/core/camel-main/src/test/java/org/apache/camel/main/scan2/MyProcessor.java
new file mode 100644
index 00000000000..76189f5b0a7
--- /dev/null
+++ b/core/camel-main/src/test/java/org/apache/camel/main/scan2/MyProcessor.java
@@ -0,0 +1,31 @@
+/*
+ * 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.scan2;
+
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+
+@BindToRegistry("hello")
+public class MyProcessor implements Processor {
+
+    @Override
+    public void process(Exchange exchange) throws Exception {
+        exchange.getMessage().setBody("Hello " + 
exchange.getMessage().getBody());
+    }
+
+}
diff --git 
a/core/camel-main/src/test/java/org/apache/camel/main/scan2/MyRouteBuilder.java 
b/core/camel-main/src/test/java/org/apache/camel/main/scan2/MyRouteBuilder.java
new file mode 100644
index 00000000000..8442b3a0d46
--- /dev/null
+++ 
b/core/camel-main/src/test/java/org/apache/camel/main/scan2/MyRouteBuilder.java
@@ -0,0 +1,28 @@
+/*
+ * 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.scan2;
+
+import org.apache.camel.builder.RouteBuilder;
+
+public class MyRouteBuilder extends RouteBuilder {
+
+    @Override
+    public void configure() throws Exception {
+        from("direct:start")
+                .process("hello");
+    }
+}
diff --git 
a/core/camel-support/src/main/java/org/apache/camel/support/scan/PackageScanHelper.java
 
b/core/camel-support/src/main/java/org/apache/camel/support/scan/PackageScanHelper.java
new file mode 100644
index 00000000000..adc59296341
--- /dev/null
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/scan/PackageScanHelper.java
@@ -0,0 +1,103 @@
+/*
+ * 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.support.scan;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.CamelContext;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.spi.Injector;
+import org.apache.camel.spi.PackageScanClassResolver;
+import org.apache.camel.spi.Registry;
+import org.apache.camel.support.PluginHelper;
+
+import static org.apache.camel.util.ObjectHelper.isEmpty;
+
+/**
+ * Helper for Camel package scanning.
+ */
+public class PackageScanHelper {
+
+    private PackageScanHelper() {
+    }
+
+    /**
+     * Scans the given Java packages for custom beans annotated with {@link 
BindToRegistry} and create new instances of
+     * these class and performs Camel dependency injection via {@link 
org.apache.camel.spi.CamelBeanPostProcessor}.
+     *
+     * @param camelContext the camel context
+     * @param packages     the Java packages to scan
+     */
+    public static void registerBeans(CamelContext camelContext, Set<String> 
packages) {
+        if (packages != null && !packages.isEmpty()) {
+            Registry registry = camelContext.getRegistry();
+            if (registry != null) {
+                PackageScanClassResolver scanner
+                        = 
camelContext.getCamelContextExtension().getContextPlugin(PackageScanClassResolver.class);
+                Injector injector = camelContext.getInjector();
+                if (scanner != null && injector != null) {
+                    Map<Class<?>, Object> created = new HashMap<>();
+                    for (String pkg : packages) {
+                        Set<Class<?>> classes = 
scanner.findAnnotated(BindToRegistry.class, pkg);
+                        for (Class<?> c : classes) {
+                            // phase-1: create empty bean instance without any 
bean post-processing
+                            Object b = injector.newInstance(c, false);
+                            if (b != null) {
+                                created.put(c, b);
+                            }
+                        }
+                        for (Class<?> c : created.keySet()) {
+                            // phase-2: discover any created beans has 
@BindToRegistry to register them eager
+                            BindToRegistry ann = 
c.getAnnotation(BindToRegistry.class);
+                            if (ann != null) {
+                                String name = ann.value();
+                                if (isEmpty(name)) {
+                                    name = c.getSimpleName();
+                                }
+                                Object bean = created.get(c);
+                                String beanName = c.getName();
+                                // - bind to registry if 
@org.apache.camel.BindToRegistry is present
+                                // use dependency injection factory to perform 
the task of binding the bean to registry
+                                Runnable task = 
PluginHelper.getDependencyInjectionAnnotationFactory(camelContext)
+                                        .createBindToRegistryFactory(name, 
bean, beanName, false);
+                                task.run();
+                            }
+                        }
+                        for (Class<?> c : created.keySet()) {
+                            // phase-3: now we can do bean post-processing on 
the created beans
+                            Object bean = created.get(c);
+                            String beanName = c.getName();
+                            try {
+                                // - call 
org.apache.camel.spi.CamelBeanPostProcessor.postProcessBeforeInitialization
+                                // - call 
org.apache.camel.spi.CamelBeanPostProcessor.postProcessAfterInitialization
+                                
PluginHelper.getBeanPostProcessor(camelContext).postProcessBeforeInitialization(bean,
+                                        beanName);
+                                
PluginHelper.getBeanPostProcessor(camelContext).postProcessAfterInitialization(bean,
+                                        beanName);
+                            } catch (Exception e) {
+                                throw new RuntimeCamelException("Error 
post-processing bean: " + beanName, e);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git 
a/dsl/camel-xml-io-dsl/src/main/java/org/apache/camel/dsl/xml/io/XmlRoutesBuilderLoader.java
 
b/dsl/camel-xml-io-dsl/src/main/java/org/apache/camel/dsl/xml/io/XmlRoutesBuilderLoader.java
index f1b32b1d1d3..4a40f99ec03 100644
--- 
a/dsl/camel-xml-io-dsl/src/main/java/org/apache/camel/dsl/xml/io/XmlRoutesBuilderLoader.java
+++ 
b/dsl/camel-xml-io-dsl/src/main/java/org/apache/camel/dsl/xml/io/XmlRoutesBuilderLoader.java
@@ -18,7 +18,6 @@ package org.apache.camel.dsl.xml.io;
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
@@ -28,9 +27,7 @@ import java.util.concurrent.atomic.AtomicInteger;
 
 import org.w3c.dom.Document;
 
-import org.apache.camel.BindToRegistry;
 import org.apache.camel.CamelContextAware;
-import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.api.management.ManagedResource;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.builder.RouteConfigurationBuilder;
@@ -47,22 +44,17 @@ import org.apache.camel.model.app.BeansDefinition;
 import org.apache.camel.model.app.RegistryBeanDefinition;
 import org.apache.camel.model.rest.RestDefinition;
 import org.apache.camel.model.rest.RestsDefinition;
-import org.apache.camel.spi.Injector;
-import org.apache.camel.spi.PackageScanClassResolver;
-import org.apache.camel.spi.Registry;
 import org.apache.camel.spi.Resource;
 import org.apache.camel.spi.annotations.RoutesLoader;
 import org.apache.camel.support.CachedResource;
-import org.apache.camel.support.PluginHelper;
 import org.apache.camel.support.PropertyBindingSupport;
+import org.apache.camel.support.scan.PackageScanHelper;
 import org.apache.camel.xml.in.ModelParser;
 import org.apache.camel.xml.io.util.XmlStreamDetector;
 import org.apache.camel.xml.io.util.XmlStreamInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static org.apache.camel.util.ObjectHelper.isEmpty;
-
 @ManagedResource(description = "Managed XML RoutesBuilderLoader")
 @RoutesLoader(XmlRoutesBuilderLoader.EXTENSION)
 public class XmlRoutesBuilderLoader extends RouteBuilderLoaderSupport {
@@ -279,59 +271,7 @@ public class XmlRoutesBuilderLoader extends 
RouteBuilderLoaderSupport {
         app.getComponentScanning().forEach(cs -> {
             packagesToScan.add(cs.getBasePackage());
         });
-        if (!packagesToScan.isEmpty()) {
-            Registry registry = getCamelContext().getRegistry();
-            if (registry != null) {
-                PackageScanClassResolver scanner
-                        = 
getCamelContext().getCamelContextExtension().getContextPlugin(PackageScanClassResolver.class);
-                Injector injector = getCamelContext().getInjector();
-                if (scanner != null && injector != null) {
-                    Map<Class<?>, Object> created = new HashMap<>();
-                    for (String pkg : packagesToScan) {
-                        Set<Class<?>> classes = 
scanner.findAnnotated(BindToRegistry.class, pkg);
-                        for (Class<?> c : classes) {
-                            // phase-1: create empty bean instance without any 
bean post-processing
-                            Object b = injector.newInstance(c, false);
-                            if (b != null) {
-                                created.put(c, b);
-                            }
-                        }
-                        for (Class<?> c : created.keySet()) {
-                            // phase-2: discover any created beans has 
@BindToRegistry to register them eager
-                            BindToRegistry ann = 
c.getAnnotation(BindToRegistry.class);
-                            if (ann != null) {
-                                String name = ann.value();
-                                if (isEmpty(name)) {
-                                    name = c.getSimpleName();
-                                }
-                                Object bean = created.get(c);
-                                String beanName = c.getName();
-                                // - bind to registry if 
@org.apache.camel.BindToRegistry is present
-                                // use dependency injection factory to perform 
the task of binding the bean to registry
-                                Runnable task = 
PluginHelper.getDependencyInjectionAnnotationFactory(getCamelContext())
-                                        .createBindToRegistryFactory(name, 
bean, beanName, false);
-                                task.run();
-                            }
-                        }
-                        for (Class<?> c : created.keySet()) {
-                            // phase-3: now we can do bean post-processing on 
the created beans
-                            Object bean = created.get(c);
-                            String beanName = c.getName();
-                            try {
-                                // - call 
org.apache.camel.spi.CamelBeanPostProcessor.postProcessBeforeInitialization
-                                // - call 
org.apache.camel.spi.CamelBeanPostProcessor.postProcessAfterInitialization
-                                
PluginHelper.getBeanPostProcessor(getCamelContext()).postProcessBeforeInitialization(bean,
-                                        beanName);
-                                
PluginHelper.getBeanPostProcessor(getCamelContext()).postProcessAfterInitialization(bean,
-                                        beanName);
-                            } catch (Exception e) {
-                                throw new RuntimeCamelException("Error 
post-processing bean: " + beanName, e);
-                            }
-                        }
-                    }
-                }
-            }
-        }
+        PackageScanHelper.registerBeans(getCamelContext(), packagesToScan);
 
         // <bean>s - register Camel beans directly with Camel injection
         for (RegistryBeanDefinition bean : app.getBeans()) {

Reply via email to