diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/registry/classloading/HibernateCallbacksTestAction.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/registry/classloading/HibernateCallbacksTestAction.java new file mode 100644 index 0000000000..45143e11fb --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/registry/classloading/HibernateCallbacksTestAction.java @@ -0,0 +1,53 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.orm.test.bootstrap.registry.classloading; + +import java.util.Collections; +import java.util.List; + +import jakarta.persistence.Entity; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.Id; +import jakarta.persistence.PrePersist; +import jakarta.persistence.Transient; + +/** + * A test scenario to be used with {@link HibernateClassLoaderLeaksTest}; + * the crucial aspect is that we're triggering a lookup of a JPA callback + * method. + */ +public class HibernateCallbacksTestAction extends HibernateLoadingTestAction { + + protected void actionOnHibernate(EntityManagerFactory emf) { + try (final EntityManager entityManager = emf.createEntityManager() ) { + Booking b = new Booking(); + b.id = Long.valueOf( 1l ); + entityManager.persist( b ); //to trigger the @PrePersist invocation + } + } + + protected List getManagedClassNames() { + return Collections.singletonList( Booking.class.getName() ); + } + + @Entity(name = "booking") + private static class Booking { + @Id Long id; + @Transient String legacyIdentifier; + + @PrePersist + public void computeLegacyIdentifier() { + //Details are not important, just making something up. + if ( legacyIdentifier == null && id != null ) { + this.legacyIdentifier = id.toString(); + } + } + + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/registry/classloading/HibernateClassLoaderLeaksTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/registry/classloading/HibernateClassLoaderLeaksTest.java index fe13eab671..2b915d02b5 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/registry/classloading/HibernateClassLoaderLeaksTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/registry/classloading/HibernateClassLoaderLeaksTest.java @@ -58,6 +58,11 @@ public void hibernateDoesNotLeakClassloader() { ClassLoaderLeakDetector.assertNotLeakingAction( HibernateLoadingTestAction.class.getName() ); } + @Test + public void hibernateDoesNotLeakClassloaderWithCallbacks() { + ClassLoaderLeakDetector.assertNotLeakingAction( HibernateCallbacksTestAction.class.getName() ); + } + private static void cleanup(Driver driver) { System.out.println( "Attempting de-registration of driver: " + driver ); try { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/registry/classloading/HibernateLoadingTestAction.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/registry/classloading/HibernateLoadingTestAction.java index 44729b558e..23341b0e33 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/registry/classloading/HibernateLoadingTestAction.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/registry/classloading/HibernateLoadingTestAction.java @@ -9,9 +9,12 @@ import java.sql.Driver; import java.sql.DriverManager; import java.sql.SQLException; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; +import org.hibernate.SessionFactory; import org.hibernate.jpa.boot.spi.Bootstrap; import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; @@ -22,25 +25,50 @@ * this is meant to test against classloader leaks, so needs * to be packaged as a Runnable rather than using our usual * testing facilities. + * @see HibernateClassLoaderLeaksTest */ public class HibernateLoadingTestAction extends NotLeakingTestAction implements Runnable { @Override - public void run() { + public final void run() { super.run(); //for basic sanity self-check final Map config = new HashMap(); EntityManagerFactory emf = Bootstrap.getEntityManagerFactoryBuilder( - new BaseEntityManagerFunctionalTestCase.TestingPersistenceUnitDescriptorImpl( getClass().getSimpleName() ), + new BaseEntityManagerFunctionalTestCase.TestingPersistenceUnitDescriptorImpl( getClass().getSimpleName() ) { + @Override + public boolean isExcludeUnlistedClasses() { + return true; + } + + @Override + public List getManagedClassNames() { + return HibernateLoadingTestAction.this.getManagedClassNames(); + } + }, config ).build(); try { - emf.close(); + checkExpectedClassLoader( emf.unwrap( SessionFactory.class ).getClass() ); + actionOnHibernate( emf ); } finally { - cleanupJDBCDrivers(); + try { + emf.close(); + } + finally { + cleanupJDBCDrivers(); + } } } + protected void actionOnHibernate(EntityManagerFactory emf) { + //no-op + } + + protected List getManagedClassNames() { + return Collections.emptyList(); + } + private void cleanupJDBCDrivers() { DriverManager.drivers().forEach( this::deregister ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/registry/classloading/NotLeakingTestAction.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/registry/classloading/NotLeakingTestAction.java index 66ed653243..9baa861999 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/registry/classloading/NotLeakingTestAction.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/registry/classloading/NotLeakingTestAction.java @@ -14,7 +14,11 @@ public class NotLeakingTestAction implements Runnable { @Override public void run() { - final ClassLoader owningClassloader = getClass().getClassLoader(); + checkExpectedClassLoader( getClass() ); + } + + protected void checkExpectedClassLoader(Class aClass) { + final ClassLoader owningClassloader = aClass.getClassLoader(); if ( !owningClassloader.getName().equals( "TestIsolatedIsolatedClassLoader" ) ) { throw new IllegalStateException( "Not being loaded by the expected classloader" ); }