Merge pull request #22 from emmanuelbernard/JPABoot

Integrate JPA into Shamrock
This commit is contained in:
Stuart Douglas
2018-09-18 09:43:47 +10:00
committed by GitHub
29 changed files with 1355 additions and 0 deletions

173
examples/jpa-strict/pom.xml Normal file
View File

@@ -0,0 +1,173 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>shamrock-examples-parent</artifactId>
<groupId>org.jboss.shamrock</groupId>
<version>1.0.0.Alpha1-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>shamrock-strict-jpa-example</artifactId>
<description>An example that only contains JPA related tests running in strict mode</description>
<dependencies>
<dependency>
<groupId>org.jboss.shamrock</groupId>
<artifactId>shamrock-jaxrs-deployment</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.shamrock</groupId>
<artifactId>shamrock-jpa-deployment</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql-protean</artifactId>
<version>42.2.5-SNAPSHOT</version>
</dependency>
<!-- test dependencies -->
<dependency>
<groupId>org.jboss.shamrock</groupId>
<artifactId>shamrock-junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.shamrock</groupId>
<artifactId>shamrock-graal</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>${project.groupId}</groupId>
<artifactId>shamrock-maven-plugin</artifactId>
<version>${project.version}</version>
<executions>
<execution>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.26.1</version>
<configuration>
<images>
<image>
<name>postgres:10.5</name>
<alias>postgresql</alias>
<run>
<env>
<POSTGRES_USER>hibernate_orm_test</POSTGRES_USER>
<POSTGRES_PASSWORD>hibernate_orm_test</POSTGRES_PASSWORD>
<POSTGRES_DB>hibernate_orm_test</POSTGRES_DB>
</env>
<ports>
<port>5432:5432</port>
</ports>
<wait>
<tcp>
<mode>mapped</mode>
<ports>
<port>5432</port>
</ports>
</tcp>
<time>10000</time>
</wait>
</run>
</image>
</images>
</configuration>
<executions>
<execution>
<id>docker-start</id>
<phase>compile</phase>
<goals>
<goal>stop</goal>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>docker-stop</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>native-image</id>
<activation>
<property>
<name>!no-native</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<systemProperties>
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
</systemProperties>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>${project.groupId}</groupId>
<artifactId>shamrock-maven-plugin</artifactId>
<version>${project.version}</version>
<executions>
<execution>
<id>native-image</id>
<goals>
<goal>native-image</goal>
</goals>
<configuration>
<reportErrorsAtRuntime>false</reportErrorsAtRuntime>
<cleanupServer>true</cleanupServer>
<enableHttpUrlHandler>true</enableHttpUrlHandler>
<!-- Requires Protean Graal fork to work, will fail otherwise
<enableRetainedHeapReporting>true</enableRetainedHeapReporting>
<enableCodeSizeReporting>true</enableCodeSizeReporting>
-->
<graalvmHome>${graalvmHome}</graalvmHome>
<enableJni>false</enableJni>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@@ -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");
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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<Person> cq = cb.createQuery(Person.class);
Root<Person> from = cq.from(Person.class);
cq.select(from);
TypedQuery<Person> q = em.createQuery(cq);
List<Person> 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");
}
}

View File

@@ -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");
}
}

View File

@@ -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 {
}

View File

@@ -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( " }" );
}
}

View File

@@ -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( "'" );
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,37 @@
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
<persistence-unit name="templatePU" transaction-type="RESOURCE_LOCAL">
<description>Hibernate test case template Persistence Unit</description>
<properties>
<!-- intentionally using worse case so that we can optimise for this -->
<property name="hibernate.archive.autodetection" value="class, hbm"/>
<!-- Connection specific -->
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL95Dialect"/>
<property name="hibernate.connection.url" value="jdbc:postgresql:hibernate_orm_test"/>
<property name="hibernate.connection.username" value="hibernate_orm_test"/>
<property name="hibernate.connection.password" value="hibernate_orm_test"/>
<!-- Tuning and debugging -->
<property name="hibernate.connection.pool_size" value="2"/>
<property name="hibernate.show_sql" value="false"/>
<property name="hibernate.format_sql" value="false"/>
<!--
Optimistically create the tables;
will cause background errors being logged if they already exist,
but is practical to retain existing data across runs (or create as needed) -->
<!-- drop-and-create create-only -->
<property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
<property name="javax.persistence.validation.mode" value="NONE"/>
</properties>
</persistence-unit>
</persistence>

View File

@@ -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());
}
}

View File

@@ -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());
}
}

View File

@@ -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<Person> cq = cb.createQuery( Person.class );
Root<Person> from = cq.from( Person.class );
cq.select( from );
TypedQuery<Person> q = em.createQuery( cq );
List<Person> 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();
}
}

View File

@@ -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();
}

View File

@@ -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());
}
}
}

View File

@@ -16,6 +16,7 @@
<module>permissive</module>
<module>shared-library</module>
<module>strict</module>
<module>jpa-strict</module>
</modules>
<dependencies>

View File

@@ -144,6 +144,55 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.26.1</version>
<configuration>
<images>
<image>
<name>postgres:10.5</name>
<alias>postgresql</alias>
<run>
<env>
<POSTGRES_USER>hibernate_orm_test</POSTGRES_USER>
<POSTGRES_PASSWORD>hibernate_orm_test</POSTGRES_PASSWORD>
<POSTGRES_DB>hibernate_orm_test</POSTGRES_DB>
</env>
<ports>
<port>5432:5432</port>
</ports>
<wait>
<tcp>
<mode>mapped</mode>
<ports>
<port>5432</port>
</ports>
</tcp>
<time>10000</time>
</wait>
</run>
</image>
</images>
</configuration>
<executions>
<execution>
<id>docker-start</id>
<phase>compile</phase>
<goals>
<goal>stop</goal>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>docker-stop</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

View File

@@ -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<Person> cq = cb.createQuery( Person.class );
Root<Person> from = cq.from( Person.class );
cq.select( from );
TypedQuery<Person> q = em.createQuery( cq );
List<Person> 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");
}
}

View File

@@ -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( " }" );
}
}

View File

@@ -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( "'" );
}
}

View File

@@ -0,0 +1,36 @@
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
<persistence-unit name="templatePU" transaction-type="RESOURCE_LOCAL">
<description>Hibernate test case template Persistence Unit</description>
<properties>
<!-- intentionally using worse case so that we can optimise for this -->
<property name="hibernate.archive.autodetection" value="class, hbm"/>
<!-- Connection specific -->
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL95Dialect"/>
<property name="hibernate.connection.url" value="jdbc:postgresql:hibernate_orm_test"/>
<property name="hibernate.connection.username" value="hibernate_orm_test"/>
<property name="hibernate.connection.password" value="hibernate_orm_test"/>
<!-- Tuning and debugging -->
<property name="hibernate.connection.pool_size" value="2"/>
<property name="hibernate.show_sql" value="false"/>
<property name="hibernate.format_sql" value="false"/>
<!--
Optimistically create the tables;
will cause background errors being logged if they already exist,
but is practical to retain existing data across runs (or create as needed) -->
<property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
<property name="javax.persistence.validation.mode" value="NONE"/>
</properties>
</persistence-unit>
</persistence>

View File

@@ -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());
}
}

View File

@@ -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<Person> cq = cb.createQuery( Person.class );
Root<Person> from = cq.from( Person.class );
cq.select( from );
TypedQuery<Person> q = em.createQuery( cq );
List<Person> 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();
}
}

View File

@@ -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

View File

@@ -64,6 +64,7 @@ final class JpaJandexScavenger {
JPADeploymentTemplate template = context.getRecordingProxy(JPADeploymentTemplate.class);
collector.dumpAllToJPATemplate(template);
template.enlistPersistenceUnit();
template.callHibernateFeatureInit();
}
return collector;

View File

@@ -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();
}
}