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

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


The following commit(s) were added to refs/heads/3.20.x by this push:
     new c9674a96c6 Improve handling of findSingleByType where multiple beans 
exist without any @Default qualifier
c9674a96c6 is described below

commit c9674a96c6d0284c0338b05fae60ae9fba9fecb0
Author: Zheng Feng <zh.f...@gmail.com>
AuthorDate: Tue May 20 14:05:29 2025 +0800

    Improve handling of findSingleByType where multiple beans exist without any 
@Default qualifier
    
    Fixes #7315
    
    Co-authored-by: James Netherton <jamesnether...@gmail.com>
---
 .../core/runtime/CamelBeanPrecedenceTest.java      | 172 +++++++++++++++++++++
 .../quarkus/core/runtime/CamelPrecedeBeanTest.java |  70 ---------
 .../camel/quarkus/core/RuntimeBeanRepository.java  |  75 +++++----
 .../component/jpa/deployment/JpaProcessor.java     |  52 +++++++
 .../quarkus/component/jpa/it/JpaResource.java      |  35 +++++
 .../camel/quarkus/component/jpa/it/JpaRoute.java   |   2 +
 .../jpa/src/main/resources/application.properties  |  33 +++-
 ...DefaultAndExplicitEntityManagerFactoryTest.java |  52 +++++++
 ...JpaMultipleNamedResourcesWithNoDefaultTest.java |  46 ++++++
 .../JpaSingleNamedResourceWithNoDefaultTest.java   |  45 ++++++
 .../quarkus/component/sql/it/SqlDbInitializer.java |   2 +
 .../quarkus/component/sql/it/SqlResource.java      |   2 +
 .../camel/quarkus/component/sql/it/SqlRoutes.java  |   2 +
 .../sql/it/datasource/SqlDataSourceResource.java   |  64 ++++++++
 .../sql/src/main/resources/application.properties  |  19 ++-
 .../SqlMultipleNamedDatasourceWithDefaultTest.java |  58 +++++++
 ...qlMultipleNamedDatasourceWithNoDefaultTest.java |  58 +++++++
 17 files changed, 682 insertions(+), 105 deletions(-)

diff --git 
a/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/runtime/CamelBeanPrecedenceTest.java
 
b/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/runtime/CamelBeanPrecedenceTest.java
new file mode 100644
index 0000000000..31352e76e9
--- /dev/null
+++ 
b/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/runtime/CamelBeanPrecedenceTest.java
@@ -0,0 +1,172 @@
+/*
+ * 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.runtime;
+
+import io.quarkus.arc.DefaultBean;
+import io.quarkus.test.QuarkusUnitTest;
+import io.smallrye.common.annotation.Identifier;
+import jakarta.annotation.Priority;
+import jakarta.enterprise.inject.Produces;
+import jakarta.inject.Inject;
+import org.apache.camel.CamelContext;
+import org.apache.camel.support.CamelContextHelper;
+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.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+public class CamelBeanPrecedenceTest {
+    @RegisterExtension
+    static final QuarkusUnitTest CONFIG = new QuarkusUnitTest()
+            .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class));
+
+    @Inject
+    CamelContext context;
+
+    @Test
+    public void findSingleByTypeForDefaultBeansWithPriority() {
+        BeanA bean = CamelContextHelper.findSingleByType(context, BeanA.class);
+        assertEquals("bar", bean.name());
+    }
+
+    @Test
+    public void findSingleByTypeForDefaultBeansWithSamePriority() {
+        BeanB bean = CamelContextHelper.findSingleByType(context, BeanB.class);
+        assertNull(bean);
+    }
+
+    @Test
+    public void findSingleByTypeForDefaultBeansWithoutPriority() {
+        BeanC bean = CamelContextHelper.findSingleByType(context, BeanC.class);
+        assertNull(bean);
+    }
+
+    @Test
+    public void findSingleByTypeForDefaultBean() {
+        BeanD bean = CamelContextHelper.findSingleByType(context, BeanD.class);
+        assertEquals("foo", bean.name());
+    }
+
+    @Test
+    public void findSingleByTypeWhereIdentifierQualifierAppliedToBean() {
+        BeanE bean = CamelContextHelper.findSingleByType(context, BeanE.class);
+        assertEquals("foo", bean.name());
+    }
+
+    @Test
+    public void findSingleByTypeWhereSingleBeanExists() {
+        BeanF bean = CamelContextHelper.findSingleByType(context, BeanF.class);
+        assertEquals("foo", bean.name());
+    }
+
+    @Test
+    public void findSingleByTypeWhereNoBeanProduced() {
+        BeanG bean = CamelContextHelper.findSingleByType(context, BeanG.class);
+        assertNull(bean);
+    }
+
+    // Default beans with priority
+    @Produces
+    @Priority(100)
+    BeanA createFooBeanA() {
+        return new BeanA("foo");
+    }
+
+    @Produces
+    @Priority(200)
+    BeanA createBarBeanA() {
+        return new BeanA("bar");
+    }
+
+    // Default beans with same priority
+    @Produces
+    @Priority(100)
+    BeanB createFooBeanB() {
+        return new BeanB("foo");
+    }
+
+    @Produces
+    @Priority(100)
+    BeanB createBarBeanB() {
+        return new BeanB("bar");
+    }
+
+    // Multiple default beans without priority
+    @Produces
+    BeanC createFooBeanC() {
+        return new BeanC("foo");
+    }
+
+    @Produces
+    BeanC createBarBeanC() {
+        return new BeanC("bar");
+    }
+
+    // Multiple beans with DefaultBean override
+    @Produces
+    BeanD createFooBeanD() {
+        return new BeanD("foo");
+    }
+
+    @Produces
+    @DefaultBean
+    BeanD createBarBeanD() {
+        return new BeanD("bar");
+    }
+
+    // Multiple beans with @Identifier qualifier
+    @Produces
+    BeanE createFooBeanE() {
+        return new BeanE("foo");
+    }
+
+    @Produces
+    @Identifier("bar")
+    BeanE createBarBeanE() {
+        return new BeanE("bar");
+    }
+
+    // Single bean
+    @Produces
+    BeanF createFooBeanF() {
+        return new BeanF("foo");
+    }
+
+    public record BeanA(String name) {
+    }
+
+    public record BeanB(String name) {
+    }
+
+    public record BeanC(String name) {
+    }
+
+    public record BeanD(String name) {
+    }
+
+    public record BeanE(String name) {
+    }
+
+    public record BeanF(String name) {
+    }
+
+    public record BeanG(String name) {
+    }
+}
diff --git 
a/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/runtime/CamelPrecedeBeanTest.java
 
b/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/runtime/CamelPrecedeBeanTest.java
deleted file mode 100644
index 71620aa058..0000000000
--- 
a/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/runtime/CamelPrecedeBeanTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.quarkus.core.runtime;
-
-import io.quarkus.test.QuarkusUnitTest;
-import jakarta.annotation.Priority;
-import jakarta.enterprise.inject.Produces;
-import jakarta.inject.Inject;
-import org.apache.camel.CamelContext;
-import org.apache.camel.support.CamelContextHelper;
-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.junit.jupiter.api.Assertions.assertEquals;
-
-public class CamelPrecedeBeanTest {
-    @RegisterExtension
-    static final QuarkusUnitTest CONFIG = new QuarkusUnitTest()
-            .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
-                    .addClasses(MyTestBean.class));
-
-    @Inject
-    CamelContext context;
-
-    @Test
-    public void testBeanPrecedence() {
-        MyTestBean bean = CamelContextHelper.findSingleByType(context, 
MyTestBean.class);
-        assertEquals("bar", bean.getName());
-    }
-
-    @Produces
-    @Priority(100)
-    MyTestBean createFoo() {
-        return new MyTestBean("foo");
-    }
-
-    @Produces
-    @Priority(200)
-    MyTestBean createBar() {
-        return new MyTestBean("bar");
-    }
-
-    public static final class MyTestBean {
-        private final String name;
-
-        public MyTestBean(String name) {
-            this.name = name;
-        }
-
-        public String getName() {
-            return name;
-        }
-    }
-}
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 6382cd7b0c..6eb36869b0 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
@@ -171,39 +171,58 @@ public final class RuntimeBeanRepository implements 
BeanRepository {
     public <T> T findSingleByType(Class<T> type) {
         ArcContainer container = Arc.container();
         Optional<Annotation[]> qualifiers = resolveQualifiersForType(type);
-        if (container != null) {
-            List<InstanceHandle<T>> handles;
-            if (qualifiers.isPresent()) {
-                handles = container.listAll(type, qualifiers.get());
-            } else {
-                handles = container.listAll(type);
-            }
+        List<InstanceHandle<T>> handles;
+        if (qualifiers.isPresent()) {
+            handles = container.listAll(type, qualifiers.get());
+        } else {
+            handles = container.listAll(type);
+        }
+
+        if (handles.isEmpty()) {
+            // No matches for the given bean type
+            return null;
+        } else if (handles.size() == 1) {
+            // Only 1 bean exists for the given type so just return it
+            return handles.get(0).get();
+        }
 
+        // For multiple bean matches determine how many have the @Default 
qualifier
+        long defaultBeanCount = handles.stream()
+                .map(InstanceHandle::getBean)
+                .filter(this::isDefaultBean)
+                .count();
+
+        // Determine if all beans for the matching type have the same priority
+        boolean beansHaveSamePriority = handles.stream()
+                .map(InstanceHandle::getBean)
+                .map(InjectableBean::getPriority)
+                .distinct()
+                .count() == 1;
+
+        // Try to resolve the target bean by @Priority and @Default qualifiers
+        if ((defaultBeanCount == 1) || (defaultBeanCount > 1 && 
!beansHaveSamePriority)) {
             List<InstanceHandle<T>> sortedHandles = new 
ArrayList<>(handles.size());
             sortedHandles.addAll(handles);
-
-            if (sortedHandles.size() > 1) {
-                sortedHandles.sort((bean1, bean2) -> {
-                    Integer priority2 = bean2.getBean().getPriority();
-                    Integer priority1 = bean1.getBean().getPriority();
-
-                    int result = priority2.compareTo(priority1);
-                    // If the priority is same, the default bean wins
-                    if (result == 0) {
-                        if (isDefaultBean(bean1.getBean())) {
-                            result = -1;
-                        } else if (isDefaultBean(bean2.getBean())) {
-                            result = 1;
-                        }
+            sortedHandles.sort((bean1, bean2) -> {
+                Integer priority2 = bean2.getBean().getPriority();
+                Integer priority1 = bean1.getBean().getPriority();
+
+                int result = priority2.compareTo(priority1);
+                // If the priority is same, the default bean wins
+                if (result == 0) {
+                    if (isDefaultBean(bean1.getBean())) {
+                        result = -1;
+                    } else if (isDefaultBean(bean2.getBean())) {
+                        result = 1;
                     }
-                    return result;
-                });
-            }
-
-            if (sortedHandles.size() > 0) {
-                return sortedHandles.get(0).get();
-            }
+                }
+                return result;
+            });
+            return sortedHandles.get(0).get();
         }
+
+        // Multiple beans exist for the given type, and we could not determine 
which one to use
+        // Users must resolve the conflict by explicitly referencing the bean 
via endpoint URI options etc
         return null;
     }
 
diff --git 
a/extensions/jpa/deployment/src/main/java/org/apache/camel/quarkus/component/jpa/deployment/JpaProcessor.java
 
b/extensions/jpa/deployment/src/main/java/org/apache/camel/quarkus/component/jpa/deployment/JpaProcessor.java
index 4ec977b19d..9ba2e5ce22 100644
--- 
a/extensions/jpa/deployment/src/main/java/org/apache/camel/quarkus/component/jpa/deployment/JpaProcessor.java
+++ 
b/extensions/jpa/deployment/src/main/java/org/apache/camel/quarkus/component/jpa/deployment/JpaProcessor.java
@@ -23,14 +23,20 @@ import io.quarkus.deployment.annotations.BuildProducer;
 import io.quarkus.deployment.annotations.BuildStep;
 import io.quarkus.deployment.annotations.ExecutionTime;
 import io.quarkus.deployment.annotations.Record;
+import io.quarkus.deployment.builditem.BytecodeTransformerBuildItem;
 import io.quarkus.deployment.builditem.FeatureBuildItem;
+import io.quarkus.gizmo.Gizmo;
 import io.quarkus.hibernate.orm.deployment.PersistenceUnitDescriptorBuildItem;
 import jakarta.persistence.EntityManagerFactory;
 import org.apache.camel.component.jpa.JpaComponent;
+import org.apache.camel.component.jpa.JpaEndpoint;
 import org.apache.camel.quarkus.component.jpa.CamelJpaProducer;
 import org.apache.camel.quarkus.component.jpa.CamelJpaRecorder;
 import 
org.apache.camel.quarkus.core.deployment.spi.CamelBeanQualifierResolverBuildItem;
 import org.apache.camel.quarkus.core.deployment.spi.CamelRuntimeBeanBuildItem;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 class JpaProcessor {
 
@@ -75,4 +81,50 @@ class JpaProcessor {
             }
         }
     }
+
+    // TODO: Remove this and make it possible to override methods in 
JpaEndpoint
+    // https://github.com/apache/camel-quarkus/issues/7369
+    @BuildStep
+    BytecodeTransformerBuildItem 
transformMethodJpaEndpointCreateEntityManagerFactory() {
+        // Since spring-orm is not on the classpath, transform 
JpaEndpoint.createEntityManagerFactory
+        // to avoid trying to create a local LocalEntityManagerFactoryBean and
+        // suppress ClassNotFoundException when the component could not find a 
EntityManagerFactory to use.
+        //
+        // For example:
+        //
+        // protected EntityManagerFactory createEntityManagerFactory() {
+        //     throw new IllegalStateException();
+        // }
+        return new BytecodeTransformerBuildItem.Builder()
+                .setClassToTransform(JpaEndpoint.class.getName())
+                .setCacheable(true)
+                .setVisitorFunction((className, classVisitor) -> {
+                    return new ClassVisitor(Gizmo.ASM_API_VERSION, 
classVisitor) {
+                        @Override
+                        public MethodVisitor visitMethod(int access, String 
name, String descriptor, String signature,
+                                String[] exceptions) {
+                            MethodVisitor visitor = super.visitMethod(access, 
name, descriptor, signature, exceptions);
+
+                            if (name.equals("createEntityManagerFactory")
+                                    && 
descriptor.equals("()Ljakarta/persistence/EntityManagerFactory;")) {
+                                return new 
MethodVisitor(Gizmo.ASM_API_VERSION, visitor) {
+                                    @Override
+                                    public void visitCode() {
+                                        super.visitCode();
+                                        visitor.visitTypeInsn(Opcodes.NEW, 
"java/lang/IllegalStateException");
+                                        visitor.visitInsn(Opcodes.DUP);
+                                        visitor.visitLdcInsn(
+                                                "Cannot create 
EntityManagerFactory. Check quarkus.hibernate-orm configuration.");
+                                        
visitor.visitMethodInsn(Opcodes.INVOKESPECIAL, 
"java/lang/IllegalStateException",
+                                                "<init>", 
"(Ljava/lang/String;)V", false);
+                                        visitor.visitInsn(Opcodes.ATHROW);
+                                    }
+                                };
+                            }
+                            return visitor;
+                        }
+                    };
+                })
+                .build();
+    }
 }
diff --git 
a/integration-tests/jpa/src/main/java/org/apache/camel/quarkus/component/jpa/it/JpaResource.java
 
b/integration-tests/jpa/src/main/java/org/apache/camel/quarkus/component/jpa/it/JpaResource.java
index 4dc0779571..762934284c 100644
--- 
a/integration-tests/jpa/src/main/java/org/apache/camel/quarkus/component/jpa/it/JpaResource.java
+++ 
b/integration-tests/jpa/src/main/java/org/apache/camel/quarkus/component/jpa/it/JpaResource.java
@@ -24,7 +24,12 @@ import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 
+import io.quarkus.arc.ClientProxy;
+import io.quarkus.arc.InjectableBean;
+import jakarta.enterprise.inject.Default;
 import jakarta.inject.Inject;
+import jakarta.inject.Named;
+import jakarta.persistence.EntityManagerFactory;
 import jakarta.ws.rs.Consumes;
 import jakarta.ws.rs.DELETE;
 import jakarta.ws.rs.GET;
@@ -39,6 +44,7 @@ import org.apache.camel.CamelContext;
 import org.apache.camel.Exchange;
 import org.apache.camel.ProducerTemplate;
 import org.apache.camel.component.jpa.JpaConstants;
+import org.apache.camel.component.jpa.JpaEndpoint;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.quarkus.component.jpa.it.model.Fruit;
 
@@ -134,4 +140,33 @@ public class JpaResource {
         mock.reset();
         return Response.ok().build();
     }
+
+    @Path("/entityManagerFactory")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response createJpaEndpoint() {
+        try {
+            String uri = "jpa:" + Fruit.class.getName() + "?nativeQuery=SELECT 
* FROM fruits";
+
+            JpaEndpoint endpoint = context.getEndpoint(uri, JpaEndpoint.class);
+            EntityManagerFactory entityManagerFactory = 
endpoint.getEntityManagerFactory();
+
+            InjectableBean<?> bean = ((ClientProxy) 
entityManagerFactory).arc_bean();
+            Named namedQualifier = (Named) bean.getQualifiers()
+                    .stream()
+                    .filter(qualifier -> 
qualifier.annotationType().equals(Named.class))
+                    .findFirst()
+                    .orElse(null);
+
+            String beanName = namedQualifier != null ? namedQualifier.value() 
: "";
+
+            Map<String, Object> response = Map.of(
+                    "name", beanName,
+                    "default", 
bean.getQualifiers().contains(Default.Literal.INSTANCE));
+
+            return Response.ok(response).build();
+        } catch (Exception e) {
+            return Response.serverError().entity(e.getMessage()).build();
+        }
+    }
 }
diff --git 
a/integration-tests/jpa/src/main/java/org/apache/camel/quarkus/component/jpa/it/JpaRoute.java
 
b/integration-tests/jpa/src/main/java/org/apache/camel/quarkus/component/jpa/it/JpaRoute.java
index 85b396c3af..a4964d81f2 100644
--- 
a/integration-tests/jpa/src/main/java/org/apache/camel/quarkus/component/jpa/it/JpaRoute.java
+++ 
b/integration-tests/jpa/src/main/java/org/apache/camel/quarkus/component/jpa/it/JpaRoute.java
@@ -18,6 +18,7 @@ package org.apache.camel.quarkus.component.jpa.it;
 
 import java.util.Collections;
 
+import io.quarkus.arc.profile.UnlessBuildProfile;
 import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.inject.Inject;
 import jakarta.inject.Named;
@@ -27,6 +28,7 @@ import org.apache.camel.component.jpa.TransactionStrategy;
 import org.apache.camel.processor.idempotent.jpa.JpaMessageIdRepository;
 import org.apache.camel.quarkus.component.jpa.it.model.Fruit;
 
+@UnlessBuildProfile(anyOf = { "single-resource-no-default", 
"multi-resource-no-default" })
 @ApplicationScoped
 public class JpaRoute extends RouteBuilder {
 
diff --git a/integration-tests/jpa/src/main/resources/application.properties 
b/integration-tests/jpa/src/main/resources/application.properties
index 699598208b..b8a35ef880 100644
--- a/integration-tests/jpa/src/main/resources/application.properties
+++ b/integration-tests/jpa/src/main/resources/application.properties
@@ -14,11 +14,32 @@
 ## See the License for the specific language governing permissions and
 ## limitations under the License.
 ## ---------------------------------------------------------------------------
-quarkus.datasource.db-kind=${cq.sqlJdbcKind:h2}
 
-quarkus.datasource.test.db-kind=${cq.sqlJdbcKind:h2}
-quarkus.datasource.test.jdbc.max-size=8
+jpa.model.packages=org.apache.camel.quarkus.component.jpa.it.model,org.apache.camel.processor.idempotent.jpa
 
-quarkus.hibernate-orm.test.packages=org.apache.camel.quarkus.component.jpa.it.model,org.apache.camel.processor.idempotent.jpa
-quarkus.hibernate-orm.test.datasource=test
-quarkus.hibernate-orm.test.database.generation=drop-and-create
+%dev,test,prod.quarkus.datasource.db-kind=${cq.sqlJdbcKind:h2}
+
+%dev,test,prod.quarkus.datasource.test.db-kind=${cq.sqlJdbcKind:h2}
+%dev,test,prod.quarkus.datasource.test.jdbc.max-size=8
+
+%dev,test,prod.quarkus.hibernate-orm.test.packages=${jpa.model.packages}
+%dev,test,prod.quarkus.hibernate-orm.test.datasource=test
+%dev,test,prod.quarkus.hibernate-orm.test.database.generation=drop-and-create
+
+# single-resource-no-default profile to test single named DataSource / 
EntityManagerFactory beans without defaults
+%single-resource-no-default.quarkus.camel.routes-discovery.exclude-patterns=**/*
+%single-resource-no-default.quarkus.datasource.testA.db-kind=h2
+%single-resource-no-default.quarkus.hibernate-orm.testA.packages=${jpa.model.packages}
+%single-resource-no-default.quarkus.hibernate-orm.testA.datasource=testA
+%single-resource-no-default.quarkus.hibernate-orm.testA.database.generation=drop-and-create
+
+# multi-resource-no-default profile to test multiple named DataSource / 
EntityManagerFactory beans without defaults
+%multi-resource-no-default.quarkus.camel.routes-discovery.exclude-patterns=**/*
+%multi-resource-no-default.quarkus.datasource.testA.db-kind=h2
+%multi-resource-no-default.quarkus.hibernate-orm.testA.packages=${jpa.model.packages}
+%multi-resource-no-default.quarkus.hibernate-orm.testA.datasource=testA
+%multi-resource-no-default.quarkus.hibernate-orm.testA.database.generation=drop-and-create
+%multi-resource-no-default.quarkus.datasource.testB.db-kind=h2
+%multi-resource-no-default.quarkus.hibernate-orm.testB.packages=${jpa.model.packages}
+%multi-resource-no-default.quarkus.hibernate-orm.testB.datasource=testB
+%multi-resource-no-default.quarkus.hibernate-orm.testB.database.generation=drop-and-create
diff --git 
a/integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/JpaMultipleNamedResourcesWithNoDefaultAndExplicitEntityManagerFactoryTest.java
 
b/integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/JpaMultipleNamedResourcesWithNoDefaultAndExplicitEntityManagerFactoryTest.java
new file mode 100644
index 0000000000..4e801a4388
--- /dev/null
+++ 
b/integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/JpaMultipleNamedResourcesWithNoDefaultAndExplicitEntityManagerFactoryTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.component.jpa.it;
+
+import java.util.Map;
+
+import io.quarkus.test.junit.QuarkusTest;
+import io.quarkus.test.junit.QuarkusTestProfile;
+import io.quarkus.test.junit.TestProfile;
+import io.restassured.RestAssured;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.Matchers.is;
+
+@QuarkusTest
+@TestProfile(JpaMultipleNamedResourcesWithNoDefaultAndExplicitEntityManagerFactoryTest.class)
+public class 
JpaMultipleNamedResourcesWithNoDefaultAndExplicitEntityManagerFactoryTest 
implements QuarkusTestProfile {
+    @Test
+    void 
multipleNamedResourcesWithoutDefaultAutowiresChosenEntityManagerFactory() {
+        RestAssured.given()
+                .get("/jpa/entityManagerFactory")
+                .then()
+                .statusCode(200)
+                .body(
+                        "name", is("testB"),
+                        "default", is(false));
+    }
+
+    @Override
+    public String getConfigProfile() {
+        return "multi-resource-no-default";
+    }
+
+    @Override
+    public Map<String, String> getConfigOverrides() {
+        return Map.of("camel.component.jpa.entity-managerFactory", "#testB");
+    }
+}
diff --git 
a/integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/JpaMultipleNamedResourcesWithNoDefaultTest.java
 
b/integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/JpaMultipleNamedResourcesWithNoDefaultTest.java
new file mode 100644
index 0000000000..50d1766b72
--- /dev/null
+++ 
b/integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/JpaMultipleNamedResourcesWithNoDefaultTest.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.component.jpa.it;
+
+import io.quarkus.test.junit.QuarkusTest;
+import io.quarkus.test.junit.QuarkusTestProfile;
+import io.quarkus.test.junit.TestProfile;
+import io.restassured.RestAssured;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.Matchers.endsWith;
+
+@QuarkusTest
+@TestProfile(JpaMultipleNamedResourcesWithNoDefaultTest.class)
+public class JpaMultipleNamedResourcesWithNoDefaultTest implements 
QuarkusTestProfile {
+
+    @Test
+    void multipleNamedResourcesWithoutDefaultNotAutowirable() {
+        // There are multiple named EntityManagerFactory beans but no default 
bean
+        // EntityManagerFactory autowiring should fail
+        RestAssured.given()
+                .get("/jpa/entityManagerFactory")
+                .then()
+                .statusCode(500)
+                .body(endsWith("Check quarkus.hibernate-orm configuration."));
+    }
+
+    @Override
+    public String getConfigProfile() {
+        return "multi-resource-no-default";
+    }
+}
diff --git 
a/integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/JpaSingleNamedResourceWithNoDefaultTest.java
 
b/integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/JpaSingleNamedResourceWithNoDefaultTest.java
new file mode 100644
index 0000000000..c1ee3d8d36
--- /dev/null
+++ 
b/integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/JpaSingleNamedResourceWithNoDefaultTest.java
@@ -0,0 +1,45 @@
+/*
+ * 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.component.jpa.it;
+
+import io.quarkus.test.junit.QuarkusTest;
+import io.quarkus.test.junit.QuarkusTestProfile;
+import io.quarkus.test.junit.TestProfile;
+import io.restassured.RestAssured;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.Matchers.is;
+
+@QuarkusTest
+@TestProfile(JpaSingleNamedResourceWithNoDefaultTest.class)
+public class JpaSingleNamedResourceWithNoDefaultTest implements 
QuarkusTestProfile {
+    @Test
+    void singleNamedResourceWithoutDefaultAutowiresEntityManagerFactory() {
+        RestAssured.given()
+                .get("/jpa/entityManagerFactory")
+                .then()
+                .statusCode(200)
+                .body(
+                        "name", is("testA"),
+                        "default", is(false));
+    }
+
+    @Override
+    public String getConfigProfile() {
+        return "single-resource-no-default";
+    }
+}
diff --git 
a/integration-tests/sql/src/main/java/org/apache/camel/quarkus/component/sql/it/SqlDbInitializer.java
 
b/integration-tests/sql/src/main/java/org/apache/camel/quarkus/component/sql/it/SqlDbInitializer.java
index fa2b9c24ea..f651f1b6f7 100644
--- 
a/integration-tests/sql/src/main/java/org/apache/camel/quarkus/component/sql/it/SqlDbInitializer.java
+++ 
b/integration-tests/sql/src/main/java/org/apache/camel/quarkus/component/sql/it/SqlDbInitializer.java
@@ -25,6 +25,7 @@ import java.sql.SQLException;
 import java.sql.Statement;
 
 import io.agroal.api.AgroalDataSource;
+import io.quarkus.arc.profile.UnlessBuildProfile;
 import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.inject.Inject;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
@@ -32,6 +33,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @ApplicationScoped
+@UnlessBuildProfile(anyOf = { "multi-ds-no-default", "multi-ds-with-default" })
 public class SqlDbInitializer {
 
     private static final Logger LOGGER = 
LoggerFactory.getLogger(SqlDbInitializer.class);
diff --git 
a/integration-tests/sql/src/main/java/org/apache/camel/quarkus/component/sql/it/SqlResource.java
 
b/integration-tests/sql/src/main/java/org/apache/camel/quarkus/component/sql/it/SqlResource.java
index 36849c2477..0c6af9c4f0 100644
--- 
a/integration-tests/sql/src/main/java/org/apache/camel/quarkus/component/sql/it/SqlResource.java
+++ 
b/integration-tests/sql/src/main/java/org/apache/camel/quarkus/component/sql/it/SqlResource.java
@@ -20,6 +20,7 @@ import java.net.URI;
 import java.util.*;
 import java.util.stream.Collectors;
 
+import io.quarkus.arc.profile.UnlessBuildProfile;
 import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.inject.Inject;
 import jakarta.inject.Named;
@@ -42,6 +43,7 @@ import org.springframework.util.LinkedCaseInsensitiveMap;
 
 @Path("/sql")
 @ApplicationScoped
+@UnlessBuildProfile(anyOf = { "multi-ds-no-default", "multi-ds-with-default" })
 public class SqlResource {
 
     @ConfigProperty(name = "quarkus.datasource.db-kind")
diff --git 
a/integration-tests/sql/src/main/java/org/apache/camel/quarkus/component/sql/it/SqlRoutes.java
 
b/integration-tests/sql/src/main/java/org/apache/camel/quarkus/component/sql/it/SqlRoutes.java
index 07fa20034b..a1d2b25093 100644
--- 
a/integration-tests/sql/src/main/java/org/apache/camel/quarkus/component/sql/it/SqlRoutes.java
+++ 
b/integration-tests/sql/src/main/java/org/apache/camel/quarkus/component/sql/it/SqlRoutes.java
@@ -26,6 +26,7 @@ import java.util.Map;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 import io.agroal.api.AgroalDataSource;
+import io.quarkus.arc.profile.UnlessBuildProfile;
 import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.enterprise.inject.Produces;
 import jakarta.inject.Inject;
@@ -40,6 +41,7 @@ import 
org.apache.camel.processor.idempotent.jdbc.JdbcMessageIdRepository;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.springframework.transaction.jta.JtaTransactionManager;
 
+@UnlessBuildProfile(anyOf = { "multi-ds-no-default", "multi-ds-with-default" })
 @ApplicationScoped
 public class SqlRoutes extends RouteBuilder {
 
diff --git 
a/integration-tests/sql/src/main/java/org/apache/camel/quarkus/component/sql/it/datasource/SqlDataSourceResource.java
 
b/integration-tests/sql/src/main/java/org/apache/camel/quarkus/component/sql/it/datasource/SqlDataSourceResource.java
new file mode 100644
index 0000000000..b705c36c0f
--- /dev/null
+++ 
b/integration-tests/sql/src/main/java/org/apache/camel/quarkus/component/sql/it/datasource/SqlDataSourceResource.java
@@ -0,0 +1,64 @@
+/*
+ * 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.component.sql.it.datasource;
+
+import java.util.Map;
+
+import javax.sql.DataSource;
+
+import io.quarkus.arc.ClientProxy;
+import io.quarkus.arc.InjectableBean;
+import jakarta.enterprise.inject.Default;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.sql.SqlEndpoint;
+
+@Path("/sql/datasource")
+public class SqlDataSourceResource {
+    @Inject
+    CamelContext camelContext;
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response createSqlEndpoint(@QueryParam("dataSourceRef") String 
dataSourceRef) {
+        try {
+            String uri = "sql:SELECT * FROM some_table";
+            if (dataSourceRef != null) {
+                uri += "?dataSource=#" + dataSourceRef;
+            }
+
+            SqlEndpoint endpoint = camelContext.getEndpoint(uri, 
SqlEndpoint.class);
+            DataSource dataSource = endpoint.getDataSource();
+
+            InjectableBean<?> bean = ((ClientProxy) dataSource).arc_bean();
+            String beanName = bean.getName() == null ? "" : bean.getName();
+            Map<String, Object> response = Map.of(
+                    "name", beanName,
+                    "default", 
bean.getQualifiers().contains(Default.Literal.INSTANCE));
+
+            return Response.ok(response).build();
+        } catch (Exception e) {
+            return Response.serverError().entity(e.getMessage()).build();
+        }
+    }
+}
diff --git a/integration-tests/sql/src/main/resources/application.properties 
b/integration-tests/sql/src/main/resources/application.properties
index 146ece032b..a2364e4000 100644
--- a/integration-tests/sql/src/main/resources/application.properties
+++ b/integration-tests/sql/src/main/resources/application.properties
@@ -15,7 +15,24 @@
 ## limitations under the License.
 ## ---------------------------------------------------------------------------
 
-quarkus.datasource.db-kind=${cq.sqlJdbcKind:h2}
+# Default profile configuration
+%dev,test,prod.quarkus.datasource.db-kind=${cq.sqlJdbcKind:h2}
+
+# multi-ds-with-default profile to test multiple named DataSource beans with 
the default DataSource
+%multi-ds-with-default.quarkus.camel.routes-discovery.exclude-patterns=**/*
+%multi-ds-with-default.quarkus.datasource.db-kind=h2
+%multi-ds-with-default.quarkus.datasource.devservices.enabled=false
+%multi-ds-with-default.quarkus.datasource.testA.db-kind=h2
+%multi-ds-with-default.quarkus.datasource.testA.devservices.enabled=false
+%multi-ds-with-default.quarkus.datasource.testB.db-kind=h2
+%multi-ds-with-default.quarkus.datasource.testB.devservices.enabled=false
+
+# multi-ds-no-default profile to test multiple named DataSource beans without 
a default DataSource
+%multi-ds-no-default.quarkus.camel.routes-discovery.exclude-patterns=**/*
+%multi-ds-no-default.quarkus.datasource.testA.db-kind=h2
+%multi-ds-no-default.quarkus.datasource.testA.devservices.enabled=false
+%multi-ds-no-default.quarkus.datasource.testB.db-kind=h2
+%multi-ds-no-default.quarkus.datasource.testB.devservices.enabled=false
 
 #
 # Camel Quarkus SQL
diff --git 
a/integration-tests/sql/src/test/java/org/apache/camel/quarkus/component/sql/it/SqlMultipleNamedDatasourceWithDefaultTest.java
 
b/integration-tests/sql/src/test/java/org/apache/camel/quarkus/component/sql/it/SqlMultipleNamedDatasourceWithDefaultTest.java
new file mode 100644
index 0000000000..929f9bd92e
--- /dev/null
+++ 
b/integration-tests/sql/src/test/java/org/apache/camel/quarkus/component/sql/it/SqlMultipleNamedDatasourceWithDefaultTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.component.sql.it;
+
+import io.quarkus.test.junit.QuarkusTest;
+import io.quarkus.test.junit.QuarkusTestProfile;
+import io.quarkus.test.junit.TestProfile;
+import io.restassured.RestAssured;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.Matchers.blankOrNullString;
+import static org.hamcrest.Matchers.is;
+
+@QuarkusTest
+@TestProfile(SqlMultipleNamedDatasourceWithDefaultTest.class)
+public class SqlMultipleNamedDatasourceWithDefaultTest implements 
QuarkusTestProfile {
+    @Test
+    void multipleNamedDataSourcesWithDefaultAutowired() {
+        RestAssured.given()
+                .get("/sql/datasource")
+                .then()
+                .statusCode(200)
+                .body(
+                        "name", blankOrNullString(),
+                        "default", is(true));
+    }
+
+    @Test
+    void multipleNamedDataSourcesWithExplicitLookup() {
+        RestAssured.given()
+                .queryParam("dataSourceRef", "testB")
+                .get("/sql/datasource")
+                .then()
+                .statusCode(200)
+                .body(
+                        "name", is("testB"),
+                        "default", is(false));
+    }
+
+    @Override
+    public String getConfigProfile() {
+        return "multi-ds-with-default";
+    }
+}
diff --git 
a/integration-tests/sql/src/test/java/org/apache/camel/quarkus/component/sql/it/SqlMultipleNamedDatasourceWithNoDefaultTest.java
 
b/integration-tests/sql/src/test/java/org/apache/camel/quarkus/component/sql/it/SqlMultipleNamedDatasourceWithNoDefaultTest.java
new file mode 100644
index 0000000000..0c82e38a98
--- /dev/null
+++ 
b/integration-tests/sql/src/test/java/org/apache/camel/quarkus/component/sql/it/SqlMultipleNamedDatasourceWithNoDefaultTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.component.sql.it;
+
+import io.quarkus.test.junit.QuarkusTest;
+import io.quarkus.test.junit.QuarkusTestProfile;
+import io.quarkus.test.junit.TestProfile;
+import io.restassured.RestAssured;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.Matchers.endsWith;
+import static org.hamcrest.Matchers.is;
+
+@QuarkusTest
+@TestProfile(SqlMultipleNamedDatasourceWithNoDefaultTest.class)
+public class SqlMultipleNamedDatasourceWithNoDefaultTest implements 
QuarkusTestProfile {
+    @Test
+    void multipleNamedDataSourcesWithoutDefaultNotAutowirable() {
+        // There are multiple named DataSource beans but no default bean
+        // DataSource autowiring should fail
+        RestAssured.given()
+                .get("/sql/datasource")
+                .then()
+                .statusCode(500)
+                .body(endsWith("DataSource must be configured"));
+    }
+
+    @Test
+    void multipleNamedDataSourcesWithExplicitLookup() {
+        RestAssured.given()
+                .queryParam("dataSourceRef", "testB")
+                .get("/sql/datasource")
+                .then()
+                .statusCode(200)
+                .body(
+                        "name", is("testB"),
+                        "default", is(false));
+    }
+
+    @Override
+    public String getConfigProfile() {
+        return "multi-ds-no-default";
+    }
+}


Reply via email to