Skip to content

Commit

Permalink
Allow injection of EMF into CDI beans
Browse files Browse the repository at this point in the history
  • Loading branch information
stuartwdouglas committed Sep 18, 2018
1 parent 76f9126 commit ae4e508
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 92 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.jboss.shamrock.example.jpa;

import javax.inject.Inject;
import javax.persistence.*;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
Expand All @@ -22,6 +23,9 @@
@WebServlet(name = "JPATestBootstrapEndpoint", urlPatterns = "/jpa/testbootstrap")
public class JPATestBootstrapEndpoint extends HttpServlet {

@Inject
private EntityManagerFactory entityManagerFactory;

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
try {
Expand All @@ -37,12 +41,7 @@ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IO


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

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.jboss.shamrock.example.jpa;

import javax.enterprise.inject.Produces;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;

public class JpaProducer {

@Produces
@PersistenceUnit(unitName = "templatePU")
EntityManagerFactory emf;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.jboss.shamrock.example.test;

import org.jboss.shamrock.junit.GraalTest;
import org.junit.runner.RunWith;


@RunWith(GraalTest.class)
public class JPABootstrapITCase extends JPABootstrapTestCase {

}
Original file line number Diff line number Diff line change
@@ -1,22 +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.jboss.shamrock.junit.ShamrockTest;
import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.assertEquals;

/**
* Test reflection around JPA entities
*
* @author Emmanuel Bernard [email protected]
*/
@RunWith(GraalTest.class)
public class JPABootstrapInGraalITCase {
@RunWith(ShamrockTest.class)
public class JPABootstrapTestCase {

@Test
public void testFieldAndGetterReflectionOnEntityFromServlet() throws Exception {
public void testJpaBootstrap() throws Exception {
assertEquals("OK", URLTester.relative("jpa/testbootstrap").invokeURL().asString());
}

Expand Down

This file was deleted.

4 changes: 4 additions & 0 deletions jpa/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
<groupId>org.jboss.shamrock</groupId>
<artifactId>shamrock-jpa-runtime</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.shamrock</groupId>
<artifactId>shamrock-transactions-deployment</artifactId>
</dependency>

<dependency>
<groupId>junit</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ public void process(final ArchiveContext archiveContext, final ProcessorContext
//Modify the bytecode of all entities to enable lazy-loading, dirty checking, etc..
enhanceEntities(domainObjects, archiveContext, processorContext);




}

private void enhanceEntities(final KnownDomainObjects domainObjects, ArchiveContext archiveContext, ProcessorContext processorContext) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

import org.jboss.shamrock.deployment.SetupContext;
import org.jboss.shamrock.deployment.ShamrockSetup;
import org.jboss.shamrock.jpa.cdi.HibernateCdiResourceProcessor;

public class JpaSetup implements ShamrockSetup {
@Override
public void setup(SetupContext context) {
context.addResourceProcessor(new HibernateResourceProcessor());
context.addResourceProcessor(new HibernateCdiResourceProcessor());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package org.jboss.shamrock.jpa.cdi;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;

import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationTarget;
import org.jboss.jandex.DotName;
import org.jboss.protean.gizmo.ClassCreator;
import org.jboss.protean.gizmo.ClassOutput;
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.BeanDeployment;
import org.jboss.shamrock.deployment.ProcessorContext;
import org.jboss.shamrock.deployment.ResourceProcessor;

public class HibernateCdiResourceProcessor implements ResourceProcessor {

private static final DotName PERSISTENCE_CONTEXT = DotName.createSimple(PersistenceContext.class.getName());
private static final DotName PERSISTENCE_UNIT = DotName.createSimple(PersistenceUnit.class.getName());
private static final DotName PRODUCES = DotName.createSimple(Produces.class.getName());

@Inject
private BeanDeployment beanDeployment;

@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);
scanForAnnotations(archiveContext, knownContextNames, PERSISTENCE_CONTEXT);
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) {
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())) {

creator.addAnnotation(Dependent.class);
MethodCreator producer = creator.getMethodCreator("producerMethod", EntityManagerFactory.class);
producer.addAnnotation(Produces.class);
producer.addAnnotation(ApplicationScoped.class);

ResultHandle ret = producer.invokeStaticMethod(MethodDescriptor.ofMethod(Persistence.class, "createEntityManagerFactory", EntityManagerFactory.class, String.class), producer.load(name));
producer.returnValue(ret);
}
beanDeployment.addGeneratedBean(className, bytes.get());
}


}

private void scanForAnnotations(ArchiveContext archiveContext, Set<String> knownUnitNames, DotName nm) {
for (AnnotationInstance anno : archiveContext.getCombinedIndex().getAnnotations(nm)) {
if (anno.target().kind() == AnnotationTarget.Kind.METHOD) {
if (anno.target().asMethod().hasAnnotation(PRODUCES)) {
knownUnitNames.add(anno.value("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());
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());
break;
}
}
}
}
}

@Override
public int getPriority() {
return 0;
}
}

0 comments on commit ae4e508

Please sign in to comment.