This is an automated email from the ASF dual-hosted git repository. ppalaga 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 eb3d702e98 Fix #7254 to support named entityManagerFactory in camel-quarkus-jpa eb3d702e98 is described below commit eb3d702e989d159b8315ac8f1494c368b7a9f902 Author: Zheng Feng <zh.f...@gmail.com> AuthorDate: Mon Apr 14 23:39:06 2025 +0800 Fix #7254 to support named entityManagerFactory in camel-quarkus-jpa --- .../camel/quarkus/core/RuntimeBeanRepository.java | 12 ++ .../component/jpa/deployment/JpaProcessor.java | 25 ++++ .../quarkus/component/jpa/CamelJpaRecorder.java | 16 +++ .../camel/quarkus/component/jpa/it/JpaRoute.java | 2 + .../jpa/src/main/resources/application.properties | 8 +- .../camel/quarkus/component/jpa/it/JpaTest.java | 149 +-------------------- .../jpa/it/{JpaTest.java => JpaTestBase.java} | 4 +- .../quarkus/component/jpa/it/NamedJpaTest.java | 18 +-- .../component/jpa/it/NamedJpaTestProfile.java | 18 ++- 9 files changed, 77 insertions(+), 175 deletions(-) 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 4522183835..2b860c15b9 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 @@ -25,6 +25,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import io.quarkus.arc.Arc; import io.quarkus.arc.ArcContainer; @@ -80,6 +81,17 @@ public final class RuntimeBeanRepository implements BeanRepository { private static <T> Optional<T> getReferenceByName(BeanManager manager, String name, Class<T> type) { Set<Bean<?>> beans = manager.getBeans(name); + // If it is a Synthetic bean, it should match with type + beans = beans.stream() + .filter(bean -> { + if (bean instanceof InjectableBean injectableBean) { + return !injectableBean.getKind().equals(InjectableBean.Kind.SYNTHETIC) + || bean.getTypes().contains(type); + } else { + return true; + } + }).collect(Collectors.toSet()); + if (beans.isEmpty()) { // Fallback to searching explicitly with NamedLiteral beans = manager.getBeans(type, NamedLiteral.of(name)); 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 adfc8405b8..4ec977b19d 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 @@ -16,15 +16,20 @@ */ package org.apache.camel.quarkus.component.jpa.deployment; +import java.util.List; + import io.quarkus.arc.deployment.AdditionalBeanBuildItem; 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.FeatureBuildItem; +import io.quarkus.hibernate.orm.deployment.PersistenceUnitDescriptorBuildItem; +import jakarta.persistence.EntityManagerFactory; import org.apache.camel.component.jpa.JpaComponent; 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; class JpaProcessor { @@ -50,4 +55,24 @@ class JpaProcessor { JpaComponent.class.getName(), recorder.createJpaComponent())); } + + @Record(ExecutionTime.STATIC_INIT) + @BuildStep + void registerPersistenceUnitCamelBeanQualifierResolver( + List<PersistenceUnitDescriptorBuildItem> persistenceUnitDescriptors, + BuildProducer<CamelBeanQualifierResolverBuildItem> camelBeanQualifierResolver, + CamelJpaRecorder recorder) { + // If there are multiple persistence unit configs, then users need to explicitly state which one to use + // via their component / endpoint configuration. Otherwise if there is just 1, and it is not the default, + // we can create a resolver for PersistenceUnitLiteral and make named PersistenceUnit autowiring work as expected + if (persistenceUnitDescriptors.size() == 1) { + PersistenceUnitDescriptorBuildItem persistenceUnitDescriptor = persistenceUnitDescriptors.get(0); + if (!persistenceUnitDescriptor.getPersistenceUnitName().equals("<default>")) { + CamelBeanQualifierResolverBuildItem beanQualifierResolver = new CamelBeanQualifierResolverBuildItem( + EntityManagerFactory.class, + recorder.createPersistenceUnitQualifierResolver(persistenceUnitDescriptor.getPersistenceUnitName())); + camelBeanQualifierResolver.produce(beanQualifierResolver); + } + } + } } diff --git a/extensions/jpa/runtime/src/main/java/org/apache/camel/quarkus/component/jpa/CamelJpaRecorder.java b/extensions/jpa/runtime/src/main/java/org/apache/camel/quarkus/component/jpa/CamelJpaRecorder.java index 658d5424ee..eb96ba41d3 100644 --- a/extensions/jpa/runtime/src/main/java/org/apache/camel/quarkus/component/jpa/CamelJpaRecorder.java +++ b/extensions/jpa/runtime/src/main/java/org/apache/camel/quarkus/component/jpa/CamelJpaRecorder.java @@ -16,9 +16,13 @@ */ package org.apache.camel.quarkus.component.jpa; +import java.lang.annotation.Annotation; + +import io.quarkus.hibernate.orm.PersistenceUnit; import io.quarkus.runtime.RuntimeValue; import io.quarkus.runtime.annotations.Recorder; import org.apache.camel.component.jpa.JpaComponent; +import org.apache.camel.quarkus.core.CamelBeanQualifierResolver; @Recorder public class CamelJpaRecorder { @@ -28,4 +32,16 @@ public class CamelJpaRecorder { component.setTransactionStrategy(new QuarkusTransactionStrategy()); return new RuntimeValue<>(component); } + + public RuntimeValue<CamelBeanQualifierResolver> createPersistenceUnitQualifierResolver(String persistenceUnitName) { + return new RuntimeValue<>(new CamelBeanQualifierResolver() { + final PersistenceUnit.PersistenceUnitLiteral persistenceUnitLiteral = new PersistenceUnit.PersistenceUnitLiteral( + persistenceUnitName); + + @Override + public Annotation[] resolveQualifiers() { + return new Annotation[] { persistenceUnitLiteral }; + } + }); + } } 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 46f5c1e084..85b396c3af 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 @@ -20,6 +20,7 @@ import java.util.Collections; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; +import jakarta.inject.Named; import jakarta.persistence.EntityManagerFactory; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.component.jpa.TransactionStrategy; @@ -30,6 +31,7 @@ import org.apache.camel.quarkus.component.jpa.it.model.Fruit; public class JpaRoute extends RouteBuilder { @Inject + @Named("test") EntityManagerFactory entityManagerFactory; @Inject diff --git a/integration-tests/jpa/src/main/resources/application.properties b/integration-tests/jpa/src/main/resources/application.properties index 81158c974b..df88312f05 100644 --- a/integration-tests/jpa/src/main/resources/application.properties +++ b/integration-tests/jpa/src/main/resources/application.properties @@ -15,6 +15,10 @@ ## limitations under the License. ## --------------------------------------------------------------------------- quarkus.datasource.db-kind=${cq.sqlJdbcKind:h2} -quarkus.datasource.jdbc.max-size=8 -quarkus.hibernate-orm.database.generation=drop-and-create +quarkus.datasource."test".db-kind=${cq.sqlJdbcKind:h2} +quarkus.datasource."test".jdbc.max-size=8 + +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 diff --git a/integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/JpaTest.java b/integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/JpaTest.java index 5bfd83e592..4b284ad2b7 100644 --- a/integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/JpaTest.java +++ b/integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/JpaTest.java @@ -16,155 +16,8 @@ */ package org.apache.camel.quarkus.component.jpa.it; -import java.util.concurrent.TimeUnit; -import java.util.stream.IntStream; - import io.quarkus.test.junit.QuarkusTest; -import io.restassured.RestAssured; -import io.restassured.http.ContentType; -import jakarta.json.bind.JsonbBuilder; -import org.apache.camel.quarkus.component.jpa.it.model.Fruit; -import org.eclipse.microprofile.config.Config; -import org.eclipse.microprofile.config.ConfigProvider; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static org.awaitility.Awaitility.await; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.greaterThanOrEqualTo; -import static org.hamcrest.Matchers.hasItems; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; @QuarkusTest -class JpaTest { - - static final String[] FRUITS = new String[] { "Orange", "Lemon", "Plum" }; - - @BeforeAll - public static void storeFruits() { - final Config config = ConfigProvider.getConfig(); - int port = config.getValue("quarkus.http.test-port", int.class); - RestAssured.port = port; - for (String fruit : FRUITS) { - RestAssured.given() - .contentType(ContentType.JSON) - .body(JsonbBuilder.create().toJson(new Fruit(fruit))) - .post("/jpa/fruit") - .then() - .statusCode(201); - } - } - - @Test - public void testProducerQuery() { - RestAssured.get("/jpa/fruit") - .then() - .statusCode(200) - .body("name", containsInAnyOrder(FRUITS)); - } - - @Test - public void testProducerNamedQuery() { - RestAssured.get("/jpa/fruit/named/" + FRUITS[0]) - .then() - .statusCode(200) - .body("name", contains(FRUITS[0])); - } - - @Test - public void testProducerNativeQuery() { - RestAssured.get("/jpa/fruit/native/2") - .then() - .statusCode(200) - .body("name", contains(FRUITS[1])); - } - - @Test - public void testConsumer() { - IntStream.range(1, 3).parallel().forEach((id) -> { - await().atMost(10L, TimeUnit.SECONDS).until(() -> findFruit(id).getProcessed()); - }); - - RestAssured.get("/jpa/mock/processed") - .then() - .statusCode(200) - .body("size()", greaterThanOrEqualTo(3)); - } - - @Test - public void testTransaction() { - final Fruit rejected = new Fruit("Potato"); - - final int acceptedId = RestAssured.given() - .contentType(ContentType.JSON) - .body(JsonbBuilder.create().toJson(new Fruit("Grapes"))) - .post("/jpa/direct/transaction") - .then() - .statusCode(200) - .body("id", notNullValue()) - .body("name", is("Grapes")) - .extract().jsonPath().getInt("id"); - - try { - RestAssured.given() - .contentType(ContentType.JSON) - .body(JsonbBuilder.create().toJson(rejected)) - .header("rollback", true) - .post("/jpa/direct/transaction") - .then() - .statusCode(500); - - RestAssured.get("/jpa/fruit/named/Grapes") - .then() - .statusCode(200) - .body("name", contains("Grapes")); - - RestAssured.get("/jpa/fruit/named/" + rejected.getName()) - .then() - .statusCode(200) - .body("$.size()", is(0)); - } finally { - RestAssured.delete("/jpa/fruit/" + acceptedId) - .then() - .statusCode(200); - } - } - - @Test - public void testJpaMessageIdRepository() { - IntStream.of(1, 2, 1, 3, 2).forEach((id) -> { - RestAssured.given() - .contentType(ContentType.JSON) - .body(JsonbBuilder.create().toJson(new Fruit(Integer.toString(id)))) - .header("messageId", id) - .post("/jpa/direct/idempotent") - .then() - .statusCode(200); - }); - - RestAssured.given() - .contentType(ContentType.JSON) - .post("/jpa/direct/idempotentLog") - .then() - .statusCode(200) - .body("$.size()", is(3)) - .body("messageId", containsInAnyOrder("1", "2", "3")) - .body("processorName", hasItems("idempotentProcessor")); - - RestAssured.get("/jpa/mock/idempotent") - .then() - .statusCode(200) - .body("size()", is(3)); - } - - public Fruit findFruit(int id) { - return JsonbBuilder.create().fromJson( - RestAssured.get("/jpa/fruit/" + id) - .then() - .statusCode(200) - .extract().body().asString(), - Fruit.class); - } +public class JpaTest extends JpaTestBase { } diff --git a/integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/JpaTest.java b/integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/JpaTestBase.java similarity index 98% copy from integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/JpaTest.java copy to integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/JpaTestBase.java index 5bfd83e592..873ce244ff 100644 --- a/integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/JpaTest.java +++ b/integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/JpaTestBase.java @@ -19,7 +19,6 @@ package org.apache.camel.quarkus.component.jpa.it; import java.util.concurrent.TimeUnit; import java.util.stream.IntStream; -import io.quarkus.test.junit.QuarkusTest; import io.restassured.RestAssured; import io.restassured.http.ContentType; import jakarta.json.bind.JsonbBuilder; @@ -37,8 +36,7 @@ import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; -@QuarkusTest -class JpaTest { +public class JpaTestBase { static final String[] FRUITS = new String[] { "Orange", "Lemon", "Plum" }; diff --git a/extensions/jpa/runtime/src/main/java/org/apache/camel/quarkus/component/jpa/CamelJpaRecorder.java b/integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/NamedJpaTest.java similarity index 63% copy from extensions/jpa/runtime/src/main/java/org/apache/camel/quarkus/component/jpa/CamelJpaRecorder.java copy to integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/NamedJpaTest.java index 658d5424ee..d793e81e4b 100644 --- a/extensions/jpa/runtime/src/main/java/org/apache/camel/quarkus/component/jpa/CamelJpaRecorder.java +++ b/integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/NamedJpaTest.java @@ -14,18 +14,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.quarkus.component.jpa; +package org.apache.camel.quarkus.component.jpa.it; -import io.quarkus.runtime.RuntimeValue; -import io.quarkus.runtime.annotations.Recorder; -import org.apache.camel.component.jpa.JpaComponent; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; -@Recorder -public class CamelJpaRecorder { - - public RuntimeValue<JpaComponent> createJpaComponent() { - JpaComponent component = new JpaComponent(); - component.setTransactionStrategy(new QuarkusTransactionStrategy()); - return new RuntimeValue<>(component); - } +@QuarkusTest +@TestProfile(NamedJpaTestProfile.class) +public class NamedJpaTest extends JpaTestBase { } diff --git a/extensions/jpa/runtime/src/main/java/org/apache/camel/quarkus/component/jpa/CamelJpaRecorder.java b/integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/NamedJpaTestProfile.java similarity index 63% copy from extensions/jpa/runtime/src/main/java/org/apache/camel/quarkus/component/jpa/CamelJpaRecorder.java copy to integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/NamedJpaTestProfile.java index 658d5424ee..6230bec236 100644 --- a/extensions/jpa/runtime/src/main/java/org/apache/camel/quarkus/component/jpa/CamelJpaRecorder.java +++ b/integration-tests/jpa/src/test/java/org/apache/camel/quarkus/component/jpa/it/NamedJpaTestProfile.java @@ -14,18 +14,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.quarkus.component.jpa; -import io.quarkus.runtime.RuntimeValue; -import io.quarkus.runtime.annotations.Recorder; -import org.apache.camel.component.jpa.JpaComponent; +package org.apache.camel.quarkus.component.jpa.it; -@Recorder -public class CamelJpaRecorder { +import java.util.Map; - public RuntimeValue<JpaComponent> createJpaComponent() { - JpaComponent component = new JpaComponent(); - component.setTransactionStrategy(new QuarkusTransactionStrategy()); - return new RuntimeValue<>(component); +import io.quarkus.test.junit.QuarkusTestProfile; + +public class NamedJpaTestProfile implements QuarkusTestProfile { + @Override + public Map<String, String> getConfigOverrides() { + return Map.of("camel.component.jpa.entity-managerFactory", "#test"); } }