diff --git a/core/deployment/src/main/java/org/jboss/shamrock/deployment/BuildTimeGenerator.java b/core/deployment/src/main/java/org/jboss/shamrock/deployment/BuildTimeGenerator.java index ad276830a03a7..e7c840262f873 100644 --- a/core/deployment/src/main/java/org/jboss/shamrock/deployment/BuildTimeGenerator.java +++ b/core/deployment/src/main/java/org/jboss/shamrock/deployment/BuildTimeGenerator.java @@ -19,6 +19,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; @@ -175,6 +176,7 @@ private final class ProcessorContextImpl implements ProcessorContext { private final Set resourceBundles = new HashSet<>(); private final Set runtimeInitializedClasses = new HashSet<>(); private final Set> proxyClasses = new HashSet<>(); + private final Map properties = new HashMap<>(); @Override public BytecodeRecorder addStaticInitTask(int priority) { @@ -301,6 +303,16 @@ public boolean isCapabilityPresent(String capability) { return capabilities.contains(capability); } + @Override + public void setProperty(String key, T value) { + properties.put(key, value); + } + + @Override + public T getProperty(String key) { + return (T) properties.get(key); + } + void writeMainClass() throws IOException { diff --git a/core/deployment/src/main/java/org/jboss/shamrock/deployment/ProcessorContext.java b/core/deployment/src/main/java/org/jboss/shamrock/deployment/ProcessorContext.java index ed259223d94fa..e4be9a7225df7 100644 --- a/core/deployment/src/main/java/org/jboss/shamrock/deployment/ProcessorContext.java +++ b/core/deployment/src/main/java/org/jboss/shamrock/deployment/ProcessorContext.java @@ -115,4 +115,8 @@ public interface ProcessorContext { * @return */ boolean isCapabilityPresent(String capability); + + void setProperty(String key, T value); + + T getProperty(String key); } diff --git a/examples/strict/src/test/java/org/jboss/shamrock/example/test/DataSourceTransactionTestCase.java b/examples/strict/src/test/java/org/jboss/shamrock/example/test/DataSourceTransactionTestCase.java index c8e20ce5f5023..390ec3d39c3c6 100644 --- a/examples/strict/src/test/java/org/jboss/shamrock/example/test/DataSourceTransactionTestCase.java +++ b/examples/strict/src/test/java/org/jboss/shamrock/example/test/DataSourceTransactionTestCase.java @@ -12,8 +12,6 @@ public class DataSourceTransactionTestCase { @Test public void testTransactionalAnnotation() { - //TODO: this does not really belong here, but it saves having to set all the DB stuff up again - Assert.assertEquals("PASSED", URLTester.relative("rest/datasource/txninterceptor0").invokeURL().asString()); try { diff --git a/ext/hibernate-protean/hibernate-orm-protean/src/main/java/org/hibernate/protean/impl/FastBootMetadataBuilder.java b/ext/hibernate-protean/hibernate-orm-protean/src/main/java/org/hibernate/protean/impl/FastBootMetadataBuilder.java index da569fd6717fd..6f17fd0690276 100644 --- a/ext/hibernate-protean/hibernate-orm-protean/src/main/java/org/hibernate/protean/impl/FastBootMetadataBuilder.java +++ b/ext/hibernate-protean/hibernate-orm-protean/src/main/java/org/hibernate/protean/impl/FastBootMetadataBuilder.java @@ -119,7 +119,9 @@ class FastBootMetadataBuilder { addPUManagedClassNamesToMetadataSources(persistenceUnit, metadataSources); this.metamodelBuilder = (MetadataBuilderImplementor) metadataSources.getMetadataBuilder( standardServiceRegistry ); - this.metamodelBuilder.applyScanner(scanner); + if( scanner != null ) { + this.metamodelBuilder.applyScanner( scanner ); + } populate( metamodelBuilder, mergedSettings, standardServiceRegistry ); this.managedResources = MetadataBuildingProcess.prepare( diff --git a/ext/hibernate-protean/hibernate-orm-protean/src/main/java/org/hibernate/protean/impl/PersistenceUnitsHolder.java b/ext/hibernate-protean/hibernate-orm-protean/src/main/java/org/hibernate/protean/impl/PersistenceUnitsHolder.java index a47a14039153f..6364fd26d32ac 100644 --- a/ext/hibernate-protean/hibernate-orm-protean/src/main/java/org/hibernate/protean/impl/PersistenceUnitsHolder.java +++ b/ext/hibernate-protean/hibernate-orm-protean/src/main/java/org/hibernate/protean/impl/PersistenceUnitsHolder.java @@ -19,6 +19,15 @@ public final class PersistenceUnitsHolder { private static final Object NO_NAME_TOKEN = new Object(); + /** + * Initialized JPA for use in a native image. This must be called from within a static init method. + * + * In general the parsedPersistenceXmlDescriptors will be provided by caling {@link #loadOriginalXMLParsedDescriptors()}. + * + * The scanner may be null to use to default scanner, or a custom scanner can be used to stop hibernate scanning + * @param parsedPersistenceXmlDescriptors + * @param scanner + */ public static void initializeJpa(List parsedPersistenceXmlDescriptors, Scanner scanner) { final List units = convertPersistenceUnits( parsedPersistenceXmlDescriptors ); final Map metadata = constructMetadataAdvance( parsedPersistenceXmlDescriptors , scanner); diff --git a/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/HibernateResourceProcessor.java b/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/HibernateResourceProcessor.java index f0a8026382479..2ea8cc508da03 100644 --- a/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/HibernateResourceProcessor.java +++ b/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/HibernateResourceProcessor.java @@ -29,10 +29,13 @@ */ public final class HibernateResourceProcessor implements ResourceProcessor { + public static final String PARSED_DESCRIPTORS = HibernateResourceProcessor.class.getPackage().getName() + ".parsedDescriptors"; + @Override public void process(final ArchiveContext archiveContext, final ProcessorContext processorContext) throws Exception { List descriptors = PersistenceUnitsHolder.loadOriginalXMLParsedDescriptors(); + processorContext.setProperty(PARSED_DESCRIPTORS, descriptors); // Hibernate specific reflective classes; these are independent from the model and configuration details. HibernateReflectiveNeeds.registerStaticReflectiveNeeds(processorContext); @@ -43,6 +46,8 @@ 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); + //set up the scanner, as this scanning has already been done we need to just tell it about the classes we + //have discovered. This scanner is bytecode serializable and is passed directly into the template ShamrockScanner scanner = new ShamrockScanner(); Set classDescriptors = new HashSet<>(); for (String i : domainObjects.getClassNames()) { @@ -50,9 +55,9 @@ public void process(final ArchiveContext archiveContext, final ProcessorContext classDescriptors.add(desc); } scanner.setClassDescriptors(classDescriptors); - PersistenceUnitsHolder.initializeJpa(descriptors, scanner); try (BytecodeRecorder recorder = processorContext.addStaticInitTask(RuntimePriority.JPA_DEPLOYMENT)) { + //now we serialize the XML and class list to bytecode, to remove the need to re-parse the XML on JVM startup recorder.registerNonDefaultConstructor(ParsedPersistenceXmlDescriptor.class.getDeclaredConstructor(URL.class), (i) -> Collections.singletonList(i.getPersistenceUnitRootUrl())); recorder.getRecordingProxy(JPADeploymentTemplate.class).initMetadata(descriptors, scanner, null); } diff --git a/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/cdi/HibernateCdiResourceProcessor.java b/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/cdi/HibernateCdiResourceProcessor.java index 1914672e1958c..19ec21e866f05 100644 --- a/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/cdi/HibernateCdiResourceProcessor.java +++ b/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/cdi/HibernateCdiResourceProcessor.java @@ -40,6 +40,7 @@ import org.jboss.shamrock.deployment.ResourceProcessor; import org.jboss.shamrock.deployment.RuntimePriority; import org.jboss.shamrock.deployment.codegen.BytecodeRecorder; +import org.jboss.shamrock.jpa.HibernateResourceProcessor; import org.jboss.shamrock.jpa.runtime.JPADeploymentTemplate; import org.jboss.shamrock.jpa.runtime.cdi.SystemEntityManager; import org.jboss.shamrock.jpa.runtime.cdi.TransactionScopedEntityManager; @@ -67,7 +68,8 @@ public void process(ArchiveContext archiveContext, ProcessorContext processorCon //this is not great, we really need a better way to do this than generating bytecode String defaultName = null; - List pus = PersistenceUnitsHolder.getPersistenceUnitDescriptors(); + List pus = processorContext.getProperty(HibernateResourceProcessor.PARSED_DESCRIPTORS); + //look through the parsed descriptors to see if we can figure out the default PU name if(pus.size() ==1) { defaultName = pus.get(0).getName(); @@ -90,6 +92,7 @@ public void process(ArchiveContext archiveContext, ProcessorContext processorCon try(BytecodeRecorder recorder = processorContext.addDeploymentTask(RuntimePriority.BOOTSTRAP_EMF)) { JPADeploymentTemplate template = recorder.getRecordingProxy(JPADeploymentTemplate.class); + //every persistence unit needs a producer, even if the factory is not injectable for (String name : allKnownNames) { String className = getClass().getName() + "$$EMFProducer-" + name; AtomicReference bytes = new AtomicReference<>(); @@ -113,7 +116,7 @@ public void process(ArchiveContext archiveContext, ProcessorContext processorCon producer.returnValue(ret); } beanDeployment.addGeneratedBean(className, bytes.get()); - template.boostrapPu(null, system); + template.boostrapPu(null, system); //force PU bootstrap at startup } diff --git a/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/runtime/JPADeploymentTemplate.java b/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/runtime/JPADeploymentTemplate.java index 7bb6dddf45229..2e3a7f0047762 100644 --- a/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/runtime/JPADeploymentTemplate.java +++ b/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/runtime/JPADeploymentTemplate.java @@ -53,6 +53,8 @@ public Class annotationType() { public void initMetadata(List parsedPersistenceXmlDescriptors, Scanner scanner, @ContextObject("bean.container") BeanContainer beanContainer) { + //this initializes the JPA metadata, and also sets the datasource if no connection URL has been set and a DataSource + //is available if (beanContainer != null) { BeanContainer.Factory ds = beanContainer.instanceFactory(DataSource.class); if (ds != null) { diff --git a/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/runtime/ShamrockScanner.java b/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/runtime/ShamrockScanner.java index 717ee61e0dbde..bcadd73293591 100644 --- a/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/runtime/ShamrockScanner.java +++ b/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/runtime/ShamrockScanner.java @@ -14,6 +14,9 @@ import org.hibernate.boot.archive.scan.spi.Scanner; import org.hibernate.boot.archive.spi.InputStreamAccess; +/** + * A hard coded scanner. This scanner is serialized to bytecode, and used to avoid scanning on hibernate startup + */ public class ShamrockScanner implements Scanner { private Set classDescriptors;