diff --git a/examples/jpa-strict/pom.xml b/examples/jpa-strict/pom.xml
new file mode 100644
index 000000000..08e308bdf
--- /dev/null
+++ b/examples/jpa-strict/pom.xml
@@ -0,0 +1,173 @@
+
+
+
+ shamrock-examples-parent
+ org.jboss.shamrock
+ 1.0.0.Alpha1-SNAPSHOT
+ ../
+
+ 4.0.0
+
+ shamrock-strict-jpa-example
+ An example that only contains JPA related tests running in strict mode
+
+
+ org.jboss.shamrock
+ shamrock-jaxrs-deployment
+ provided
+
+
+ org.jboss.shamrock
+ shamrock-jpa-deployment
+ provided
+
+
+ org.postgresql
+ postgresql-protean
+ 42.2.5-SNAPSHOT
+
+
+
+
+ org.jboss.shamrock
+ shamrock-junit
+ test
+
+
+ org.jboss.shamrock
+ shamrock-graal
+ test
+
+
+ org.glassfish
+ javax.json
+ test
+
+
+
+
+
+
+ ${project.groupId}
+ shamrock-maven-plugin
+ ${project.version}
+
+
+
+ build
+
+
+
+
+
+ io.fabric8
+ docker-maven-plugin
+ 0.26.1
+
+
+
+ postgres:10.5
+ postgresql
+
+
+ hibernate_orm_test
+ hibernate_orm_test
+ hibernate_orm_test
+
+
+ 5432:5432
+
+
+
+ mapped
+
+ 5432
+
+
+
+
+
+
+
+
+
+
+ docker-start
+ compile
+
+ stop
+ start
+
+
+
+ docker-stop
+ post-integration-test
+
+ stop
+
+
+
+
+
+
+
+
+
+ native-image
+
+
+ !no-native
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+
+
+
+ integration-test
+ verify
+
+
+
+ ${project.build.directory}/${project.build.finalName}-runner
+
+
+
+
+
+
+ ${project.groupId}
+ shamrock-maven-plugin
+ ${project.version}
+
+
+ native-image
+
+ native-image
+
+
+ false
+ true
+ true
+
+ ${graalvmHome}
+ false
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/MainMethod.java b/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/MainMethod.java
new file mode 100644
index 000000000..f5d63cfc6
--- /dev/null
+++ b/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/MainMethod.java
@@ -0,0 +1,9 @@
+package org.jboss.shamrock.example;
+
+public class MainMethod {
+
+ public static void main(String... args) throws Exception {
+ Class.forName("org.jboss.shamrock.runtime.RuntimeRunner");
+ }
+
+}
diff --git a/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/Address.java b/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/Address.java
new file mode 100644
index 000000000..523980d99
--- /dev/null
+++ b/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/Address.java
@@ -0,0 +1,42 @@
+package org.jboss.shamrock.example.jpa;
+
+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/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/Animal.java b/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/Animal.java
new file mode 100644
index 000000000..405c85b0a
--- /dev/null
+++ b/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/Animal.java
@@ -0,0 +1,16 @@
+package org.jboss.shamrock.example.jpa;
+
+/**
+ * @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/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/Customer.java b/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/Customer.java
new file mode 100644
index 000000000..943d1e153
--- /dev/null
+++ b/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/Customer.java
@@ -0,0 +1,48 @@
+package org.jboss.shamrock.example.jpa;
+
+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/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/Human.java b/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/Human.java
new file mode 100644
index 000000000..487af53d5
--- /dev/null
+++ b/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/Human.java
@@ -0,0 +1,21 @@
+package org.jboss.shamrock.example.jpa;
+
+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/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/JPATestBootstrapEndpoint.java b/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/JPATestBootstrapEndpoint.java
new file mode 100644
index 000000000..e9f80dc6d
--- /dev/null
+++ b/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/JPATestBootstrapEndpoint.java
@@ -0,0 +1,103 @@
+package org.jboss.shamrock.example.jpa;
+
+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.Persistence;
+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 for the JPA integration. WARNING: these tests will ONLY pass in Substrate, as it also verifies
+ * reflection non-functionality.
+ */
+@WebServlet(name = "JPATestBootstrapEndpoint", urlPatterns = "/jpa/testbootstrap")
+public class JPATestBootstrapEndpoint extends HttpServlet {
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ try {
+ testStoreLoadOnJPA();
+ } catch (Exception e) {
+ reportException("Oops, shit happened, No boot for you!", e, resp);
+ }
+
+ resp.getWriter().write("OK");
+ }
+
+ public void testStoreLoadOnJPA() throws Exception {
+ EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("templatePU");
+ System.out.println("Hibernate EntityManagerFactory: booted");
+
+ doStuffWithHibernate(entityManagerFactory);
+
+ entityManagerFactory.close();
+ System.out.println("Hibernate EntityManagerFactory: shut down");
+
+ }
+
+ private static void doStuffWithHibernate(EntityManagerFactory entityManagerFactory) {
+ EntityManager em = entityManagerFactory.createEntityManager();
+ EntityTransaction transaction = em.getTransaction();
+ transaction.begin();
+
+ persistNewPerson(em);
+
+ listExistingPersons(em);
+
+ 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);
+ TypedQuery q = em.createQuery(cq);
+ List allpersons = q.getResultList();
+ StringBuilder sb = new StringBuilder("list of stored Person names:\n\t");
+ for (Person p : allpersons) {
+ p.describeFully(sb);
+ sb.append("\n\t");
+ }
+ sb.append("\nList complete.\n");
+ System.out.print(sb);
+ }
+
+ private static void persistNewPerson(EntityManager entityManager) {
+ Person person = new Person();
+ person.setName(randomName());
+ 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/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/JPATestReflectionEndpoint.java b/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/JPATestReflectionEndpoint.java
new file mode 100644
index 000000000..2ee3bd85d
--- /dev/null
+++ b/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/JPATestReflectionEndpoint.java
@@ -0,0 +1,138 @@
+package org.jboss.shamrock.example.jpa;
+
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * Various tests for the JPA integration.
+ * WARNING: these tests will ONLY pass in Substrate, as it also verifies reflection non-functionality.
+ */
+@WebServlet(name = "JPATestReflectionEndpoint", urlPatterns = "/jpa/testreflection")
+public class JPATestReflectionEndpoint extends HttpServlet {
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ makeSureNonEntityAreDCE(resp);
+ makeSureEntitiesAreAccessibleViaReflection(resp);
+ makeSureNonAnnotatedEmbeddableAreAccessibleViaReflection(resp);
+ makeSureAnnotatedEmbeddableAreAccessibleViaReflection(resp);
+ makeSureClassAreAccessibleViaReflection("org.jboss.shamrock.example.jpa.Human", "Unable to enlist @MappedSuperclass", resp);
+ makeSureClassAreAccessibleViaReflection("org.jboss.shamrock.example.jpa.Animal", "Unable to enlist entity superclass", resp);
+ resp.getWriter().write("OK");
+ }
+
+ private void makeSureClassAreAccessibleViaReflection(String className, String errorMessage, HttpServletResponse resp) throws IOException {
+ try {
+ className = getTrickedClassName(className);
+
+ Class> custClass = Class.forName(className);
+ Object instance = custClass.newInstance();
+ }
+ catch (Exception e) {
+ reportException(errorMessage, e, resp);
+ }
+ }
+
+ private void makeSureEntitiesAreAccessibleViaReflection(HttpServletResponse resp) throws IOException {
+ try {
+ String className = getTrickedClassName(org.jboss.shamrock.example.jpa.Customer.class.getName());
+
+ Class> custClass = Class.forName(className);
+ Object instance = custClass.newInstance();
+ Field id = custClass.getDeclaredField("id");
+ id.setAccessible(true);
+ if (id.get(instance) != null) {
+ resp.getWriter().write("id should be reachable and null");
+ }
+ Method setter = custClass.getDeclaredMethod("setName", String.class);
+ Method getter = custClass.getDeclaredMethod("getName");
+ setter.invoke(instance, "Emmanuel");
+ if (! "Emmanuel".equals(getter.invoke(instance))) {
+ resp.getWriter().write("getter / setter should be reachable and usable");
+ }
+ }
+ catch (Exception e) {
+ reportException(e, resp);
+ }
+ }
+
+ private void makeSureAnnotatedEmbeddableAreAccessibleViaReflection(HttpServletResponse resp) throws IOException {
+ try {
+ String className = getTrickedClassName(org.jboss.shamrock.example.jpa.WorkAddress.class.getName());
+
+ Class> custClass = Class.forName(className);
+ Object instance = custClass.newInstance();
+ Method setter = custClass.getDeclaredMethod("setCompany", String.class);
+ Method getter = custClass.getDeclaredMethod("getCompany");
+ setter.invoke(instance, "Red Hat");
+ if (! "Red Hat".equals(getter.invoke(instance))) {
+ resp.getWriter().write("@Embeddable embeddable should be reachable and usable");
+ }
+ }
+ catch (Exception e) {
+ reportException(e, resp);
+ }
+ }
+ private void makeSureNonAnnotatedEmbeddableAreAccessibleViaReflection(HttpServletResponse resp) throws IOException {
+ try {
+ String className = getTrickedClassName(org.jboss.shamrock.example.jpa.Address.class.getName());
+
+ Class> custClass = Class.forName(className);
+ Object instance = custClass.newInstance();
+ Method setter = custClass.getDeclaredMethod("setStreet1", String.class);
+ Method getter = custClass.getDeclaredMethod("getStreet1");
+ setter.invoke(instance, "1 rue du General Leclerc");
+ if (! "1 rue du General Leclerc".equals(getter.invoke(instance))) {
+ resp.getWriter().write("Non @Embeddable embeddable getter / setter should be reachable and usable");
+ }
+ }
+ catch (Exception e) {
+ reportException(e, resp);
+ }
+ }
+
+ private void makeSureNonEntityAreDCE(HttpServletResponse resp) {
+ try {
+ String className = getTrickedClassName(org.jboss.shamrock.example.jpa.NotAnEntityNotReferenced.class.getName());
+
+ Class> custClass = Class.forName(className);
+ resp.getWriter().write("Should not be able to find a non referenced non entity class");
+ Object instance = custClass.newInstance();
+ }
+ catch (Exception e) {
+ // Expected outcome
+ }
+ }
+
+ /**
+ * Trick SubstrateVM not to detect a simple use of Class.forname
+ */
+ private String getTrickedClassName(String className) {
+ className = className + " ITrickYou";
+ className = className.subSequence(0, className.indexOf(' ')).toString();
+ return className;
+ }
+
+ private void reportException(final Exception e, final HttpServletResponse resp) throws IOException {
+ reportException(null, e, resp);
+ }
+
+ 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/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/NotAnEntityNotReferenced.java b/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/NotAnEntityNotReferenced.java
new file mode 100644
index 000000000..f918171bd
--- /dev/null
+++ b/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/NotAnEntityNotReferenced.java
@@ -0,0 +1,11 @@
+package org.jboss.shamrock.example.jpa;
+
+/**
+ * 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/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/Person.java b/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/Person.java
new file mode 100644
index 000000000..3af490f65
--- /dev/null
+++ b/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/Person.java
@@ -0,0 +1,58 @@
+package org.jboss.shamrock.example.jpa;
+
+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;
+
+@Entity
+public class Person {
+
+ private long id;
+ private String name;
+ private SequencedAddress address;
+
+ 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 void describeFully(StringBuilder sb) {
+ sb.append( "Person with id=" ).append( id ).append( ", name='" ).append( name ).append( "', address { " );
+ getAddress().describeFully( sb );
+ sb.append( " }" );
+ }
+}
diff --git a/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/SequencedAddress.java b/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/SequencedAddress.java
new file mode 100644
index 000000000..101b263b0
--- /dev/null
+++ b/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/SequencedAddress.java
@@ -0,0 +1,41 @@
+package org.jboss.shamrock.example.jpa;
+
+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/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/WorkAddress.java b/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/WorkAddress.java
new file mode 100644
index 000000000..2a2c37e0b
--- /dev/null
+++ b/examples/jpa-strict/src/main/java/org/jboss/shamrock/example/jpa/WorkAddress.java
@@ -0,0 +1,21 @@
+package org.jboss.shamrock.example.jpa;
+
+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/examples/jpa-strict/src/main/resources/META-INF/persistence.xml b/examples/jpa-strict/src/main/resources/META-INF/persistence.xml
new file mode 100644
index 000000000..7ba2efca3
--- /dev/null
+++ b/examples/jpa-strict/src/main/resources/META-INF/persistence.xml
@@ -0,0 +1,37 @@
+
+
+
+
+ Hibernate test case template Persistence Unit
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jpa-strict/src/test/java/org/jboss/shamrock/example/test/JPABootstrapInGraalITCase.java b/examples/jpa-strict/src/test/java/org/jboss/shamrock/example/test/JPABootstrapInGraalITCase.java
new file mode 100644
index 000000000..185ebdfdb
--- /dev/null
+++ b/examples/jpa-strict/src/test/java/org/jboss/shamrock/example/test/JPABootstrapInGraalITCase.java
@@ -0,0 +1,23 @@
+package org.jboss.shamrock.example.test;
+
+import org.jboss.shamrock.example.testutils.URLTester;
+import org.jboss.shamrock.junit.GraalTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test reflection around JPA entities
+ *
+ * @author Emmanuel Bernard emmanuel@hibernate.org
+ */
+@RunWith(GraalTest.class)
+public class JPABootstrapInGraalITCase {
+
+ @Test
+ public void testFieldAndGetterReflectionOnEntityFromServlet() throws Exception {
+ assertEquals("OK", URLTester.relative("jpa/testbootstrap").invokeURL().asString());
+ }
+
+}
diff --git a/examples/jpa-strict/src/test/java/org/jboss/shamrock/example/test/JPAReflectionInGraalITCase.java b/examples/jpa-strict/src/test/java/org/jboss/shamrock/example/test/JPAReflectionInGraalITCase.java
new file mode 100644
index 000000000..9fbea6bea
--- /dev/null
+++ b/examples/jpa-strict/src/test/java/org/jboss/shamrock/example/test/JPAReflectionInGraalITCase.java
@@ -0,0 +1,23 @@
+package org.jboss.shamrock.example.test;
+
+import static org.junit.Assert.assertEquals;
+
+import org.jboss.shamrock.example.testutils.URLTester;
+import org.jboss.shamrock.junit.GraalTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test reflection around JPA entities
+ *
+ * @author Emmanuel Bernard emmanuel@hibernate.org
+ */
+@RunWith(GraalTest.class)
+public class JPAReflectionInGraalITCase {
+
+ @Test
+ public void testFieldAndGetterReflectionOnEntityFromServlet() throws Exception {
+ assertEquals("OK", URLTester.relative("jpa/testreflection").invokeURL().asString());
+ }
+
+}
diff --git a/examples/jpa-strict/src/test/java/org/jboss/shamrock/example/test/JPAStoreLoadTestCase.java b/examples/jpa-strict/src/test/java/org/jboss/shamrock/example/test/JPAStoreLoadTestCase.java
new file mode 100644
index 000000000..9b7d9b549
--- /dev/null
+++ b/examples/jpa-strict/src/test/java/org/jboss/shamrock/example/test/JPAStoreLoadTestCase.java
@@ -0,0 +1,82 @@
+package org.jboss.shamrock.example.test;
+
+import java.util.List;
+import java.util.UUID;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.EntityTransaction;
+import javax.persistence.Persistence;
+import javax.persistence.TypedQuery;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Root;
+
+import org.jboss.shamrock.example.jpa.Person;
+import org.jboss.shamrock.example.jpa.SequencedAddress;
+import org.jboss.shamrock.junit.ShamrockTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ *
+ */
+@RunWith(ShamrockTest.class)
+public class JPAStoreLoadTestCase {
+
+ @Test
+ public void testStoreLoadOnJPA() throws Exception {
+ EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory( "templatePU" );
+ System.out.println( "Hibernate EntityManagerFactory: booted" );
+
+ doStuffWithHibernate( entityManagerFactory );
+
+ entityManagerFactory.close();
+ System.out.println( "Hibernate EntityManagerFactory: shut down" );
+
+ }
+
+
+ private static void doStuffWithHibernate(EntityManagerFactory entityManagerFactory) {
+ EntityManager em = entityManagerFactory.createEntityManager();
+ EntityTransaction transaction = em.getTransaction();
+ transaction.begin();
+
+ persistNewPerson( em );
+
+ listExistingPersons( em );
+
+ 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 );
+ TypedQuery q = em.createQuery( cq );
+ List allpersons = q.getResultList();
+ StringBuilder sb = new StringBuilder( "list of stored Person names:\n\t" );
+ for ( Person p : allpersons ) {
+ p.describeFully( sb );
+ sb.append( "\n\t" );
+ }
+ sb.append( "\nList complete.\n" );
+ System.out.print( sb );
+ }
+
+ private static void persistNewPerson(EntityManager entityManager) {
+ Person person = new Person();
+ person.setName( randomName() );
+ person.setAddress( new SequencedAddress( "Street " + randomName() ) );
+ entityManager.persist( person );
+ }
+
+ private static String randomName() {
+ return UUID.randomUUID().toString();
+ }
+
+
+}
diff --git a/examples/jpa-strict/src/test/java/org/jboss/shamrock/example/testutils/URLResponse.java b/examples/jpa-strict/src/test/java/org/jboss/shamrock/example/testutils/URLResponse.java
new file mode 100644
index 000000000..50a2ad39a
--- /dev/null
+++ b/examples/jpa-strict/src/test/java/org/jboss/shamrock/example/testutils/URLResponse.java
@@ -0,0 +1,14 @@
+package org.jboss.shamrock.example.testutils;
+
+import java.io.InputStream;
+
+import javax.json.JsonReader;
+
+public interface URLResponse {
+
+ String asString();
+
+ InputStream asInputStream();
+
+ JsonReader asJsonReader();
+}
diff --git a/examples/jpa-strict/src/test/java/org/jboss/shamrock/example/testutils/URLTester.java b/examples/jpa-strict/src/test/java/org/jboss/shamrock/example/testutils/URLTester.java
new file mode 100644
index 000000000..b1b4cfaf0
--- /dev/null
+++ b/examples/jpa-strict/src/test/java/org/jboss/shamrock/example/testutils/URLTester.java
@@ -0,0 +1,84 @@
+package org.jboss.shamrock.example.testutils;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+
+import javax.json.Json;
+import javax.json.JsonReader;
+
+/**
+ * Convenience class to invoke an URL and return the response.
+ */
+public final class URLTester {
+
+ private final URL fullURL;
+
+ private URLTester(final URL fullURL) {
+ this.fullURL = fullURL;
+ }
+
+ public static URLTester relative(final String relativePath) {
+ final URL uri;
+ try {
+ uri = new URL("http://localhost:8080/" + relativePath);
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ return new URLTester(uri);
+ }
+
+ private URLResponse privateInvokeURL() throws IOException {
+ URLConnection connection = fullURL.openConnection();
+ InputStream in = connection.getInputStream();
+ byte[] buf = new byte[100];
+ int r;
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ while ((r = in.read(buf)) > 0) {
+ out.write(buf, 0, r);
+ }
+ return new URLResponseAdapter(out);
+ }
+
+ public URLResponse invokeURL() {
+ try {
+ return privateInvokeURL();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static class URLResponseAdapter implements URLResponse {
+
+ private final ByteArrayOutputStream buffer;
+
+ public URLResponseAdapter(final ByteArrayOutputStream buffer) {
+ this.buffer = buffer;
+ }
+
+ @Override
+ public String toString() {
+ return new String(buffer.toByteArray());
+ }
+
+ @Override
+ public String asString() {
+ return toString();
+ }
+
+ @Override
+ public InputStream asInputStream() {
+ return new ByteArrayInputStream(buffer.toByteArray());
+ }
+
+ @Override
+ public JsonReader asJsonReader() {
+ return Json.createReader(asInputStream());
+ }
+ }
+
+}
diff --git a/examples/pom.xml b/examples/pom.xml
index 4e8203b12..dbb13a6cf 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -16,6 +16,7 @@
permissive
shared-library
strict
+ jpa-strict
diff --git a/examples/strict/pom.xml b/examples/strict/pom.xml
index cc3bab693..f30dc6814 100644
--- a/examples/strict/pom.xml
+++ b/examples/strict/pom.xml
@@ -144,6 +144,55 @@
+
+ io.fabric8
+ docker-maven-plugin
+ 0.26.1
+
+
+
+ postgres:10.5
+ postgresql
+
+
+ hibernate_orm_test
+ hibernate_orm_test
+ hibernate_orm_test
+
+
+ 5432:5432
+
+
+
+ mapped
+
+ 5432
+
+
+
+
+
+
+
+
+
+
+ docker-start
+ compile
+
+ stop
+ start
+
+
+
+ docker-stop
+ post-integration-test
+
+ stop
+
+
+
+
diff --git a/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/JPATestBootstrapEndpoint.java b/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/JPATestBootstrapEndpoint.java
new file mode 100644
index 000000000..789778c65
--- /dev/null
+++ b/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/JPATestBootstrapEndpoint.java
@@ -0,0 +1,107 @@
+package org.jboss.shamrock.example.jpa;
+
+import javax.persistence.*;
+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;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * Various tests for the JPA integration.
+ * WARNING: these tests will ONLY pass in Substrate, as it also verifies reflection non-functionality.
+ */
+@WebServlet(name = "JPATestBootstrapEndpoint", urlPatterns = "/jpa/testbootstrap")
+public class JPATestBootstrapEndpoint extends HttpServlet {
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ try {
+ testStoreLoadOnJPA();
+ }
+ catch (Exception e) {
+ reportException("Oops, shit happened, No boot for you!", e, resp);
+ }
+
+
+ resp.getWriter().write("OK");
+ }
+
+
+ public void testStoreLoadOnJPA() throws Exception {
+ EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory( "templatePU" );
+ System.out.println( "Hibernate EntityManagerFactory: booted" );
+
+ doStuffWithHibernate( entityManagerFactory );
+
+ entityManagerFactory.close();
+ System.out.println( "Hibernate EntityManagerFactory: shut down" );
+
+ }
+
+ private static void doStuffWithHibernate(EntityManagerFactory entityManagerFactory) {
+ EntityManager em = entityManagerFactory.createEntityManager();
+ EntityTransaction transaction = em.getTransaction();
+ transaction.begin();
+
+ persistNewPerson( em );
+
+ listExistingPersons( em );
+
+ 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 );
+ TypedQuery q = em.createQuery( cq );
+ List allpersons = q.getResultList();
+ StringBuilder sb = new StringBuilder( "list of stored Person names:\n\t" );
+ for ( Person p : allpersons ) {
+ p.describeFully( sb );
+ sb.append( "\n\t" );
+ }
+ sb.append( "\nList complete.\n" );
+ System.out.print( sb );
+ }
+
+ private static void persistNewPerson(EntityManager entityManager) {
+ Person person = new Person();
+ person.setName( randomName() );
+ person.setAddress( new SequencedAddress( "Street " + randomName() ) );
+ entityManager.persist( person );
+ }
+
+ private static String randomName() {
+ return UUID.randomUUID().toString();
+ }
+
+ private void reportException(final Exception e, final HttpServletResponse resp) throws IOException {
+ reportException(null, e, resp);
+ }
+
+ 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/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/Person.java b/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/Person.java
new file mode 100644
index 000000000..3af490f65
--- /dev/null
+++ b/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/Person.java
@@ -0,0 +1,58 @@
+package org.jboss.shamrock.example.jpa;
+
+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;
+
+@Entity
+public class Person {
+
+ private long id;
+ private String name;
+ private SequencedAddress address;
+
+ 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 void describeFully(StringBuilder sb) {
+ sb.append( "Person with id=" ).append( id ).append( ", name='" ).append( name ).append( "', address { " );
+ getAddress().describeFully( sb );
+ sb.append( " }" );
+ }
+}
diff --git a/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/SequencedAddress.java b/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/SequencedAddress.java
new file mode 100644
index 000000000..101b263b0
--- /dev/null
+++ b/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/SequencedAddress.java
@@ -0,0 +1,41 @@
+package org.jboss.shamrock.example.jpa;
+
+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/examples/strict/src/main/resources/META-INF/persistence.xml b/examples/strict/src/main/resources/META-INF/persistence.xml
new file mode 100644
index 000000000..548b704a9
--- /dev/null
+++ b/examples/strict/src/main/resources/META-INF/persistence.xml
@@ -0,0 +1,36 @@
+
+
+
+
+ Hibernate test case template Persistence Unit
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/strict/src/test/java/org/jboss/shamrock/example/test/JPABootstrapInGraalITCase.java b/examples/strict/src/test/java/org/jboss/shamrock/example/test/JPABootstrapInGraalITCase.java
new file mode 100644
index 000000000..185ebdfdb
--- /dev/null
+++ b/examples/strict/src/test/java/org/jboss/shamrock/example/test/JPABootstrapInGraalITCase.java
@@ -0,0 +1,23 @@
+package org.jboss.shamrock.example.test;
+
+import org.jboss.shamrock.example.testutils.URLTester;
+import org.jboss.shamrock.junit.GraalTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test reflection around JPA entities
+ *
+ * @author Emmanuel Bernard emmanuel@hibernate.org
+ */
+@RunWith(GraalTest.class)
+public class JPABootstrapInGraalITCase {
+
+ @Test
+ public void testFieldAndGetterReflectionOnEntityFromServlet() throws Exception {
+ assertEquals("OK", URLTester.relative("jpa/testbootstrap").invokeURL().asString());
+ }
+
+}
diff --git a/examples/strict/src/test/java/org/jboss/shamrock/example/test/JPAStoreLoadTestCase.java b/examples/strict/src/test/java/org/jboss/shamrock/example/test/JPAStoreLoadTestCase.java
new file mode 100644
index 000000000..9b7d9b549
--- /dev/null
+++ b/examples/strict/src/test/java/org/jboss/shamrock/example/test/JPAStoreLoadTestCase.java
@@ -0,0 +1,82 @@
+package org.jboss.shamrock.example.test;
+
+import java.util.List;
+import java.util.UUID;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.EntityTransaction;
+import javax.persistence.Persistence;
+import javax.persistence.TypedQuery;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Root;
+
+import org.jboss.shamrock.example.jpa.Person;
+import org.jboss.shamrock.example.jpa.SequencedAddress;
+import org.jboss.shamrock.junit.ShamrockTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ *
+ */
+@RunWith(ShamrockTest.class)
+public class JPAStoreLoadTestCase {
+
+ @Test
+ public void testStoreLoadOnJPA() throws Exception {
+ EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory( "templatePU" );
+ System.out.println( "Hibernate EntityManagerFactory: booted" );
+
+ doStuffWithHibernate( entityManagerFactory );
+
+ entityManagerFactory.close();
+ System.out.println( "Hibernate EntityManagerFactory: shut down" );
+
+ }
+
+
+ private static void doStuffWithHibernate(EntityManagerFactory entityManagerFactory) {
+ EntityManager em = entityManagerFactory.createEntityManager();
+ EntityTransaction transaction = em.getTransaction();
+ transaction.begin();
+
+ persistNewPerson( em );
+
+ listExistingPersons( em );
+
+ 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 );
+ TypedQuery q = em.createQuery( cq );
+ List allpersons = q.getResultList();
+ StringBuilder sb = new StringBuilder( "list of stored Person names:\n\t" );
+ for ( Person p : allpersons ) {
+ p.describeFully( sb );
+ sb.append( "\n\t" );
+ }
+ sb.append( "\nList complete.\n" );
+ System.out.print( sb );
+ }
+
+ private static void persistNewPerson(EntityManager entityManager) {
+ Person person = new Person();
+ person.setName( randomName() );
+ person.setAddress( new SequencedAddress( "Street " + randomName() ) );
+ entityManager.persist( person );
+ }
+
+ private static String randomName() {
+ return UUID.randomUUID().toString();
+ }
+
+
+}
diff --git a/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/HibernateReflectiveNeeds.java b/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/HibernateReflectiveNeeds.java
index 5fa2825b3..8dac162fb 100644
--- a/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/HibernateReflectiveNeeds.java
+++ b/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/HibernateReflectiveNeeds.java
@@ -2,6 +2,7 @@ package org.jboss.shamrock.jpa;
import java.util.Objects;
+import org.hibernate.tuple.component.PojoComponentTuplizer;
import org.jboss.shamrock.deployment.ProcessorContext;
/**
@@ -29,6 +30,7 @@ final class HibernateReflectiveNeeds {
private void registerAll() {
//Various well known needs:
simpleConstructor(org.hibernate.tuple.entity.PojoEntityTuplizer.class);
+ allConstructors(org.hibernate.tuple.component.PojoComponentTuplizer.class);
simpleConstructor(org.hibernate.persister.entity.SingleTableEntityPersister.class);
simpleConstructor(org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorBuilderImpl.class);
simpleConstructor(org.hibernate.id.enhanced.SequenceStyleGenerator.class);
@@ -53,6 +55,11 @@ final class HibernateReflectiveNeeds {
simpleConstructor("org.postgresql.Driver");
}
+ private void allConstructors(final Class clazz) {
+ //FIXME simpleConstructor is not optimized yet to only enlist the no-arg constructor
+ simpleConstructor(clazz);
+ }
+
/**
* Register classes which we know will only need to be created via their no-arg constructor
* @param clazz
diff --git a/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/JpaJandexScavenger.java b/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/JpaJandexScavenger.java
index 0c4f14b91..59b4f27b2 100644
--- a/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/JpaJandexScavenger.java
+++ b/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/JpaJandexScavenger.java
@@ -64,6 +64,7 @@ final class JpaJandexScavenger {
JPADeploymentTemplate template = context.getRecordingProxy(JPADeploymentTemplate.class);
collector.dumpAllToJPATemplate(template);
template.enlistPersistenceUnit();
+ template.callHibernateFeatureInit();
}
return collector;
diff --git a/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/JPADeploymentTemplate.java b/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/JPADeploymentTemplate.java
index f0e3adebc..59d8d6cb9 100644
--- a/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/JPADeploymentTemplate.java
+++ b/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/JPADeploymentTemplate.java
@@ -1,5 +1,7 @@
package org.jboss.shamrock.jpa;
+import org.hibernate.protean.Hibernate;
+
import java.util.ArrayList;
import java.util.List;
@@ -16,4 +18,8 @@ public class JPADeploymentTemplate {
public void enlistPersistenceUnit() {
System.out.println("List of entities \n" + entities.toString());
}
+
+ public void callHibernateFeatureInit() {
+ Hibernate.featureInit();
+ }
}