Merge pull request #25 from stuartwdouglas/emi

Entity Manager injection support
This commit is contained in:
Stuart Douglas
2018-09-20 15:47:51 +10:00
committed by GitHub
34 changed files with 1108 additions and 83 deletions

View File

@@ -74,6 +74,7 @@ public class BuildTimeGenerator {
private final List<Function<String, Function<ClassVisitor, ClassVisitor>>> bytecodeTransformers = new ArrayList<>();
private final Set<String> applicationArchiveMarkers;
private final ArchiveContextBuilder archiveContextBuilder;
private final Set<String> capabilities;
public BuildTimeGenerator(ClassOutput classOutput, ClassLoader cl, boolean useStaticInit, ArchiveContextBuilder contextBuilder) {
this.useStaticInit = useStaticInit;
@@ -91,6 +92,7 @@ public class BuildTimeGenerator {
this.classLoader = cl;
this.applicationArchiveMarkers = new HashSet<>(setupContext.applicationArchiveMarkers);
this.archiveContextBuilder = contextBuilder;
this.capabilities = new HashSet<>(setupContext.capabilities);
}
public List<Function<String, Function<ClassVisitor, ClassVisitor>>> getBytecodeTransformers() {
@@ -294,6 +296,11 @@ public class BuildTimeGenerator {
this.proxyClasses.add(Arrays.asList(proxyClasses));
}
@Override
public boolean isCapabilityPresent(String capability) {
return capabilities.contains(capability);
}
void writeMainClass() throws IOException {

View File

@@ -108,4 +108,11 @@ public interface ProcessorContext {
* @param proxyClasses The interface names that this proxy will implement
*/
void addProxyDefinition(String ... proxyClasses);
/**
*
* @param capability
* @return
*/
boolean isCapabilityPresent(String capability);
}

View File

@@ -15,8 +15,9 @@ public class RuntimePriority {
public static final int JAXRS_DEPLOYMENT = 350;
public static final int ARC_DEPLOYMENT = 300;
public static final int UNDERTOW_DEPLOY = 400;
public static final int UNDERTOW_START = 500;
public static final int BEAN_VALIDATION_DEPLOYMENT = 600;
public static final int TRANSACTIONS_DEPLOYMENT = 700;
public static final int DATASOURCE_DEPLOYMENT = 700;
public static final int BOOTSTRAP_EMF = 800;
public static final int UNDERTOW_START = 900;
}

View File

@@ -24,4 +24,10 @@ public interface SetupContext {
* @param file The file location
*/
void addApplicationArchiveMarker(String file);
/**
* Registers a capability name as being present, this can be queried via {@link ProcessorContext#isCapabilityPresent(String)}
* @param name The capability name
*/
void addCapability(String name);
}

View File

@@ -1,13 +1,16 @@
package org.jboss.shamrock.deployment;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
class SetupContextImpl implements SetupContext {
final List<ResourceProcessor> resourceProcessors = new ArrayList<>();
final List<InjectionProvider> injectionProviders = new ArrayList<>();
final List<String> applicationArchiveMarkers = new ArrayList<>();
final Set<String> capabilities = new HashSet<>();
@Override
public void addResourceProcessor(ResourceProcessor resourceProcessor) {
@@ -23,4 +26,8 @@ class SetupContextImpl implements SetupContext {
public void addApplicationArchiveMarker(String file) {
applicationArchiveMarkers.add(file);
}
public void addCapability(String name) {
capabilities.add(name);
}
}

View File

@@ -53,7 +53,14 @@ public class RuntimeClassLoader extends ClassLoader implements ClassOutput, Cons
}
@Override
public Enumeration<URL> getResources(String name) throws IOException {
public Enumeration<URL> getResources(String nm) throws IOException {
String name;
if(nm.startsWith("/")) {
name = nm.substring(1);
} else {
name = nm;
}
// TODO some superugly hack for bean provider
byte[] data = resources.get(name);
if (data != null) {
@@ -77,6 +84,28 @@ public class RuntimeClassLoader extends ClassLoader implements ClassOutput, Cons
return super.getResources(name);
}
@Override
public URL getResource(String nm) {
String name;
if(nm.startsWith("/")) {
name = nm.substring(1);
} else {
name = nm;
}
return super.getResource(name);
}
@Override
public InputStream getResourceAsStream(String nm) {
String name;
if(nm.startsWith("/")) {
name = nm.substring(1);
} else {
name = nm;
}
return super.getResourceAsStream(name);
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class<?> ex = findLoadedClass(name);

View File

@@ -4,7 +4,7 @@
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
<persistence-unit name="templatePU" transaction-type="RESOURCE_LOCAL">
<persistence-unit name="templatePU" transaction-type="JTA">
<description>Hibernate test case template Persistence Unit</description>

View File

@@ -0,0 +1,104 @@
package org.jboss.shamrock.example.jpa;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.UUID;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
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;
import javax.transaction.UserTransaction;
/**
* Various tests for the JPA integration.
*/
@WebServlet(urlPatterns = "/jpa/testjpaeminjection")
public class JPATestEMInjectionEndpoint extends HttpServlet {
@Inject
private EntityManager em;
@Inject
private UserTransaction transaction;
@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 {
doStuffWithHibernate();
System.out.println("Hibernate EntityManagerFactory: shut down");
}
private void doStuffWithHibernate() throws Exception {
transaction.begin();
persistNewPerson(em);
listExistingPersons(em);
transaction.commit();
}
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

@@ -1,6 +1,7 @@
package org.jboss.shamrock.example.jpa;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;
@@ -10,4 +11,8 @@ public class JpaProducer {
@Produces
@PersistenceUnit(unitName = "templatePU")
EntityManagerFactory emf;
@Produces
@PersistenceContext(unitName = "templatePU")
EntityManager em;
}

View File

@@ -4,7 +4,7 @@
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
<persistence-unit name="templatePU" transaction-type="RESOURCE_LOCAL">
<persistence-unit name="templatePU" transaction-type="JTA">
<description>Hibernate test case template Persistence Unit</description>

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.ShamrockTest;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* Test reflection around JPA entities
*
* @author Emmanuel Bernard emmanuel@hibernate.org
*/
@RunWith(ShamrockTest.class)
public class JPAEntityManagerInjectionTestCase {
@Test
public void testJpaEntityManagerInjection() throws Exception {
assertEquals("OK", URLTester.relative("jpa/testjpaeminjection").invokeURL().asString());
}
}

View File

@@ -7,7 +7,9 @@ public interface AnnotatedElement {
AnnotationCreator addAnnotation(String annotationType);
AnnotationCreator addAnnotation(Class<?> annotationType);
default AnnotationCreator addAnnotation(Class<?> annotationType) {
return addAnnotation(annotationType.getName());
}
default void addAnnotation(AnnotationInstance annotation) {
AnnotationCreator ac = addAnnotation(annotation.name().toString());

View File

@@ -150,11 +150,6 @@ public class ClassCreator implements AutoCloseable, AnnotatedElement {
return ac;
}
@Override
public AnnotationCreator addAnnotation(Class<?> annotationType) {
return addAnnotation(annotationType.getName());
}
public static class Builder {
private ClassOutput classOutput;

View File

@@ -1,7 +1,7 @@
package org.jboss.protean.gizmo;
public interface FieldCreator extends MemberCreator<FieldCreator> {
public interface FieldCreator extends MemberCreator<FieldCreator>,AnnotatedElement {
FieldDescriptor getFieldDescriptor();

View File

@@ -1,11 +1,18 @@
package org.jboss.protean.gizmo;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Opcodes;
class FieldCreatorImpl implements FieldCreator {
private final FieldDescriptor fieldDescriptor;
private final List<AnnotationCreatorImpl> annotations = new ArrayList<>();
private int modifiers;
@@ -32,7 +39,21 @@ class FieldCreatorImpl implements FieldCreator {
@Override
public void write(ClassWriter file) {
file.visitField(modifiers, fieldDescriptor.getName(), fieldDescriptor.getType(), null, null);
FieldVisitor fieldVisitor = file.visitField(modifiers, fieldDescriptor.getName(), fieldDescriptor.getType(), null, null);
for(AnnotationCreatorImpl annotation : annotations) {
AnnotationVisitor av = fieldVisitor.visitAnnotation(DescriptorUtils.extToInt(annotation.getAnnotationType()), true);
for(Map.Entry<String, Object> e : annotation.getValues().entrySet()) {
av.visit(e.getKey(), e.getValue());
}
av.visitEnd();
}
fieldVisitor.visitEnd();
}
@Override
public AnnotationCreator addAnnotation(String annotationType) {
AnnotationCreatorImpl ac = new AnnotationCreatorImpl(annotationType);
annotations.add(ac);
return ac;
}
}

View File

@@ -39,4 +39,6 @@ public interface MethodCreator extends MemberCreator<MethodCreator>, BytecodeCre
*/
MethodDescriptor getMethodDescriptor();
AnnotatedElement getParameterAnnotations(int param);
}

View File

@@ -3,9 +3,9 @@ package org.jboss.protean.gizmo;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassWriter;
@@ -17,6 +17,7 @@ class MethodCreatorImpl extends BytecodeCreatorImpl implements MethodCreator {
private int modifiers = Opcodes.ACC_PUBLIC;
private final List<String> exceptions = new ArrayList<>();
private final List<AnnotationCreatorImpl> annotations = new ArrayList<>();
private final Map<Integer, AnnotationParameters> parameterAnnotations = new HashMap<>();
MethodCreatorImpl(MethodDescriptor methodDescriptor, String declaringClassName, ClassOutput classOutput, ClassCreator classCreator) {
super(methodDescriptor, declaringClassName, classOutput, classCreator);
@@ -38,6 +39,16 @@ class MethodCreatorImpl extends BytecodeCreatorImpl implements MethodCreator {
return methodDescriptor;
}
@Override
public AnnotatedElement getParameterAnnotations(int param) {
if(parameterAnnotations.containsKey(param)) {
return parameterAnnotations.get(param);
}
AnnotationParameters p = new AnnotationParameters();
parameterAnnotations.put(param, p);
return p;
}
@Override
public int getModifiers() {
return modifiers;
@@ -53,6 +64,8 @@ class MethodCreatorImpl extends BytecodeCreatorImpl implements MethodCreator {
public void write(ClassWriter file) {
MethodVisitor visitor = file.visitMethod(modifiers, methodDescriptor.getName(), methodDescriptor.getDescriptor(), null, exceptions.toArray(new String[0]));
int localVarCount = Modifier.isStatic(modifiers) ? 0 : 1;
for (int i = 0; i < methodDescriptor.getParameterTypes().length; ++i) {
String s = methodDescriptor.getParameterTypes()[i];
@@ -73,6 +86,15 @@ class MethodCreatorImpl extends BytecodeCreatorImpl implements MethodCreator {
}
av.visitEnd();
}
for(Map.Entry<Integer, AnnotationParameters> entry : parameterAnnotations.entrySet()) {
for(AnnotationCreatorImpl annotation : entry.getValue().annotations) {
AnnotationVisitor av = visitor.visitParameterAnnotation(entry.getKey(), DescriptorUtils.extToInt(annotation.getAnnotationType()), true);
for(Map.Entry<String, Object> e : annotation.getValues().entrySet()) {
av.visit(e.getKey(), e.getValue());
}
av.visitEnd();
}
}
visitor.visitEnd();
}
@@ -88,8 +110,17 @@ class MethodCreatorImpl extends BytecodeCreatorImpl implements MethodCreator {
return ac;
}
@Override
public AnnotationCreator addAnnotation(Class<?> annotationType) {
return addAnnotation(annotationType.getName());
private static class AnnotationParameters implements AnnotatedElement {
final List<AnnotationCreatorImpl> annotations = new ArrayList<>();
@Override
public AnnotationCreator addAnnotation(String annotationType) {
AnnotationCreatorImpl ret = new AnnotationCreatorImpl(annotationType);
annotations.add(ret);
return ret;
}
}
}

View File

@@ -10,6 +10,7 @@
<modelVersion>4.0.0</modelVersion>
<artifactId>hibernate-orm-protean-example</artifactId>
<version>1.0.0-SNAPSHOT</version>
<dependencies>
<dependency>

View File

@@ -10,6 +10,7 @@
<modelVersion>4.0.0</modelVersion>
<artifactId>hibernate-orm-protean</artifactId>
<version>1.0.0-SNAPSHOT</version>
<dependencies>
<dependency>

View File

@@ -31,6 +31,7 @@ import org.hibernate.cfg.Environment;
import org.hibernate.cfg.beanvalidation.BeanValidationIntegrator;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.dialect.spi.DialectFactory;
import org.hibernate.engine.transaction.jta.platform.internal.JBossStandAloneJtaPlatform;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatformResolver;
import org.hibernate.id.factory.spi.MutableIdentifierGeneratorFactory;
@@ -268,8 +269,9 @@ class FastBootMetadataBuilder {
}
private JtaPlatform extractJtaPlatform() {
JtaPlatformResolver service = standardServiceRegistry.getService( JtaPlatformResolver.class );
return service.resolveJtaPlatform( this.configurationValues, (ServiceRegistryImplementor) standardServiceRegistry );
return new JBossStandAloneJtaPlatform();
// JtaPlatformResolver service = standardServiceRegistry.getService( JtaPlatformResolver.class );
// return service.resolveJtaPlatform( this.configurationValues, (ServiceRegistryImplementor) standardServiceRegistry );
}
private Dialect extractDialect() {
@@ -416,9 +418,11 @@ class FastBootMetadataBuilder {
else {
if ( txnType == PersistenceUnitTransactionType.JTA ) {
ssrBuilder.applySetting( TRANSACTION_COORDINATOR_STRATEGY, JtaTransactionCoordinatorBuilderImpl.class );
configurationValues.put(TRANSACTION_COORDINATOR_STRATEGY, JtaTransactionCoordinatorBuilderImpl.class);
}
else if ( txnType == PersistenceUnitTransactionType.RESOURCE_LOCAL ) {
ssrBuilder.applySetting( TRANSACTION_COORDINATOR_STRATEGY, JdbcResourceLocalTransactionCoordinatorBuilderImpl.class );
configurationValues.put(TRANSACTION_COORDINATOR_STRATEGY, JdbcResourceLocalTransactionCoordinatorBuilderImpl.class);
}
}
}

View File

@@ -1,10 +1,13 @@
package org.hibernate.protean.impl;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationHandler;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.ServiceLoader;
@@ -29,7 +32,7 @@ public class FlatClassLoaderService implements ClassLoaderService {
@Override
public <T> Class<T> classForName(String className) {
try {
return (Class<T>) Class.forName( className, false, Thread.currentThread().getContextClassLoader() );
return (Class<T>) Class.forName( className, false, getClassLoader() );
}
catch (ClassNotFoundException e) {
log.errorf( "Could not load class '%s' using Class.forName(String)", className );
@@ -39,7 +42,7 @@ public class FlatClassLoaderService implements ClassLoaderService {
@Override
public URL locateResource(String name) {
URL resource = FlatClassLoaderService.class.getResource( name );
URL resource = getClassLoader().getResource( name );
if ( resource == null ) {
log.warnf( "Loading of resource '%s' failed. Maybe that's ok, maybe you forgot to include this resource in the binary image? -H:IncludeResources=", name );
}
@@ -51,7 +54,7 @@ public class FlatClassLoaderService implements ClassLoaderService {
@Override
public InputStream locateResourceStream(String name) {
InputStream resourceAsStream = FlatClassLoaderService.class.getResourceAsStream( name );
InputStream resourceAsStream = getClassLoader().getResourceAsStream( name );
if ( resourceAsStream == null ) {
log.warnf( "Loading of resource '%s' failed. Maybe that's ok, maybe you forgot to include this resource in the binary image? -H:IncludeResources=", name );
}
@@ -64,12 +67,21 @@ public class FlatClassLoaderService implements ClassLoaderService {
@Override
public List<URL> locateResources(String name) {
log.debugf( "locateResources (plural form) was invoked for resource '%s'. Is there a real need for this plural form?", name );
return Collections.singletonList( locateResource( name ) );
try {
Enumeration<URL> resources = getClassLoader().getResources(name);
List<URL> resource = new ArrayList<>();
while (resources.hasMoreElements()) {
resource.add(resources.nextElement());
}
return resource;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public <S> Collection<S> loadJavaServices(Class<S> serviceContract) {
ServiceLoader<S> serviceLoader = ServiceLoader.load( serviceContract );
ServiceLoader<S> serviceLoader = ServiceLoader.load( serviceContract , getClassLoader());
final LinkedHashSet<S> services = new LinkedHashSet<S>();
for ( S service : serviceLoader ) {
services.add( service );
@@ -85,7 +97,7 @@ public class FlatClassLoaderService implements ClassLoaderService {
@Override
public <T> T workWithClassLoader(Work<T> work) {
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
ClassLoader systemClassLoader = getClassLoader();
return work.doWork( systemClassLoader );
}
@@ -94,4 +106,12 @@ public class FlatClassLoaderService implements ClassLoaderService {
//easy!
}
private ClassLoader getClassLoader() {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if(cl == null) {
return FlatClassLoaderService.class.getClassLoader();
}
return cl;
}
}

View File

@@ -19,8 +19,10 @@ import org.hibernate.engine.jdbc.connections.internal.MultiTenantConnectionProvi
import org.hibernate.engine.jdbc.cursor.internal.RefCursorSupportInitiator;
import org.hibernate.engine.jdbc.internal.JdbcServicesInitiator;
import org.hibernate.engine.jndi.internal.JndiServiceInitiator;
import org.hibernate.engine.transaction.jta.platform.internal.JBossStandAloneJtaPlatform;
import org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator;
import org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformResolverInitiator;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
import org.hibernate.hql.internal.QueryTranslatorFactoryInitiator;
import org.hibernate.id.factory.internal.MutableIdentifierGeneratorFactoryInitiator;
import org.hibernate.integrator.spi.Integrator;
@@ -39,6 +41,7 @@ import org.hibernate.resource.transaction.internal.TransactionCoordinatorBuilder
import org.hibernate.service.Service;
import org.hibernate.service.internal.ProvidedService;
import org.hibernate.service.internal.SessionFactoryServiceRegistryFactoryInitiator;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.tool.hbm2ddl.ImportSqlCommandExtractorInitiator;
import org.hibernate.tool.schema.internal.SchemaManagementToolInitiator;
@@ -182,6 +185,12 @@ public class PreconfiguredServiceRegistryBuilder {
//Replaces JtaPlatformResolverInitiator.INSTANCE );
serviceInitiators.add( new ProteanJtaPlatformResolver( rs.getJtaPlatform() ) );
serviceInitiators.add(new JtaPlatformInitiator() {
@Override
protected JtaPlatform getFallbackProvider(Map configurationValues, ServiceRegistryImplementor registry) {
return new JBossStandAloneJtaPlatform();
}
});
//Disabled:
//serviceInitiators.add( JtaPlatformInitiator.INSTANCE );

View File

@@ -91,6 +91,20 @@
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>

View File

@@ -27,7 +27,13 @@ public final class HibernateEntityEnhancer implements Function<String, Function<
Objects.requireNonNull(classnameWhitelist);
this.classnameWhitelist = classnameWhitelist;
BytecodeProvider provider = new org.hibernate.bytecode.internal.bytebuddy.BytecodeProviderImpl();
this.enhancer = provider.getEnhancer(new DefaultEnhancementContext());
DefaultEnhancementContext enhancementContext = new DefaultEnhancementContext() {
@Override
public ClassLoader getLoadingClassLoader() {
return Thread.currentThread().getContextClassLoader();
}
};
this.enhancer = provider.getEnhancer(enhancementContext);
}
@Override

View File

@@ -35,20 +35,69 @@ final class HibernateReflectiveNeeds {
simpleConstructor(org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorBuilderImpl.class);
simpleConstructor(org.hibernate.id.enhanced.SequenceStyleGenerator.class);
simpleConstructor(org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl.class);
simpleConstructor(org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl.class);
processorContext.addReflectiveClass(true, false, com.arjuna.ats.jta.UserTransaction.class.getName());
processorContext.addReflectiveClass(true, false, com.arjuna.ats.jta.TransactionManager.class.getName());
//FIXME following is not Hibernate specific?
simpleConstructor("com.sun.xml.internal.stream.events.XMLEventFactoryImpl");
//ANTLR tokens:
simpleConstructor(org.hibernate.hql.internal.ast.HqlToken.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.Node.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.QueryNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.SqlNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.FromClause.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.DotNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.IdentNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.FromElement.class);
//ANTLR tokens:
simpleConstructor(org.hibernate.hql.internal.ast.tree.SelectClause.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.HqlSqlWalkerNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.MethodNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.AbstractStatement.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.EntityJoinFromElement.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.UnaryLogicOperatorNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.NullNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.IntoClause.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.AbstractRestrictableStatement.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.UpdateStatement.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.SelectExpressionImpl.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.CastFunctionNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.MapKeyEntityFromElement.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.DeleteStatement.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.SqlNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.SearchedCaseNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.FromElement.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.JavaConstantNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.SelectExpressionList.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.SqlFragment.class);
///TODO ... several mode ANTLR tokens will be needed. Above will do for an hello world demo.
simpleConstructor(org.hibernate.hql.internal.ast.tree.MapKeyNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.ImpliedFromElement.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.IsNotNullLogicOperatorNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.InsertStatement.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.UnaryArithmeticNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.CollectionFunction.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.BinaryLogicOperatorNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.CountNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.IsNullLogicOperatorNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.IdentNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.ComponentJoin.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.ParameterNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.AbstractSelectExpression.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.MapEntryNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.MapValueNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.InLogicOperatorNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.IndexNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.AbstractNullnessCheckNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.DotNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.ResultVariableRefNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.BetweenOperatorNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.AggregateNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.QueryNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.BooleanLiteralNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.SimpleCaseNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.AbstractMapComponentNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.FromReferenceNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.OrderByClause.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.FromClause.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.ConstructorNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.LiteralNode.class);
simpleConstructor(org.hibernate.hql.internal.ast.tree.BinaryArithmeticOperatorNode.class);
//PostgreSQL specific (move to its own home?) FIXME
simpleConstructor(org.hibernate.dialect.PostgreSQL95Dialect.class);

View File

@@ -1,6 +1,7 @@
package org.jboss.shamrock.jpa;
import java.io.IOException;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
@@ -22,6 +23,7 @@ import org.jboss.jandex.IndexView;
import org.jboss.shamrock.deployment.ArchiveContext;
import org.jboss.shamrock.deployment.ProcessorContext;
import org.jboss.shamrock.deployment.codegen.BytecodeRecorder;
import org.jboss.shamrock.jpa.runtime.JPADeploymentTemplate;
/**
* Scan the Jandex index to find JPA entities (and embeddables supporting entity models).
@@ -144,7 +146,7 @@ final class JpaJandexScavenger {
}
ClassInfo classInfo = index.getClassByName(className);
if (classInfo == null) {
if (className == ClassType.OBJECT_TYPE.name()) {
if (className == ClassType.OBJECT_TYPE.name() || className.toString().equals(Serializable.class.getName())) {
return;
}
else {

View File

@@ -7,25 +7,39 @@ import java.util.concurrent.atomic.AtomicReference;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Dependent;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;
import javax.transaction.TransactionManager;
import javax.transaction.TransactionSynchronizationRegistry;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationTarget;
import org.jboss.jandex.AnnotationValue;
import org.jboss.jandex.DotName;
import org.jboss.protean.gizmo.ClassCreator;
import org.jboss.protean.gizmo.ClassOutput;
import org.jboss.protean.gizmo.FieldCreator;
import org.jboss.protean.gizmo.FieldDescriptor;
import org.jboss.protean.gizmo.MethodCreator;
import org.jboss.protean.gizmo.MethodDescriptor;
import org.jboss.protean.gizmo.ResultHandle;
import org.jboss.shamrock.deployment.ArchiveContext;
import org.jboss.shamrock.deployment.BeanArchiveIndex;
import org.jboss.shamrock.deployment.BeanDeployment;
import org.jboss.shamrock.deployment.ProcessorContext;
import org.jboss.shamrock.deployment.ResourceProcessor;
import org.jboss.shamrock.deployment.RuntimePriority;
import org.jboss.shamrock.deployment.codegen.BytecodeRecorder;
import org.jboss.shamrock.jpa.runtime.JPADeploymentTemplate;
import org.jboss.shamrock.jpa.runtime.cdi.SystemEntityManager;
import org.jboss.shamrock.jpa.runtime.cdi.TransactionScopedEntityManager;
public class HibernateCdiResourceProcessor implements ResourceProcessor {
@@ -36,8 +50,12 @@ public class HibernateCdiResourceProcessor implements ResourceProcessor {
@Inject
private BeanDeployment beanDeployment;
@Inject
BeanArchiveIndex beanArchiveIndex;
@Override
public void process(ArchiveContext archiveContext, ProcessorContext processorContext) throws Exception {
Set<String> knownUnitNames = new HashSet<>();
Set<String> knownContextNames = new HashSet<>();
scanForAnnotations(archiveContext, knownUnitNames, PERSISTENCE_UNIT);
@@ -45,25 +63,26 @@ public class HibernateCdiResourceProcessor implements ResourceProcessor {
knownUnitNames.remove(""); //TODO: support for the default PU
//now create producer beans for all of the above unit names
//this is not great, we really need a better way to do this than generating bytecode
for (String name : knownUnitNames) {
Set<String> allKnownNames = new HashSet<>(knownUnitNames);
allKnownNames.addAll(knownContextNames);
for (String name : allKnownNames) {
String className = getClass().getName() + "$$EMFProducer-" + name;
AtomicReference<byte[]> bytes = new AtomicReference<>();
try (ClassCreator creator = new ClassCreator(new ClassOutput() {
@Override
public void write(String name, byte[] data) {
try {
bytes.set(data);
processorContext.addGeneratedClass(true, name, data);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}, className, null, Object.class.getName())) {
try (ClassCreator creator = new ClassCreator(new InMemoryClassOutput(bytes, processorContext), className, null, Object.class.getName())) {
creator.addAnnotation(Dependent.class);
MethodCreator producer = creator.getMethodCreator("producerMethod", EntityManagerFactory.class);
producer.addAnnotation(Produces.class);
producer.addAnnotation(ApplicationScoped.class);
if (!knownUnitNames.contains(name)) {
//there was no @PersistenceUnit producer with this name
//this means that we still need it, but the user would not be expecting a bean to be registered
//we register an artificial qualifier that we will use for the managed persistence contexts
producer.addAnnotation(SystemEntityManager.class);
}
ResultHandle ret = producer.invokeStaticMethod(MethodDescriptor.ofMethod(Persistence.class, "createEntityManagerFactory", EntityManagerFactory.class, String.class), producer.load(name));
producer.returnValue(ret);
@@ -72,25 +91,117 @@ public class HibernateCdiResourceProcessor implements ResourceProcessor {
}
try(BytecodeRecorder recorder = processorContext.addDeploymentTask(RuntimePriority.BOOTSTRAP_EMF)) {
JPADeploymentTemplate template = recorder.getRecordingProxy(JPADeploymentTemplate.class);
for (String name : knownContextNames) {
String className = getClass().getName() + "$$EMProducer-" + name;
AtomicReference<byte[]> bytes = new AtomicReference<>();
//we need to know if transactions are present or not
//TODO: this should be based on if a PU is JTA enabled or not
if (processorContext.isCapabilityPresent("transactions")) {
boolean system = false;
try (ClassCreator creator = new ClassCreator(new InMemoryClassOutput(bytes, processorContext), className, null, Object.class.getName())) {
creator.addAnnotation(Dependent.class);
FieldCreator emfField = creator.getFieldCreator("emf", EntityManagerFactory.class);
emfField.addAnnotation(Inject.class);
if (!knownUnitNames.contains(name)) {
emfField.addAnnotation(SystemEntityManager.class);
system = true;
}
FieldDescriptor emf = emfField.getFieldDescriptor();
FieldCreator tsrField = creator.getFieldCreator("tsr", TransactionSynchronizationRegistry.class);
tsrField.addAnnotation(Inject.class);
FieldDescriptor tsr = tsrField.getFieldDescriptor();
FieldCreator tmField = creator.getFieldCreator("tm", TransactionManager.class);
tmField.addAnnotation(Inject.class);
FieldDescriptor tm = tmField.getFieldDescriptor();
MethodCreator producer = creator.getMethodCreator("producerMethod", EntityManager.class);
producer.addAnnotation(Produces.class);
producer.addAnnotation(RequestScoped.class);
ResultHandle emfRh = producer.readInstanceField(emf, producer.getThis());
ResultHandle tsrRh = producer.readInstanceField(tsr, producer.getThis());
ResultHandle tmRh = producer.readInstanceField(tm, producer.getThis());
producer.returnValue(producer.newInstance(MethodDescriptor.ofConstructor(TransactionScopedEntityManager.class, TransactionManager.class, TransactionSynchronizationRegistry.class, EntityManagerFactory.class), tmRh, tsrRh, emfRh));
MethodCreator disposer = creator.getMethodCreator("disposerMethod", void.class, EntityManager.class);
disposer.getParameterAnnotations(0).addAnnotation(Disposes.class);
disposer.invokeVirtualMethod(MethodDescriptor.ofMethod(TransactionScopedEntityManager.class, "requestDone", void.class), disposer.getMethodParam(0));
disposer.returnValue(null);
}
beanDeployment.addGeneratedBean(className, bytes.get());
template.boostrapPu(null, system);
} else {
boolean system = false;
//if there is no TX support then we just use a super simple approach, and produce a normal EM
try (ClassCreator creator = new ClassCreator(new InMemoryClassOutput(bytes, processorContext), className, null, Object.class.getName())) {
creator.addAnnotation(Dependent.class);
FieldCreator emfField = creator.getFieldCreator("emf", EntityManagerFactory.class);
emfField.addAnnotation(Inject.class);
if (!knownUnitNames.contains(name)) {
emfField.addAnnotation(SystemEntityManager.class);
system = true;
}
FieldDescriptor emf = emfField.getFieldDescriptor();
MethodCreator producer = creator.getMethodCreator("producerMethod", EntityManager.class);
producer.addAnnotation(Produces.class);
producer.addAnnotation(Dependent.class);
ResultHandle factory = producer.readInstanceField(emf, producer.getThis());
producer.returnValue(producer.invokeInterfaceMethod(MethodDescriptor.ofMethod(EntityManagerFactory.class, "createEntityManager", EntityManager.class), factory));
MethodCreator disposer = creator.getMethodCreator("disposerMethod", void.class, EntityManager.class);
disposer.getParameterAnnotations(0).addAnnotation(Disposes.class);
disposer.invokeInterfaceMethod(MethodDescriptor.ofMethod(EntityManager.class, "close", void.class), disposer.getMethodParam(0));
disposer.returnValue(null);
}
beanDeployment.addGeneratedBean(className, bytes.get());
template.boostrapPu(null, system);
}
}
}
}
private void scanForAnnotations(ArchiveContext archiveContext, Set<String> knownUnitNames, DotName nm) {
for (AnnotationInstance anno : archiveContext.getCombinedIndex().getAnnotations(nm)) {
AnnotationValue unitName = anno.value("unitName");
if(unitName == null) {
continue;
}
if (anno.target().kind() == AnnotationTarget.Kind.METHOD) {
if (anno.target().asMethod().hasAnnotation(PRODUCES)) {
knownUnitNames.add(anno.value("unitName").asString());
knownUnitNames.add(unitName.asString());
}
} else if (anno.target().kind() == AnnotationTarget.Kind.FIELD) {
for (AnnotationInstance i : anno.target().asField().annotations()) {
if (i.name().equals(PRODUCES)) {
knownUnitNames.add(anno.value("unitName").asString());
knownUnitNames.add(unitName.asString());
break;
}
}
} else if (anno.target().kind() == AnnotationTarget.Kind.CLASS) {
for (AnnotationInstance i : anno.target().asClass().classAnnotations()) {
if (i.name().equals(PRODUCES)) {
knownUnitNames.add(anno.value("unitName").asString());
knownUnitNames.add(unitName.asString());
break;
}
}
@@ -100,6 +211,26 @@ public class HibernateCdiResourceProcessor implements ResourceProcessor {
@Override
public int getPriority() {
return 0;
return 100;
}
private static class InMemoryClassOutput implements ClassOutput {
private final AtomicReference<byte[]> bytes;
private final ProcessorContext processorContext;
public InMemoryClassOutput(AtomicReference<byte[]> bytes, ProcessorContext processorContext) {
this.bytes = bytes;
this.processorContext = processorContext;
}
@Override
public void write(String name, byte[] data) {
try {
bytes.set(data);
processorContext.addGeneratedClass(true, name, data);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}

View File

@@ -0,0 +1,42 @@
package org.jboss.shamrock.jpa;
import java.io.FileInputStream;
import java.net.URL;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.hibernate.hql.internal.ast.tree.Node;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.Index;
import org.jboss.jandex.Indexer;
import org.junit.Ignore;
import org.junit.Test;
//not a real test, but you can use to to
//get all not implementation that need to be added for reflection
@Ignore
public class HqlNodeScannerTestCase {
@Test
public void generateAllNodes() throws Exception {
URL url = Node.class.getResource("Node.class");
String jar = url.getPath().substring(5, url.getPath().lastIndexOf("!"));
System.out.println(jar);
Indexer indexer = new Indexer();
try (ZipInputStream in = new ZipInputStream(new FileInputStream(jar))) {
ZipEntry e = in.getNextEntry();
while (e != null) {
if (e.getName().endsWith(".class")) {
indexer.index(in);
}
e = in.getNextEntry();
}
}
Index index = indexer.complete();
for (ClassInfo i : index.getAllKnownSubclasses(DotName.createSimple(Node.class.getName()))) {
System.out.println("simpleConstructor(" + i.name() + ".class);");
}
}
}

View File

@@ -1,25 +0,0 @@
package org.jboss.shamrock.jpa;
import org.hibernate.protean.Hibernate;
import java.util.ArrayList;
import java.util.List;
/**
* @author Emmanuel Bernard emmanuel@hibernate.org
*/
public class JPADeploymentTemplate {
private List<String> entities = new ArrayList<>();
public void addEntity(String entityClass) {
entities.add(entityClass);
}
public void enlistPersistenceUnit() {
System.out.println("List of entities found by Shamrock deployment \n" + entities.toString());
}
public void callHibernateFeatureInit() {
Hibernate.featureInit();
}
}

View File

@@ -0,0 +1,48 @@
package org.jboss.shamrock.jpa.runtime;
import org.hibernate.protean.Hibernate;
import org.jboss.shamrock.jpa.runtime.cdi.SystemEntityManager;
import org.jboss.shamrock.runtime.BeanContainer;
import org.jboss.shamrock.runtime.ContextObject;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
import javax.enterprise.util.AnnotationLiteral;
import javax.persistence.EntityManagerFactory;
/**
* @author Emmanuel Bernard emmanuel@hibernate.org
*/
public class JPADeploymentTemplate {
private List<String> entities = new ArrayList<>();
public void addEntity(String entityClass) {
entities.add(entityClass);
}
public void enlistPersistenceUnit() {
System.out.println("List of entities found by Shamrock deployment \n" + entities.toString());
}
public void callHibernateFeatureInit() {
Hibernate.featureInit();
}
public void boostrapPu(@ContextObject("bean.container") BeanContainer beanContainer, boolean synthetic) {
//TODO: we need to take qualifiers into account, at the moment we can only have one EM, but this is probably fine for the PoC
if(synthetic) {
beanContainer.instance(EntityManagerFactory.class, new AnnotationLiteral<SystemEntityManager>() {
@Override
public Class<? extends Annotation> annotationType() {
return SystemEntityManager.class;
}
}).getProperties();
} else {
beanContainer.instance(EntityManagerFactory.class).getProperties();
}
}
}

View File

@@ -0,0 +1,11 @@
package org.jboss.shamrock.jpa.runtime.cdi;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.inject.Qualifier;
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface SystemEntityManager {
}

View File

@@ -0,0 +1,460 @@
package org.jboss.shamrock.jpa.runtime.cdi;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityGraph;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.Query;
import javax.persistence.StoredProcedureQuery;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaDelete;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.CriteriaUpdate;
import javax.persistence.metamodel.Metamodel;
import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.TransactionManager;
import javax.transaction.TransactionSynchronizationRegistry;
public class TransactionScopedEntityManager implements EntityManager {
private final TransactionManager transactionManager;
private final TransactionSynchronizationRegistry tsr;
private final EntityManagerFactory emf;
private static final Object transactionKey = new Object();
private EntityManager fallbackEntityManager;
public TransactionScopedEntityManager(TransactionManager transactionManager, TransactionSynchronizationRegistry tsr, EntityManagerFactory emf) {
this.transactionManager = transactionManager;
this.tsr = tsr;
this.emf = emf;
}
public void requestDone() {
if(fallbackEntityManager != null) {
fallbackEntityManager.close();
}
}
EntityManagerResult getEntityManager() {
if (isInTransaction()) {
EntityManager em = (EntityManager) tsr.getResource(transactionKey);
if (em != null) {
return new EntityManagerResult(em, false);
}
EntityManager newEm = emf.createEntityManager();
tsr.putResource(transactionKey, newEm);
tsr.registerInterposedSynchronization(new Synchronization() {
@Override
public void beforeCompletion() {
newEm.flush();
newEm.close();
}
@Override
public void afterCompletion(int i) {
}
});
return new EntityManagerResult(newEm, false);
} else {
if(fallbackEntityManager == null) {
fallbackEntityManager = emf.createEntityManager();
}
return new EntityManagerResult(emf.createEntityManager(), false);
}
}
private boolean isInTransaction() {
try {
switch (transactionManager.getStatus()) {
case Status.STATUS_ACTIVE:
case Status.STATUS_COMMITTING:
case Status.STATUS_MARKED_ROLLBACK:
case Status.STATUS_PREPARED:
case Status.STATUS_PREPARING:
return true;
default:
return false;
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void persist(Object entity) {
try (EntityManagerResult emr = getEntityManager()) {
emr.em.persist(entity);
}
}
@Override
public <T> T merge(T entity) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.merge(entity);
}
}
@Override
public void remove(Object entity) {
try (EntityManagerResult emr = getEntityManager()) {
emr.em.remove(entity);
}
}
@Override
public <T> T find(Class<T> entityClass, Object primaryKey) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.find(entityClass, primaryKey);
}
}
@Override
public <T> T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.find(entityClass, primaryKey, properties);
}
}
@Override
public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.find(entityClass, primaryKey, lockMode);
}
}
@Override
public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode, Map<String, Object> properties) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.find(entityClass, primaryKey, lockMode, properties);
}
}
@Override
public <T> T getReference(Class<T> entityClass, Object primaryKey) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.getReference(entityClass, primaryKey);
}
}
@Override
public void flush() {
try (EntityManagerResult emr = getEntityManager()) {
emr.em.flush();
}
}
@Override
public void setFlushMode(FlushModeType flushMode) {
try (EntityManagerResult emr = getEntityManager()) {
emr.em.setFlushMode(flushMode);
}
}
@Override
public FlushModeType getFlushMode() {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.getFlushMode();
}
}
@Override
public void lock(Object entity, LockModeType lockMode) {
try (EntityManagerResult emr = getEntityManager()) {
emr.em.lock(entity, lockMode);
}
}
@Override
public void lock(Object entity, LockModeType lockMode, Map<String, Object> properties) {
try (EntityManagerResult emr = getEntityManager()) {
emr.em.lock(entity, lockMode, properties);
}
}
@Override
public void refresh(Object entity) {
try (EntityManagerResult emr = getEntityManager()) {
emr.em.refresh(entity);
}
}
@Override
public void refresh(Object entity, Map<String, Object> properties) {
try (EntityManagerResult emr = getEntityManager()) {
emr.em.refresh(entity, properties);
}
}
@Override
public void refresh(Object entity, LockModeType lockMode) {
try (EntityManagerResult emr = getEntityManager()) {
emr.em.refresh(entity, lockMode);
}
}
@Override
public void refresh(Object entity, LockModeType lockMode, Map<String, Object> properties) {
try (EntityManagerResult emr = getEntityManager()) {
emr.em.refresh(entity, lockMode, properties);
}
}
@Override
public void clear() {
try (EntityManagerResult emr = getEntityManager()) {
emr.em.clear();
}
}
@Override
public void detach(Object entity) {
try (EntityManagerResult emr = getEntityManager()) {
emr.em.detach(entity);
}
}
@Override
public boolean contains(Object entity) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.contains(entity);
}
}
@Override
public LockModeType getLockMode(Object entity) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.getLockMode(entity);
}
}
@Override
public void setProperty(String propertyName, Object value) {
try (EntityManagerResult emr = getEntityManager()) {
emr.em.setProperty(propertyName, value);
}
}
@Override
public Map<String, Object> getProperties() {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.getProperties();
}
}
@Override
public Query createQuery(String qlString) {
//TODO: this needs some thought for how it works outside a tx
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.createQuery(qlString);
}
}
@Override
public <T> TypedQuery<T> createQuery(CriteriaQuery<T> criteriaQuery) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.createQuery(criteriaQuery);
}
}
@Override
public Query createQuery(CriteriaUpdate updateQuery) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.createQuery(updateQuery);
}
}
@Override
public Query createQuery(CriteriaDelete deleteQuery) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.createQuery(deleteQuery);
}
}
@Override
public <T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.createQuery(qlString, resultClass);
}
}
@Override
public Query createNamedQuery(String name) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.createNamedQuery(name);
}
}
@Override
public <T> TypedQuery<T> createNamedQuery(String name, Class<T> resultClass) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.createNamedQuery(name, resultClass);
}
}
@Override
public Query createNativeQuery(String sqlString) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.createNativeQuery(sqlString);
}
}
@Override
public Query createNativeQuery(String sqlString, Class resultClass) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.createNativeQuery(sqlString, resultClass);
}
}
@Override
public Query createNativeQuery(String sqlString, String resultSetMapping) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.createNativeQuery(sqlString, resultSetMapping);
}
}
@Override
public StoredProcedureQuery createNamedStoredProcedureQuery(String name) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.createNamedStoredProcedureQuery(name);
}
}
@Override
public StoredProcedureQuery createStoredProcedureQuery(String procedureName) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.createStoredProcedureQuery(procedureName);
}
}
@Override
public StoredProcedureQuery createStoredProcedureQuery(String procedureName, Class... resultClasses) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.createStoredProcedureQuery(procedureName, resultClasses);
}
}
@Override
public StoredProcedureQuery createStoredProcedureQuery(String procedureName, String... resultSetMappings) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.createStoredProcedureQuery(procedureName, resultSetMappings);
}
}
@Override
public void joinTransaction() {
try (EntityManagerResult emr = getEntityManager()) {
emr.em.joinTransaction();
}
}
@Override
public boolean isJoinedToTransaction() {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.isJoinedToTransaction();
}
}
@Override
public <T> T unwrap(Class<T> cls) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.unwrap(cls);
}
}
@Override
public Object getDelegate() {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.getDelegate();
}
}
@Override
public void close() {
throw new IllegalStateException("Not supported for transaction scoped entity managers");
}
@Override
public boolean isOpen() {
return true;
}
@Override
public EntityTransaction getTransaction() {
throw new IllegalStateException("Not supported for JTA entity managers");
}
@Override
public EntityManagerFactory getEntityManagerFactory() {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.getEntityManagerFactory();
}
}
@Override
public CriteriaBuilder getCriteriaBuilder() {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.getCriteriaBuilder();
}
}
@Override
public Metamodel getMetamodel() {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.getMetamodel();
}
}
@Override
public <T> EntityGraph<T> createEntityGraph(Class<T> rootType) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.createEntityGraph(rootType);
}
}
@Override
public EntityGraph<?> createEntityGraph(String graphName) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.createEntityGraph(graphName);
}
}
@Override
public EntityGraph<?> getEntityGraph(String graphName) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.getEntityGraph(graphName);
}
}
@Override
public <T> List<EntityGraph<? super T>> getEntityGraphs(Class<T> entityClass) {
try (EntityManagerResult emr = getEntityManager()) {
return emr.em.getEntityGraphs(entityClass);
}
}
static class EntityManagerResult implements AutoCloseable {
private final EntityManager em;
private final boolean closeOnEnd;
EntityManagerResult(EntityManager em, boolean closeOnEnd) {
this.em = em;
this.closeOnEnd = closeOnEnd;
}
@Override
public void close() {
if (closeOnEnd) {
em.close();
}
}
}
}

View File

@@ -17,6 +17,7 @@ public class ShamrockTest extends BlockJUnit4ClassRunner {
private static boolean first = true;
private static boolean started = false;
private static boolean failed = false;
/**
* Creates a BlockJUnit4ClassRunner to run {@code klass}
@@ -42,19 +43,29 @@ public class ShamrockTest extends BlockJUnit4ClassRunner {
try {
notifier.addListener(new RunListener() {
@Override
public void testStarted(Description description) {
if (failed) {
notifier.fireTestFailure(new Failure(description, new AssertionError("Startup failed")));
return;
}
if (!started) {
started = true;
//TODO: so much hacks...
Class<?> theClass = description.getTestClass();
String classFileName = theClass.getName().replace(".", "/") + ".class";
URL resource = theClass.getClassLoader().getResource(classFileName);
String testClassLocation = resource.getPath().substring(0, resource.getPath().length() - classFileName.length());
String appClassLocation = testClassLocation.replace("test-classes", "classes");
Path appRoot = Paths.get(appClassLocation);
RuntimeRunner runtimeRunner = new RuntimeRunner(getClass().getClassLoader(), appRoot, Paths.get(testClassLocation), new ArchiveContextBuilder());
runtimeRunner.run();
try {
Class<?> theClass = description.getTestClass();
String classFileName = theClass.getName().replace(".", "/") + ".class";
URL resource = theClass.getClassLoader().getResource(classFileName);
String testClassLocation = resource.getPath().substring(0, resource.getPath().length() - classFileName.length());
String appClassLocation = testClassLocation.replace("test-classes", "classes");
Path appRoot = Paths.get(appClassLocation);
RuntimeRunner runtimeRunner = new RuntimeRunner(getClass().getClassLoader(), appRoot, Paths.get(testClassLocation), new ArchiveContextBuilder());
runtimeRunner.run();
} catch (RuntimeException e) {
failed = true;
throw e;
}
}
}
});

View File

@@ -6,6 +6,7 @@ import org.jboss.shamrock.deployment.ShamrockSetup;
public class TransactionsSetup implements ShamrockSetup {
@Override
public void setup(SetupContext context) {
context.addCapability("transactions");
context.addResourceProcessor(new TransactionsProcessor());
}
}