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

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


The following commit(s) were added to refs/heads/main by this push:
     new d1297d4f3bc fix: handle unnamed beans (#9432)
d1297d4f3bc is described below

commit d1297d4f3bc24c5c51a7d4bd0c2ef02e9d99fd02
Author: GaĆ«lle Fournier <[email protected]>
AuthorDate: Wed Nov 4 17:06:10 2026 +0100

    fix: handle unnamed beans (#9432)
---
 docs/modules/ROOT/pages/migration-guide/4.0.0.adoc |  10 ++
 .../CamelBeanLookupWithIdentifierTest.java         |  16 +++
 .../core/deployment/CamelUnnamedBeanTest.java      | 109 +++++++++++++++++++++
 .../camel/quarkus/core/RuntimeBeanRepository.java  |  19 ++--
 4 files changed, 143 insertions(+), 11 deletions(-)

diff --git a/docs/modules/ROOT/pages/migration-guide/4.0.0.adoc 
b/docs/modules/ROOT/pages/migration-guide/4.0.0.adoc
index c8fbf8520ca..11e75ecb077 100644
--- a/docs/modules/ROOT/pages/migration-guide/4.0.0.adoc
+++ b/docs/modules/ROOT/pages/migration-guide/4.0.0.adoc
@@ -138,6 +138,16 @@ quarkus.camel.routes-discovery.exclude-patterns = **
 camel.main.javaRoutesExcludePattern = **
 ----
 
+== Unnamed CDI beans are again visible to Camel by type
+
+Camel looks up several of its SPI types from the registry with 
`Registry#findByTypeWithName`. For example, `DefaultConfigurationConfigurer` 
installs a single bean of types such as `UnitOfWorkFactory`, `UuidGenerator` 
and `ShutdownStrategy` on the `CamelContext`, and the same lookup is used for 
`BacklogTracer` and `BacklogDebugger`. Since Camel Quarkus 3.26.0, that method 
omitted CDI beans that declare neither `@Named` nor `@Identifier`, so a bean of 
such a type was silently ignored.
+
+Those beans are returned again, keyed by their CDI bean identifier, as before 
Camel Quarkus 3.26.0. An SPI bean no longer needs `@Named` or `@Identifier` to 
be installed on the `CamelContext`.
+
+The key of an unnamed bean is an opaque CDI identifier, not a bean name, so 
`Registry#lookupByNameAndType` does not resolve a bean by it. Beans that are 
looked up by name still need `@Named` or `@Identifier`.
+
+If an application declares both a named and an unnamed bean of the same SPI 
type, `Registry#findByTypeWithName` now returns two entries and Camel installs 
neither. In Camel Quarkus 3.40.x, only the named bean was installed. Declare a 
single bean of such a type, and keep the bean that should apply.
+
 == Core extension build item changes
 
 These changes affect only custom Quarkus extensions that consume build items 
from `camel-quarkus-core-deployment`. Applications are unaffected.
diff --git 
a/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/deployment/CamelBeanLookupWithIdentifierTest.java
 
b/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/deployment/CamelBeanLookupWithIdentifierTest.java
index 9b11562485f..2e2bdcf68c3 100644
--- 
a/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/deployment/CamelBeanLookupWithIdentifierTest.java
+++ 
b/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/deployment/CamelBeanLookupWithIdentifierTest.java
@@ -84,12 +84,25 @@ public class CamelBeanLookupWithIdentifierTest {
         assertNotNull(typeWithName.get("my-identifier"));
     }
 
+    @Test
+    void resolveUnnamedBeanWithType() {
+        Map<String, MyUnnamedBean> typeWithName = 
context.getRegistry().findByTypeWithName(MyUnnamedBean.class);
+        assertNotNull(typeWithName);
+        assertEquals(1, typeWithName.size());
+        assertNotNull(typeWithName.values().iterator().next());
+    }
+
     @Produces
     @Identifier("my-identifier")
     public MyIdentifiedBean createIdentifiedBean() {
         return new MyIdentifiedBean();
     }
 
+    @Produces
+    public MyUnnamedBean createUnnamedBean() {
+        return new MyUnnamedBean();
+    }
+
     public static class Routes extends RouteBuilder {
         @Override
         public void configure() throws Exception {
@@ -102,4 +115,7 @@ public class CamelBeanLookupWithIdentifierTest {
             return "Hello World";
         }
     }
+
+    public static class MyUnnamedBean {
+    }
 }
diff --git 
a/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/deployment/CamelUnnamedBeanTest.java
 
b/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/deployment/CamelUnnamedBeanTest.java
new file mode 100644
index 00000000000..dd18fbd9982
--- /dev/null
+++ 
b/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/deployment/CamelUnnamedBeanTest.java
@@ -0,0 +1,109 @@
+/*
+ * 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.quarkus.core.deployment;
+
+import java.util.Map;
+import java.util.UUID;
+
+import io.quarkus.test.QuarkusExtensionTest;
+import jakarta.enterprise.inject.Produces;
+import jakarta.inject.Inject;
+import jakarta.inject.Named;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.impl.engine.DefaultUnitOfWork;
+import org.apache.camel.spi.UnitOfWork;
+import org.apache.camel.spi.UnitOfWorkFactory;
+import org.apache.camel.spi.UuidGenerator;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CamelUnnamedBeanTest {
+
+    @RegisterExtension
+    static final QuarkusExtensionTest CONFIG = new QuarkusExtensionTest()
+            .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class));
+
+    @Inject
+    CamelContext context;
+
+    @Test
+    void unnamedBeanIsExposedByType() {
+        Map<String, MyUnnamedBean> beans = 
context.getRegistry().findByTypeWithName(MyUnnamedBean.class);
+        assertThat(beans).hasSize(1);
+        // Unnamed beans are keyed by their bean identifier
+        assertThat(beans.keySet()).doesNotContainNull();
+        assertThat(beans.values()).allMatch(MyUnnamedBean.class::isInstance);
+    }
+
+    @Test
+    void unnamedSpiBeanIsInstalledOnCamelContext() {
+        // Camel installs SPI beans resolved through 
Registry#findByTypeWithName (DefaultConfigurationConfigurer)
+        
assertThat(context.getCamelContextExtension().getContextPlugin(UnitOfWorkFactory.class))
+                .isInstanceOf(MyUnitOfWorkFactory.class);
+    }
+
+    @Test
+    void namedAndUnnamedBeansOfSameTypeAreBothVisible() {
+        Map<String, UuidGenerator> beans = 
context.getRegistry().findByTypeWithName(UuidGenerator.class);
+        assertThat(beans).hasSize(2);
+        assertThat(beans).containsKey("my-uuid-generator");
+        assertThat(beans.values()).allMatch(MyUuidGenerator.class::isInstance);
+    }
+
+    @Produces
+    public MyUnnamedBean createUnnamedBean() {
+        return new MyUnnamedBean();
+    }
+
+    @Produces
+    public UnitOfWorkFactory createUnitOfWorkFactory() {
+        return new MyUnitOfWorkFactory();
+    }
+
+    @Produces
+    @Named("my-uuid-generator")
+    public UuidGenerator createNamedUuidGenerator() {
+        return new MyUuidGenerator();
+    }
+
+    @Produces
+    public UuidGenerator createUnnamedUuidGenerator() {
+        return new MyUuidGenerator();
+    }
+
+    public static class MyUnnamedBean {
+    }
+
+    public static class MyUnitOfWorkFactory implements UnitOfWorkFactory {
+        @Override
+        public UnitOfWork createUnitOfWork(Exchange exchange) {
+            return new DefaultUnitOfWork(exchange);
+        }
+    }
+
+    public static class MyUuidGenerator implements UuidGenerator {
+        @Override
+        public String generateUuid() {
+            return UUID.randomUUID().toString();
+        }
+    }
+}
diff --git 
a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/RuntimeBeanRepository.java
 
b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/RuntimeBeanRepository.java
index 06531cfcc1d..343f38748b1 100644
--- 
a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/RuntimeBeanRepository.java
+++ 
b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/RuntimeBeanRepository.java
@@ -124,16 +124,11 @@ public final class RuntimeBeanRepository implements 
BeanRepository {
 
     private static <T> Map<String, T> getReferencesByTypeWithName(Class<T> 
type, Annotation... qualifiers) {
         Map<String, T> beans = new HashMap<>();
-        Arc.container()
-                .listAll(type, qualifiers)
-                .stream()
-                .filter(InstanceHandle::isAvailable)
-                .forEach(instanceHandle -> {
-                    String name = resolveBeanName(instanceHandle.getBean());
-                    if (ObjectHelper.isNotEmpty(name)) {
-                        beans.put(name, instanceHandle.get());
-                    }
-                });
+        for (InstanceHandle<T> instanceHandle : Arc.container().listAll(type, 
qualifiers)) {
+            if (instanceHandle.isAvailable()) {
+                beans.put(resolveBeanName(instanceHandle.getBean()), 
instanceHandle.get());
+            }
+        }
         return beans;
     }
 
@@ -218,6 +213,8 @@ public final class RuntimeBeanRepository implements 
BeanRepository {
                 }
             }
         }
-        return name;
+        // Unnamed beans are exposed via Registry#findByTypeWithName; the 
identifier
+        // is a map key only, so lookupByNameAndType cannot resolve it.
+        return ObjectHelper.isNotEmpty(name) ? name : bean.getIdentifier();
     }
 }

Reply via email to