From c0fa25ade67bc1b783e0a715bbd00497e1f0ad6e Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Fri, 1 Sep 2023 11:38:39 +0200 Subject: [PATCH] HHH-17154 Fix NullPointerException is thrown when constructing EntityManagerFactoryBuilderImpl --- .../internal/bytebuddy/EnhancerImpl.java | 11 ++++-- .../bytecode/enhance/spi/Enhancer.java | 13 ++++++- .../bytecode/spi/ClassTransformer.java | 2 +- .../hibernate/internal/CoreMessageLogger.java | 5 +++ .../EntityManagerFactoryBuilderImpl.java | 34 +++++++++++++++++-- .../EnhancingClassTransformerImpl.java | 4 +-- .../orm/test/bootstrap/BootstrapTest.java | 18 ++++++++++ 7 files changed, 77 insertions(+), 10 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/EnhancerImpl.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/EnhancerImpl.java index c25a62e91beb..b6209fa91877 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/EnhancerImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/EnhancerImpl.java @@ -167,9 +167,14 @@ public void discoverTypes(String className, byte[] originalBytes) { if ( originalBytes != null ) { classFileLocator.setClassNameAndBytes( className, originalBytes ); } - final TypeDescription typeDescription = typePool.describe( className ).resolve(); - enhancementContext.registerDiscoveredType( typeDescription, Type.PersistenceType.ENTITY ); - enhancementContext.discoverCompositeTypes( typeDescription, typePool ); + try { + final TypeDescription typeDescription = typePool.describe( className ).resolve(); + enhancementContext.registerDiscoveredType( typeDescription, Type.PersistenceType.ENTITY ); + enhancementContext.discoverCompositeTypes( typeDescription, typePool ); + } + catch (RuntimeException e) { + throw new EnhancementException( "Failed to discover types for class " + className, e ); + } } private TypePool buildTypePool(final ClassFileLocator classFileLocator) { diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/Enhancer.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/Enhancer.java index 26591dbfe368..cc20b56a7baa 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/Enhancer.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/Enhancer.java @@ -31,5 +31,16 @@ public interface Enhancer { */ byte[] enhance(String className, byte[] originalBytes) throws EnhancementException; - void discoverTypes(String className, byte[] originalBytes); + /** + * Discovers types prior to enhancement. + * + * It is possible to invoke this method concurrently. + * + * @param className The name of the class whose bytecode is being analyzed for type discovery. + * @param originalBytes The class's original (pre-enhancement) byte code + * + * @throws EnhancementException Indicates a problem during type discovery + * @since 6.3 + */ + void discoverTypes(String className, byte[] originalBytes) throws EnhancementException; } diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/spi/ClassTransformer.java b/hibernate-core/src/main/java/org/hibernate/bytecode/spi/ClassTransformer.java index bd6efdc01373..8b2652b13233 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/spi/ClassTransformer.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/spi/ClassTransformer.java @@ -43,5 +43,5 @@ byte[] transform( ProtectionDomain protectionDomain, byte[] classfileBuffer) throws TransformerException; - void discoverTypes(ClassLoader loader, String entityClassName); + void discoverTypes(ClassLoader loader, String className); } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java index 956983adce7d..7a3083b29a05 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java @@ -1861,4 +1861,9 @@ void attemptToAssociateProxyWithTwoOpenSessions( id = 515) HibernateException nullIdentitySelectString(); + @LogMessage(level = WARN) + @Message(value = "Failed to discover types for enhancement from class: %s", + id = 516) + void enhancementDiscoveryFailed(String className, @Cause Throwable cause); + } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java index 98ea663fbec9..1e6f30e8a120 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java @@ -31,6 +31,10 @@ import org.hibernate.boot.cfgxml.spi.CfgXmlAccessService; import org.hibernate.boot.cfgxml.spi.LoadedConfig; import org.hibernate.boot.cfgxml.spi.MappingReference; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmRootEntityType; +import org.hibernate.boot.jaxb.spi.BindableMappingDescriptor; +import org.hibernate.boot.jaxb.spi.Binding; import org.hibernate.boot.model.TypeContributor; import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor; import org.hibernate.boot.model.convert.spi.ConverterDescriptor; @@ -50,6 +54,7 @@ import org.hibernate.boot.spi.SessionFactoryBuilderImplementor; import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext; import org.hibernate.bytecode.enhance.spi.EnhancementContext; +import org.hibernate.bytecode.enhance.spi.EnhancementException; import org.hibernate.bytecode.enhance.spi.UnloadedClass; import org.hibernate.bytecode.enhance.spi.UnloadedField; import org.hibernate.bytecode.spi.ClassTransformer; @@ -347,11 +352,34 @@ private EntityManagerFactoryBuilderImpl( if ( classLoader == null ) { throw persistenceException( "Enhancement requires a temp class loader, but none was given." ); } - for ( PersistentClass entityBinding : metadata.getEntityBindings() ) { - if ( entityBinding.getClassName() != null ) { - classTransformer.discoverTypes( classLoader, entityBinding.getClassName() ); + for ( Binding binding : metadataSources.getXmlBindings() ) { + final BindableMappingDescriptor root = binding.getRoot(); + if ( root instanceof JaxbHbmHibernateMapping ) { + final JaxbHbmHibernateMapping hibernateMapping = (JaxbHbmHibernateMapping) root; + final String packageName = hibernateMapping.getPackage(); + for ( JaxbHbmRootEntityType clazz : hibernateMapping.getClazz() ) { + final String className; + if ( packageName == null || packageName.isEmpty() ) { + className = clazz.getName(); + } + else { + className = packageName + '.' + clazz.getName(); + } + try { + classTransformer.discoverTypes( classLoader, className ); + } + catch (EnhancementException ex) { + LOG.enhancementDiscoveryFailed( className, ex ); + } + } } } + for ( String annotatedClassName : metadataSources.getAnnotatedClassNames() ) { + classTransformer.discoverTypes( classLoader, annotatedClassName ); + } + for ( Class annotatedClass : metadataSources.getAnnotatedClasses() ) { + classTransformer.discoverTypes( classLoader, annotatedClass.getName() ); + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/internal/enhance/EnhancingClassTransformerImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/internal/enhance/EnhancingClassTransformerImpl.java index 5113beed344c..99b119d4082f 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/internal/enhance/EnhancingClassTransformerImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/internal/enhance/EnhancingClassTransformerImpl.java @@ -57,8 +57,8 @@ public byte[] transform( } @Override - public void discoverTypes(ClassLoader loader, String entityClassName) { - getEnhancer( loader ).discoverTypes( entityClassName, null ); + public void discoverTypes(ClassLoader loader, String className) { + getEnhancer( loader ).discoverTypes( className, null ); } private Enhancer getEnhancer(ClassLoader loader) { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/BootstrapTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/BootstrapTest.java index 5755e9d37ae6..0c0199b5d0ae 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/BootstrapTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/BootstrapTest.java @@ -42,11 +42,13 @@ import org.hibernate.jpa.HibernatePersistenceProvider; import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl; import org.hibernate.jpa.boot.internal.PersistenceUnitInfoDescriptor; +import org.hibernate.jpa.boot.spi.EntityManagerFactoryBuilder; import org.hibernate.orm.test.mapping.basic.bitset.BitSetType; import org.hibernate.orm.test.mapping.basic.bitset.BitSetUserType; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.spi.SessionFactoryServiceRegistry; +import org.hibernate.testing.orm.junit.JiraKey; import org.junit.Test; import jakarta.persistence.AttributeConverter; @@ -322,6 +324,22 @@ public void test_bootstrap_bootstrap_native_EntityManagerFactory_example() { } } + @Test + @JiraKey("HHH-17154") + public void build_EntityManagerFactory_with_NewTempClassLoader() { + new EntityManagerFactoryBuilderImpl( + new PersistenceUnitInfoDescriptor( + new PersistenceUnitInfoImpl( "", new ArrayList<>(), new Properties() ) { + @Override + public ClassLoader getNewTempClassLoader() { + return Thread.currentThread().getContextClassLoader(); + } + } + ), + new HashMap<>() + ).cancel(); + } + public Object getBeanManager() { return null; }