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();
}
}