diff --git a/.github/workflows/ci-actions.yml b/.github/workflows/ci-actions.yml index 8f51c4b65e3c7..f59379f0dc061 100644 --- a/.github/workflows/ci-actions.yml +++ b/.github/workflows/ci-actions.yml @@ -416,13 +416,12 @@ jobs: - category: Data2 db2: "true" mysql: "true" - postgres: "true" mariadb: "true" timeout: 65 test-modules: > jpa - jpa-postgresql jpa-mysql + jpa-db2 reactive-mysql-client reactive-db2-client hibernate-reactive-db2 @@ -445,8 +444,9 @@ jobs: hibernate-orm-rest-data-panache - category: Data5 postgres: "true" - timeout: 55 + timeout: 60 test-modules: > + jpa-postgresql hibernate-search-elasticsearch narayana-stm narayana-jta diff --git a/bom/runtime/pom.xml b/bom/runtime/pom.xml index c400702dcbe8d..574b8ca71ec70 100644 --- a/bom/runtime/pom.xml +++ b/bom/runtime/pom.xml @@ -115,6 +115,7 @@ 8.0.20 7.2.2.jre8 10.14.2.0 + 11.5.4.0 1.2.6 4.3.0 5.6.2 @@ -708,6 +709,11 @@ quarkus-jaeger-deployment ${project.version} + + io.quarkus + quarkus-jdbc-db2 + ${project.version} + io.quarkus quarkus-jdbc-postgresql @@ -3305,6 +3311,11 @@ derbytools ${derby-jdbc.version} + + com.ibm.db2 + jcc + ${db2-jdbc.version} + com.microsoft.sqlserver mssql-jdbc diff --git a/core/deployment/src/main/java/io/quarkus/deployment/Feature.java b/core/deployment/src/main/java/io/quarkus/deployment/Feature.java index db95d5c78e9f3..d78efb58b7c0a 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/Feature.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/Feature.java @@ -37,6 +37,7 @@ public enum Feature { INFINISPAN_CLIENT, INFINISPAN_EMBEDDED, JAEGER, + JDBC_DB2, JDBC_DERBY, JDBC_H2, JDBC_POSTGRESQL, diff --git a/docs/src/main/asciidoc/datasource.adoc b/docs/src/main/asciidoc/datasource.adoc index 578c480759777..51c536ec7934b 100644 --- a/docs/src/main/asciidoc/datasource.adoc +++ b/docs/src/main/asciidoc/datasource.adoc @@ -42,7 +42,7 @@ If you want a better understanding of how all this works, this guide has a lot m === JDBC datasource -Add the `agroal` extension plus one of `jdbc-derby`, `jdbc-h2`, `jdbc-mariadb`, `jdbc-mssql`, `jdbc-mysql` or `jdbc-postgresql`. +Add the `agroal` extension plus one of `jdbc-db2`, `jdbc-derby`, `jdbc-h2`, `jdbc-mariadb`, `jdbc-mssql`, `jdbc-mysql`, or `jdbc-postgresql`. Then configure your datasource: @@ -89,7 +89,7 @@ The database kind defines which type of database you will connect to. We currently include these built-in database kinds: -* DB2: `db2` (reactive only) +* DB2: `db2` * Derby: `derby` * H2: `h2` * MariaDB: `mariadb` @@ -151,6 +151,7 @@ You will also need to choose, and add, the Quarkus extension for your relational Quarkus provides driver extensions for: +* DB2 - `jdbc-db2` * Derby - `jdbc-derby` * H2 - `jdbc-h2` * MariaDB - `jdbc-mariadb` @@ -203,6 +204,10 @@ When using one of the built-in datasource kinds, the JDBC driver is resolved aut |=== |Database kind |JDBC driver |XA driver +|`db2` +|`com.ibm.db2.jcc.DBDriver` +|`com.ibm.db2.jcc.DB2XADataSource` + |`derby` |`org.apache.derby.jdbc.ClientDriver` |`org.apache.derby.jdbc.ClientXADataSource` @@ -524,6 +529,14 @@ Defaults for the different parts are as follows: The https://jdbc.postgresql.org/documentation/head/connect.html[official documentation] go into more detail and list optional parameters as well. +=== DB2 + +`jdbc:db2://[:]/[:=;[=;]]` + +Example:: `jdbc:db2://localhost:50000/MYDB:user=dbadm;password=dbadm;` + +See the https://www.ibm.com/support/knowledgecenter/SSEPGG_11.5.0/com.ibm.db2.luw.apdv.java.doc/src/tpc/imjcc_r0052342.html[official documentation] for more detail on URL syntax and additional supported options. + === MariaDB `jdbc:mariadb:[replication:|failover:|sequential:|aurora:]//[,...]/[database][?=[&=]]` diff --git a/docs/src/main/asciidoc/hibernate-orm.adoc b/docs/src/main/asciidoc/hibernate-orm.adoc index 8f006f109a8f5..a21f9961170cc 100644 --- a/docs/src/main/asciidoc/hibernate-orm.adoc +++ b/docs/src/main/asciidoc/hibernate-orm.adoc @@ -29,6 +29,7 @@ Add the following dependencies to your project: * the Hibernate ORM extension: `io.quarkus:quarkus-hibernate-orm` * your JDBC driver extension; the following options are available: + - `quarkus-jdbc-db2` for link:https://www.ibm.com/products/db2-database[IBM DB2] - `quarkus-jdbc-derby` for link:https://db.apache.org/derby/[Apache Derby] - `quarkus-jdbc-h2` for link:https://www.h2database.com/html/main.html[H2] - `quarkus-jdbc-mariadb` for link:https://mariadb.com/[MariaDB] diff --git a/extensions/jdbc/jdbc-db2/deployment/pom.xml b/extensions/jdbc/jdbc-db2/deployment/pom.xml new file mode 100644 index 0000000000000..9bfe433e2ca74 --- /dev/null +++ b/extensions/jdbc/jdbc-db2/deployment/pom.xml @@ -0,0 +1,50 @@ + + + + quarkus-jdbc-db2-parent + io.quarkus + 999-SNAPSHOT + + 4.0.0 + + quarkus-jdbc-db2-deployment + Quarkus - JDBC - DB2 - Deployment + + + + io.quarkus + quarkus-core-deployment + + + io.quarkus + quarkus-arc-deployment + + + io.quarkus + quarkus-agroal-spi + + + io.quarkus + quarkus-jdbc-db2 + + + + + + + maven-compiler-plugin + + + + io.quarkus + quarkus-extension-processor + ${project.version} + + + + + + + diff --git a/extensions/jdbc/jdbc-db2/deployment/src/main/java/io/quarkus/jdbc/db2/deployment/JDBCDB2Processor.java b/extensions/jdbc/jdbc-db2/deployment/src/main/java/io/quarkus/jdbc/db2/deployment/JDBCDB2Processor.java new file mode 100644 index 0000000000000..6d75ad8c51242 --- /dev/null +++ b/extensions/jdbc/jdbc-db2/deployment/src/main/java/io/quarkus/jdbc/db2/deployment/JDBCDB2Processor.java @@ -0,0 +1,59 @@ +package io.quarkus.jdbc.db2.deployment; + +import io.quarkus.agroal.deployment.JdbcDriverBuildItem; +import io.quarkus.arc.deployment.AdditionalBeanBuildItem; +import io.quarkus.arc.processor.BuiltinScope; +import io.quarkus.datasource.common.runtime.DatabaseKind; +import io.quarkus.deployment.Capabilities; +import io.quarkus.deployment.Capability; +import io.quarkus.deployment.Feature; +import io.quarkus.deployment.annotations.BuildProducer; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.builditem.FeatureBuildItem; +import io.quarkus.deployment.builditem.NativeImageEnableAllCharsetsBuildItem; +import io.quarkus.deployment.builditem.SslNativeConfigBuildItem; +import io.quarkus.deployment.builditem.nativeimage.NativeImageConfigBuildItem; +import io.quarkus.jdbc.db2.runtime.DB2AgroalConnectionConfigurer; + +public class JDBCDB2Processor { + + @BuildStep + FeatureBuildItem feature() { + return new FeatureBuildItem(Feature.JDBC_DB2); + } + + @BuildStep + void registerDriver(BuildProducer jdbcDriver, + SslNativeConfigBuildItem sslNativeConfigBuildItem) { + jdbcDriver.produce(new JdbcDriverBuildItem(DatabaseKind.DB2, "com.ibm.db2.jcc.DB2Driver", + "com.ibm.db2.jcc.DB2XADataSource")); + } + + @BuildStep + void configureAgroalConnection(BuildProducer additionalBeans, + Capabilities capabilities) { + if (capabilities.isPresent(Capability.AGROAL)) { + additionalBeans + .produce(new AdditionalBeanBuildItem.Builder().addBeanClass(DB2AgroalConnectionConfigurer.class) + .setDefaultScope(BuiltinScope.APPLICATION.getName()) + .setUnremovable() + .build()); + } + } + + @BuildStep + NativeImageConfigBuildItem build() { + // The DB2 JDBC driver has been updated with conditional checks for the + // "QuarkusWithJcc" system property which will no-op some code paths that + // are not needed for T4 JDBC usage and are incompatible with native mode + return NativeImageConfigBuildItem.builder() + .addNativeImageSystemProperty("QuarkusWithJcc", "true") + .build(); + } + + @BuildStep + NativeImageEnableAllCharsetsBuildItem enableAllCharsets() { + // When connecting to DB2 on z/OS the Cp037 charset is required + return new NativeImageEnableAllCharsetsBuildItem(); + } +} diff --git a/extensions/jdbc/jdbc-db2/pom.xml b/extensions/jdbc/jdbc-db2/pom.xml new file mode 100644 index 0000000000000..6006e86aa6aae --- /dev/null +++ b/extensions/jdbc/jdbc-db2/pom.xml @@ -0,0 +1,21 @@ + + + + quarkus-jdbc-parent + io.quarkus + 999-SNAPSHOT + + 4.0.0 + + quarkus-jdbc-db2-parent + Quarkus - JDBC - DB2 + pom + + deployment + runtime + + + + diff --git a/extensions/jdbc/jdbc-db2/runtime/pom.xml b/extensions/jdbc/jdbc-db2/runtime/pom.xml new file mode 100644 index 0000000000000..c3f92096be0df --- /dev/null +++ b/extensions/jdbc/jdbc-db2/runtime/pom.xml @@ -0,0 +1,56 @@ + + + + quarkus-jdbc-db2-parent + io.quarkus + 999-SNAPSHOT + + 4.0.0 + + quarkus-jdbc-db2 + Quarkus - JDBC - DB2 - Runtime + Connect to the DB2 database via JDBC + + + + com.ibm.db2 + jcc + + + io.quarkus + quarkus-core + + + io.quarkus + quarkus-agroal + true + + + org.graalvm.nativeimage + svm + + + + + + + io.quarkus + quarkus-bootstrap-maven-plugin + + + maven-compiler-plugin + + + + io.quarkus + quarkus-extension-processor + ${project.version} + + + + + + + diff --git a/extensions/jdbc/jdbc-db2/runtime/src/main/java/io/quarkus/jdbc/db2/runtime/DB2AgroalConnectionConfigurer.java b/extensions/jdbc/jdbc-db2/runtime/src/main/java/io/quarkus/jdbc/db2/runtime/DB2AgroalConnectionConfigurer.java new file mode 100644 index 0000000000000..3939d6d46e8b7 --- /dev/null +++ b/extensions/jdbc/jdbc-db2/runtime/src/main/java/io/quarkus/jdbc/db2/runtime/DB2AgroalConnectionConfigurer.java @@ -0,0 +1,9 @@ +package io.quarkus.jdbc.db2.runtime; + +import io.quarkus.agroal.runtime.AgroalConnectionConfigurer; +import io.quarkus.agroal.runtime.JdbcDriver; +import io.quarkus.datasource.common.runtime.DatabaseKind; + +@JdbcDriver(DatabaseKind.DB2) +public class DB2AgroalConnectionConfigurer implements AgroalConnectionConfigurer { +} diff --git a/extensions/jdbc/jdbc-db2/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/jdbc/jdbc-db2/runtime/src/main/resources/META-INF/quarkus-extension.yaml new file mode 100644 index 0000000000000..a3fa12e7954cd --- /dev/null +++ b/extensions/jdbc/jdbc-db2/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -0,0 +1,9 @@ +--- +name: "JDBC Driver - DB2" +metadata: + keywords: + - "jdbc-db2" + - "jdbc" + - "db2" + categories: + - "data" diff --git a/extensions/jdbc/pom.xml b/extensions/jdbc/pom.xml index daa20c372a228..a9e4512de15b5 100644 --- a/extensions/jdbc/pom.xml +++ b/extensions/jdbc/pom.xml @@ -15,6 +15,7 @@ pom jdbc-postgresql + jdbc-db2 jdbc-derby jdbc-h2 jdbc-mariadb diff --git a/integration-tests/jpa-db2/README.md b/integration-tests/jpa-db2/README.md new file mode 100644 index 0000000000000..0f9ae1f5799db --- /dev/null +++ b/integration-tests/jpa-db2/README.md @@ -0,0 +1,40 @@ +# JPA example with DB2 + +## Running the tests + +By default, the tests of this module are disabled. + +To run the tests in a standard JVM with DB2 started as a Docker container, you can run the following command: + +``` +mvn verify -Dtest-db2 -Ddocker +``` + +Additionally, you can generate a native image and run the tests for this native image by adding `-Dnative`: + +``` +mvn verify -Dtest-db2 -Ddocker -Dnative +``` + +## To manually run an equivalent DB2 container instead of through Testcontainers, do the following: + +1. Start DB2 in a container + +``` +docker run \ + -e DBNAME=hreact \ + -e DB2INSTANCE=hreact \ + -e DB2INST1_PASSWORD=hreact \ + -e AUTOCONFIG=false \ + -e ARCHIVE_LOGS=false \ + -e LICENSE=accept \ + -p 50000:50000 \ + --privileged \ + ibmcom/db2:11.5.0.0a +``` + +2. Run the test, specifying the JDBC URL for the container you started in the previous step + +``` +mvn verify -Dtest-db2 -Djdbc-db2.url=jdbc:db2://localhost:50000/hreact +``` diff --git a/integration-tests/jpa-db2/pom.xml b/integration-tests/jpa-db2/pom.xml new file mode 100644 index 0000000000000..11547c09c547c --- /dev/null +++ b/integration-tests/jpa-db2/pom.xml @@ -0,0 +1,247 @@ + + + + quarkus-integration-tests-parent + io.quarkus + 999-SNAPSHOT + ../ + + 4.0.0 + + quarkus-integration-test-jpa-db2 + Quarkus - Integration Tests - JPA - DB2 + Module that contains JPA related tests running with the DB2 database + + + jdbc:db2://localhost:50000/hreact + ibmcom/db2:11.5.0.0a + + + + + io.quarkus + quarkus-undertow + + + io.quarkus + quarkus-hibernate-orm + + + io.quarkus + quarkus-jdbc-db2 + + + + io.quarkus + quarkus-junit5 + test + + + io.rest-assured + rest-assured + test + + + + + + + src/main/resources + true + + + + + maven-surefire-plugin + + true + + + + maven-failsafe-plugin + + true + + + + io.quarkus + quarkus-maven-plugin + + + + build + + + + + + + + + + test-db2 + + + test-db2 + + + + + + maven-surefire-plugin + + false + + + + maven-failsafe-plugin + + false + + + + + + + + native-image + + + native + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + integration-test + verify + + + + + ${project.build.directory}/${project.build.finalName}-runner + + + + + + + + io.quarkus + quarkus-maven-plugin + + + native-image + + native-image + + + true + true + ${graalvmHome} + + + + + + + + + + docker-db2 + + + docker + + + + jdbc:db2://localhost:50005/hreact + + + + + io.fabric8 + docker-maven-plugin + + + + ${db2.image} + quarkus-test-db2 + + + bridge + + true + + 50005:50000 + + + hreact + hreact + hreact + accept + + false + false + + + DB2: + default + cyan + + + + .*Setup has completed\..* + + + + + + + + + + docker-start + compile + + stop + start + + + + docker-stop + post-integration-test + + stop + + + + + + org.codehaus.mojo + exec-maven-plugin + + + docker-prune + generate-resources + + exec + + + ${basedir}/../../.github/docker-prune.sh + + + + + + + + + diff --git a/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/Address.java b/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/Address.java new file mode 100644 index 0000000000000..a473d1cb87767 --- /dev/null +++ b/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/Address.java @@ -0,0 +1,42 @@ +package io.quarkus.it.jpa.db2; + +import javax.persistence.Embeddable; + +/** + * This is an enmarked @Embeddable class. + * Let's see if just being referenced by the main entity is enough to be detected. + * + * @author Emmanuel Bernard emmanuel@hibernate.org + */ +//FIXME : this used to be non-annotated explicitly for testing purposes +// added the annotation as it's illegal according to the ORM metadata validation +@Embeddable +public class Address { + private String street1; + private String street2; + private String zipCode; + + public String getStreet1() { + return street1; + } + + public void setStreet1(String street1) { + this.street1 = street1; + } + + public String getStreet2() { + return street2; + } + + public void setStreet2(String street2) { + this.street2 = street2; + } + + public String getZipCode() { + return zipCode; + } + + public void setZipCode(String zipCode) { + this.zipCode = zipCode; + } +} diff --git a/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/Animal.java b/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/Animal.java new file mode 100644 index 0000000000000..c02474d45c22e --- /dev/null +++ b/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/Animal.java @@ -0,0 +1,16 @@ +package io.quarkus.it.jpa.db2; + +/** + * @author Emmanuel Bernard emmanuel@hibernate.org + */ +public class Animal { + private double weight; + + public double getWeight() { + return weight; + } + + public void setWeight(double weight) { + this.weight = weight; + } +} diff --git a/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/Customer.java b/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/Customer.java new file mode 100644 index 0000000000000..b0ebf79488a49 --- /dev/null +++ b/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/Customer.java @@ -0,0 +1,48 @@ +package io.quarkus.it.jpa.db2; + +import javax.persistence.Embedded; +import javax.persistence.Entity; +import javax.persistence.Id; + +/** + * Used to test reflection references for JPA + * + * @author Emmanuel Bernard emmanuel@hibernate.org + */ +@Entity +public class Customer extends Human { + @Id + // no getter explicitly to test field only reflective access + private Long id; + + private Address address; + private WorkAddress workAddress; + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + // Address is referenced but not marked as @Embeddable + @Embedded + public Address getAddress() { + return address; + } + + public WorkAddress getWorkAddress() { + return workAddress; + } + + public void setWorkAddress(WorkAddress workAddress) { + this.workAddress = workAddress; + } + + public void setAddress(Address address) { + this.address = address; + } +} diff --git a/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/Human.java b/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/Human.java new file mode 100644 index 0000000000000..dddb023b353cc --- /dev/null +++ b/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/Human.java @@ -0,0 +1,21 @@ +package io.quarkus.it.jpa.db2; + +import javax.persistence.MappedSuperclass; + +/** + * Mapped superclass test + * + * @author Emmanuel Bernard emmanuel@hibernate.org + */ +@MappedSuperclass +public class Human extends Animal { + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/JPAFunctionalityTestEndpoint.java b/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/JPAFunctionalityTestEndpoint.java new file mode 100644 index 0000000000000..0169577b8fbb8 --- /dev/null +++ b/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/JPAFunctionalityTestEndpoint.java @@ -0,0 +1,158 @@ +package io.quarkus.it.jpa.db2; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.List; +import java.util.UUID; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.EntityTransaction; +import javax.persistence.PersistenceUnit; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Various tests covering JPA functionality. All tests should work in both standard JVM and native mode. + */ +@SuppressWarnings("serial") +@WebServlet(name = "JPATestBootstrapEndpoint", urlPatterns = "/jpa/testfunctionality") +public class JPAFunctionalityTestEndpoint extends HttpServlet { + + @PersistenceUnit(unitName = "templatePU") + EntityManagerFactory entityManagerFactory; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + try { + doStuffWithHibernate(entityManagerFactory); + } catch (Exception e) { + reportException("An error occurred while performing Hibernate operations", e, resp); + } + resp.getWriter().write("OK"); + } + + /** + * Lists the various operations we want to test for: + */ + private static void doStuffWithHibernate(EntityManagerFactory entityManagerFactory) { + + //Cleanup any existing data: + deleteAllPerson(entityManagerFactory); + + //Store some well known Person instances we can then test on: + storeTestPersons(entityManagerFactory); + + //Load all persons and run some checks on the query results: + verifyListOfExistingPersons(entityManagerFactory); + + //Try a JPA named query: + verifyJPANamedQuery(entityManagerFactory); + + deleteAllPerson(entityManagerFactory); + + } + + private static void verifyJPANamedQuery(final EntityManagerFactory emf) { + EntityManager em = emf.createEntityManager(); + EntityTransaction transaction = em.getTransaction(); + transaction.begin(); + TypedQuery typedQuery = em.createNamedQuery( + "get_person_by_name", Person.class); + typedQuery.setParameter("name", "Quarkus"); + final Person singleResult = typedQuery.getSingleResult(); + + if (!singleResult.getName().equals("Quarkus")) { + throw new RuntimeException("Wrong result from named JPA query"); + } + + transaction.commit(); + em.close(); + } + + private static void verifyListOfExistingPersons(final EntityManagerFactory emf) { + EntityManager em = emf.createEntityManager(); + EntityTransaction transaction = em.getTransaction(); + transaction.begin(); + listExistingPersons(em); + transaction.commit(); + em.close(); + } + + private static void storeTestPersons(final EntityManagerFactory emf) { + EntityManager em = emf.createEntityManager(); + EntityTransaction transaction = em.getTransaction(); + transaction.begin(); + persistNewPerson(em, "Gizmo"); + persistNewPerson(em, "Quarkus"); + persistNewPerson(em, "Hibernate ORM"); + transaction.commit(); + em.close(); + } + + private static void deleteAllPerson(final EntityManagerFactory emf) { + EntityManager em = emf.createEntityManager(); + EntityTransaction transaction = em.getTransaction(); + transaction.begin(); + em.createNativeQuery("Delete from Person").executeUpdate(); + transaction.commit(); + em.close(); + } + + private static void listExistingPersons(EntityManager em) { + CriteriaBuilder cb = em.getCriteriaBuilder(); + + CriteriaQuery cq = cb.createQuery(Person.class); + Root from = cq.from(Person.class); + cq.select(from).orderBy(cb.asc(from.get("name"))); + TypedQuery q = em.createQuery(cq); + List allpersons = q.getResultList(); + if (allpersons.size() != 3) { + throw new RuntimeException("Incorrect number of results"); + } + if (!allpersons.get(0).getName().equals("Gizmo")) { + throw new RuntimeException("Incorrect order of results"); + } + StringBuilder sb = new StringBuilder("list of stored Person names:\n\t"); + for (Person p : allpersons) { + p.describeFully(sb); + sb.append("\n\t"); + if (p.getStatus() != Status.LIVING) { + throw new RuntimeException("Incorrect status " + p); + } + } + sb.append("\nList complete.\n"); + System.out.print(sb); + } + + private static void persistNewPerson(EntityManager entityManager, String name) { + Person person = new Person(); + person.setName(name); + person.setStatus(Status.LIVING); + person.setAddress(new SequencedAddress("Street " + randomName())); + entityManager.persist(person); + } + + private static String randomName() { + return UUID.randomUUID().toString(); + } + + private void reportException(String errorMessage, final Exception e, final HttpServletResponse resp) throws IOException { + final PrintWriter writer = resp.getWriter(); + if (errorMessage != null) { + writer.write(errorMessage); + writer.write(" "); + } + writer.write(e.toString()); + writer.append("\n\t"); + e.printStackTrace(writer); + writer.append("\n\t"); + } + +} diff --git a/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/NotAnEntityNotReferenced.java b/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/NotAnEntityNotReferenced.java new file mode 100644 index 0000000000000..2eb63793a824b --- /dev/null +++ b/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/NotAnEntityNotReferenced.java @@ -0,0 +1,11 @@ +package io.quarkus.it.jpa.db2; + +/** + * Should not be referenced by the code + * So be dead code eliminated. + * Used to test that entities get referenced but not non entities + * + * @author Emmanuel Bernard emmanuel@hibernate.org + */ +public class NotAnEntityNotReferenced { +} diff --git a/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/Person.java b/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/Person.java new file mode 100644 index 0000000000000..340ee10a5edbc --- /dev/null +++ b/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/Person.java @@ -0,0 +1,71 @@ +package io.quarkus.it.jpa.db2; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.NamedQuery; + +@Entity +@NamedQuery(name = "get_person_by_name", query = "select p from Person p where name = :name") +public class Person { + + private long id; + private String name; + private SequencedAddress address; + private Status status; + + public Person() { + } + + public Person(long id, String name, SequencedAddress address) { + this.id = id; + this.name = name; + this.address = address; + } + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "personSeq") + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) + public SequencedAddress getAddress() { + return address; + } + + public void setAddress(SequencedAddress address) { + this.address = address; + } + + public Status getStatus() { + return status; + } + + public void setStatus(Status status) { + this.status = status; + } + + public void describeFully(StringBuilder sb) { + sb.append("Person with id=").append(id).append(", name='").append(name).append("', status='").append(status) + .append("', address { "); + getAddress().describeFully(sb); + sb.append(" }"); + } +} diff --git a/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/SequencedAddress.java b/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/SequencedAddress.java new file mode 100644 index 0000000000000..73037d41250ae --- /dev/null +++ b/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/SequencedAddress.java @@ -0,0 +1,42 @@ +package io.quarkus.it.jpa.db2; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +public class SequencedAddress { + + private long id; + private String street; + + public SequencedAddress() { + } + + public SequencedAddress(String street) { + this.street = street; + } + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "addressSeq") + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getStreet() { + return street; + } + + public void setStreet(String name) { + this.street = name; + } + + public void describeFully(StringBuilder sb) { + sb.append("Address with id=").append(id).append(", street='").append(street).append("'"); + } +} diff --git a/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/Status.java b/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/Status.java new file mode 100644 index 0000000000000..973807a1ea2df --- /dev/null +++ b/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/Status.java @@ -0,0 +1,6 @@ +package io.quarkus.it.jpa.db2; + +public enum Status { + LIVING, + DECEASED +} diff --git a/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/WorkAddress.java b/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/WorkAddress.java new file mode 100644 index 0000000000000..dadea80c1a306 --- /dev/null +++ b/integration-tests/jpa-db2/src/main/java/io/quarkus/it/jpa/db2/WorkAddress.java @@ -0,0 +1,21 @@ +package io.quarkus.it.jpa.db2; + +import javax.persistence.Embeddable; + +/** + * Class marked @Embeddable explicitly so it is picked up. + * + * @author Emmanuel Bernard emmanuel@hibernate.org + */ +@Embeddable +public class WorkAddress { + private String company; + + public String getCompany() { + return company; + } + + public void setCompany(String company) { + this.company = company; + } +} diff --git a/integration-tests/jpa-db2/src/main/resources/META-INF/persistence.xml b/integration-tests/jpa-db2/src/main/resources/META-INF/persistence.xml new file mode 100644 index 0000000000000..1d067ecc6ba8d --- /dev/null +++ b/integration-tests/jpa-db2/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,23 @@ + + + + + Hibernate test case template Persistence Unit + + + + + + + + + + + diff --git a/integration-tests/jpa-db2/src/main/resources/application.properties b/integration-tests/jpa-db2/src/main/resources/application.properties new file mode 100644 index 0000000000000..fe498c6bed1ee --- /dev/null +++ b/integration-tests/jpa-db2/src/main/resources/application.properties @@ -0,0 +1,4 @@ +quarkus.datasource.db-kind=db2 +quarkus.datasource.username=hreact +quarkus.datasource.password=hreact +quarkus.datasource.jdbc.url=${jdbc-db2.url} \ No newline at end of file diff --git a/integration-tests/jpa-db2/src/test/java/io/quarkus/it/jpa/db2/JPAFunctionalityInGraalITCase.java b/integration-tests/jpa-db2/src/test/java/io/quarkus/it/jpa/db2/JPAFunctionalityInGraalITCase.java new file mode 100644 index 0000000000000..a4913879e667a --- /dev/null +++ b/integration-tests/jpa-db2/src/test/java/io/quarkus/it/jpa/db2/JPAFunctionalityInGraalITCase.java @@ -0,0 +1,7 @@ +package io.quarkus.it.jpa.db2; + +import io.quarkus.test.junit.NativeImageTest; + +@NativeImageTest +public class JPAFunctionalityInGraalITCase extends JPAFunctionalityTest { +} diff --git a/integration-tests/jpa-db2/src/test/java/io/quarkus/it/jpa/db2/JPAFunctionalityTest.java b/integration-tests/jpa-db2/src/test/java/io/quarkus/it/jpa/db2/JPAFunctionalityTest.java new file mode 100644 index 0000000000000..9f9cdb68458fc --- /dev/null +++ b/integration-tests/jpa-db2/src/test/java/io/quarkus/it/jpa/db2/JPAFunctionalityTest.java @@ -0,0 +1,18 @@ +package io.quarkus.it.jpa.db2; + +import static org.hamcrest.Matchers.is; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; +import io.restassured.RestAssured; + +@QuarkusTest +public class JPAFunctionalityTest { + + @Test + public void testJPAFunctionalityFromServlet() throws Exception { + RestAssured.when().get("/jpa/testfunctionality").then().body(is("OK")); + } + +} diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index f0258f4b69c73..b75beeadde35b 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -34,6 +34,7 @@ kafka kafka-streams jpa + jpa-db2 jpa-derby jpa-postgresql vault