Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 19 additions & 11 deletions components/camel-jpa/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<description>Camel JPA support</description>

<properties>
<camel.surefire.fork.additional-vmargs>-javaagent:${project.basedir}/target/openjpa-${openjpa-version}.jar -Xmx3G</camel.surefire.fork.additional-vmargs>
<camel.surefire.fork.additional-vmargs>-Xmx3G</camel.surefire.fork.additional-vmargs>
<camel.surefire.forkTimeout>240</camel.surefire.forkTimeout>
</properties>

Expand Down Expand Up @@ -94,7 +94,15 @@
<artifactId>h2</artifactId>
<version>${h2-version}</version>
<scope>test</scope>
</dependency>
</dependency>
<dependency>
<!-- always on the test classpath (not only in the hibernate profile) so that
KeyValueEntryHibernateMappingTest verifies Hibernate entity mapping in every build -->
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate-version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
Expand Down Expand Up @@ -134,6 +142,11 @@
<name>!hibernate</name>
</property>
</activation>
<properties>
<!-- the OpenJPA enhancer agent must only be attached when the OpenJPA provider is in use;
with -Dhibernate the agent jar is not copied and the forked JVM would fail to start -->
<camel.surefire.fork.additional-vmargs>-javaagent:${project.basedir}/target/openjpa-${openjpa-version}.jar -Xmx3G</camel.surefire.fork.additional-vmargs>
</properties>
<build>
<pluginManagement>
<plugins>
Expand Down Expand Up @@ -231,8 +244,11 @@
<goals>
<goal>copy-resources</goal>
</goals>
<phase>generate-test-resources</phase>
<!-- must run after the default testResources goal so the Hibernate
variant reliably replaces the default OpenJPA persistence.xml -->
<phase>process-test-resources</phase>
<configuration>
<overwrite>true</overwrite>
<resources>
<resource>
<directory>
Expand All @@ -247,14 +263,6 @@
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate-version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</profile>
<profile>
<id>full</id>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import jakarta.persistence.Id;
import jakarta.persistence.Lob;
import jakarta.persistence.Table;
import jakarta.persistence.Transient;

/**
* JPA entity representing a single key-value entry in the {@code CAMEL_KEYVALUE} table.
Expand Down Expand Up @@ -97,6 +98,7 @@ public void setExpiresAt(long expiresAt) {
*
* @return whether the entry is expired
*/
@Transient
public boolean isExpired() {
return expiresAt > 0 && System.currentTimeMillis() >= expiresAt;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
import org.apache.camel.examples.Customer;
import org.apache.camel.test.junit6.CamelTestSupport;
import org.junit.jupiter.api.AfterEach;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import static org.junit.jupiter.api.Assertions.assertEquals;
Expand All @@ -53,27 +51,24 @@ protected void setUp(String endpointUri) throws Exception {
}
entityManager = endpoint.getEntityManagerFactory().createEntityManager();

transactionTemplate.execute(new TransactionCallback<Object>() {
public Object doInTransaction(TransactionStatus status) {
entityManager.joinTransaction();
entityManager.createQuery("delete from " + Customer.class.getName()).executeUpdate();
return null;
}
});
// use a plain resource-local transaction: em.joinTransaction() enlists with the Spring-managed
// transaction only under OpenJPA; under Hibernate it silently begins a local transaction that
// is never committed, so the cleanup would be lost
entityManager.getTransaction().begin();
entityManager.createQuery("delete from " + Customer.class.getName()).executeUpdate();
// bulk delete does not cascade, so remove the orphaned addresses explicitly
entityManager.createQuery("delete from " + Address.class.getName()).executeUpdate();
entityManager.getTransaction().commit();

assertEntitiesInDatabase(0, Customer.class.getName());
assertEntitiesInDatabase(0, Address.class.getName());
}

protected void save(final Object persistable) {
transactionTemplate.execute(new TransactionCallback<Object>() {
public Object doInTransaction(TransactionStatus status) {
entityManager.joinTransaction();
entityManager.persist(persistable);
entityManager.flush();
return null;
}
});
entityManager.getTransaction().begin();
entityManager.persist(persistable);
entityManager.flush();
entityManager.getTransaction().commit();
}

protected void assertEntitiesInDatabase(int count, String entity) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,10 @@ public void configure() {
from("direct:namedQuery")
.to("jpa://" + Customer.class.getName() + "?namedQuery=findAllCustomersWithName&parameters=#params");
from("direct:nativeQuery")
.to("jpa://" + MultiSteps.class.getName() + "?nativeQuery=select * from MultiSteps where step = 1");
// explicit column list: the column order of "select *" depends on the DDL the
// JPA provider generated, so positional access to the result would not be stable
.to("jpa://" + MultiSteps.class.getName()
+ "?nativeQuery=select id, address, step from MultiSteps where step = 1");
from("direct:nativeQueryWithResultClass")
.to("jpa://" + MultiSteps.class.getName()
+ "?resultClass=org.apache.camel.examples.MultiSteps&nativeQuery=select * from MultiSteps where step = 1");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* 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.processor.keyvalue.jpa;

import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

/**
* Verifies in every build (not only with -Dhibernate) that Hibernate can map {@link KeyValueEntry}. The entity is
* shipped in the camel-jpa jar and e.g. Quarkus auto-discovers it from the classpath and always maps it with Hibernate,
* so a mapping problem breaks applications that never use the KeyValueRepository (CAMEL-24604: a derived getter
* without @Transient made Hibernate fail with "Could not locate setter method for property 'expired'").
* <p>
* Uses the native Hibernate bootstrap on purpose: it does not go through jakarta.persistence provider resolution, so
* the rest of the test suite keeps using the provider selected by the active maven profile.
*/
class KeyValueEntryHibernateMappingTest {

@Test
void hibernateMustBeAbleToMapKeyValueEntry() {
StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
.applySetting("hibernate.connection.driver_class", "org.h2.Driver")
.applySetting("hibernate.connection.url", "jdbc:h2:mem:camel24604")
.build();
try {
assertDoesNotThrow(() -> new MetadataSources(registry)
.addAnnotatedClass(KeyValueEntry.class)
.buildMetadata()
.buildSessionFactory()
.close(),
"Hibernate should be able to build a SessionFactory for KeyValueEntry");
} finally {
StandardServiceRegistryBuilder.destroy(registry);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
</persistence-unit>

<persistence-unit name="custom" transaction-type="RESOURCE_LOCAL">
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<class>org.apache.camel.examples.MultiSteps</class>
<class>org.apache.camel.examples.SendEmail</class>

Expand All @@ -63,6 +64,7 @@
</persistence-unit>

<persistence-unit name="pooling" transaction-type="RESOURCE_LOCAL">
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<class>org.apache.camel.examples.SendEmail</class>

<properties>
Expand All @@ -80,6 +82,7 @@
</persistence-unit>

<persistence-unit name="keyvalueDb" transaction-type="RESOURCE_LOCAL">
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<class>org.apache.camel.processor.keyvalue.jpa.KeyValueEntry</class>

<properties>
Expand All @@ -93,6 +96,7 @@

<!-- START SNIPPET: e1 -->
<persistence-unit name="idempotentDb" transaction-type="RESOURCE_LOCAL">
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<class>org.apache.camel.processor.idempotent.jpa.MessageProcessed</class>

<properties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
<property name="hibernate.connection.driver_class" value="org.h2.Driver"/>
<property name="hibernate.connection.url" value="jdbc:h2:./target/h2;DB_CLOSE_DELAY=-1"/>
<property name="hibernate.hbm2ddl.auto" value="create"/>
<!-- update, not create: several tests use multiple JPA endpoints, each creating its own
EntityManagerFactory against this database; "create" would drop and recreate the schema
mid-test. OpenJPA's SynchronizeMappings=buildSchema is additive in the same way. -->
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>

Expand Down Expand Up @@ -79,6 +82,19 @@
</properties>
</persistence-unit>

<persistence-unit name="keyvalueDb" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

<class>org.apache.camel.processor.keyvalue.jpa.KeyValueEntry</class>

<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
<property name="hibernate.connection.driver_class" value="org.h2.Driver"/>
<property name="hibernate.connection.url" value="jdbc:h2:./target/keyvalueTest;DB_CLOSE_DELAY=-1"/>
<property name="hibernate.hbm2ddl.auto" value="create"/>
</properties>
</persistence-unit>

<persistence-unit name="skipLockedEntiy" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

Expand Down