-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
HHH-16012 - Develop an abstraction for domain model Class refs
- temp ClassLoader work
- Loading branch information
Showing
9 changed files
with
352 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
78 changes: 78 additions & 0 deletions
78
src/test/java/org/hibernate/orm/test/boot/models/source/ClassLoaderAccessTests.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
/* | ||
* 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.boot.models.source; | ||
|
||
import org.hibernate.boot.models.source.internal.hcann.ClassDetailsImpl; | ||
import org.hibernate.boot.models.source.spi.ClassDetails; | ||
import org.hibernate.boot.models.source.spi.ClassDetailsRegistry; | ||
import org.hibernate.boot.models.spi.ModelProcessingContext; | ||
import org.hibernate.boot.registry.BootstrapServiceRegistry; | ||
import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; | ||
import org.hibernate.boot.registry.StandardServiceRegistry; | ||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder; | ||
import org.hibernate.orm.test.boot.models.ModelHelper; | ||
import org.hibernate.orm.test.util.ClassLoaderAccessImpl; | ||
import org.hibernate.orm.test.util.CollectingClassLoaderService; | ||
|
||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
/** | ||
* Assert expectations about {@link Class} references and how they got loaded | ||
* | ||
* @author Steve Ebersole | ||
*/ | ||
public class ClassLoaderAccessTests { | ||
public static final String ENTITY_CLASS_NAME = "org.hibernate.orm.test.boot.models.source.TestEntity"; | ||
|
||
@Test | ||
public void testClassLoaderIsolation() { | ||
final CollectingClassLoaderService classLoaderService = new CollectingClassLoaderService(); | ||
final BootstrapServiceRegistry bootstrapRegistry = new BootstrapServiceRegistryBuilder() | ||
.applyClassLoaderService( classLoaderService ) | ||
.build(); | ||
final StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder( bootstrapRegistry ).build(); | ||
|
||
final ModelProcessingContext processingContext = ModelHelper.buildProcessingContext( serviceRegistry ); | ||
final ClassDetailsRegistry classDetailsRegistry = processingContext.getClassDetailsRegistry(); | ||
|
||
final ClassDetails classDetails = classDetailsRegistry.resolveClassDetails( ENTITY_CLASS_NAME ); | ||
// assert it was handled via the HCANN builder | ||
assertThat( classDetails ).isInstanceOf( ClassDetailsImpl.class ); | ||
|
||
// Currently ORM completely ignores the temp classloader. That manifests here as the entity class being loaded on the "live" class-loader | ||
assertThat( classLoaderService.getCachedClassForName( ENTITY_CLASS_NAME ) ).isNotNull(); | ||
} | ||
|
||
@Test | ||
public void testClassLoaderIsolation2() { | ||
// Unlike `#testClassLoaderIsolation`, here we use a ClassLoaderAccess which incorporates the temp ClassLoader. | ||
|
||
final CollectingClassLoaderService classLoaderService = new CollectingClassLoaderService(); | ||
final BootstrapServiceRegistry bootstrapRegistry = new BootstrapServiceRegistryBuilder() | ||
.applyClassLoaderService( classLoaderService ) | ||
.build(); | ||
final StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder( bootstrapRegistry ).build(); | ||
|
||
final ClassLoader tmpClassLoader = new ClassLoader() {}; | ||
final ClassLoaderAccessImpl classLoaderAccess = new ClassLoaderAccessImpl( tmpClassLoader, classLoaderService ); | ||
|
||
final ModelProcessingContext processingContext = ModelHelper.buildProcessingContext( serviceRegistry, classLoaderAccess ); | ||
final ClassDetailsRegistry classDetailsRegistry = processingContext.getClassDetailsRegistry(); | ||
|
||
final ClassDetails classDetails = classDetailsRegistry.resolveClassDetails( ENTITY_CLASS_NAME ); | ||
// assert it was handled via the HCANN builder | ||
assertThat( classDetails ).isInstanceOf( ClassDetailsImpl.class ); | ||
|
||
// Now, the entity is not loaded into the "live" class-loader | ||
assertThat( classLoaderService.getCachedClassForName( ENTITY_CLASS_NAME ) ).isNull(); | ||
assertThat( classLoaderAccess.getClassesLoadedFromTempClassLoader() ).containsOnly( ENTITY_CLASS_NAME ); | ||
} | ||
|
||
} |
44 changes: 44 additions & 0 deletions
44
src/test/java/org/hibernate/orm/test/boot/models/source/TestEntity.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
/* | ||
* 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.boot.models.source; | ||
|
||
import jakarta.persistence.Basic; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.Id; | ||
|
||
/** | ||
* @author Steve Ebersole | ||
*/ | ||
@Entity | ||
public class TestEntity { | ||
@Id | ||
private Integer id; | ||
@Basic | ||
private String name; | ||
|
||
private TestEntity() { | ||
// for use by Hibernate | ||
} | ||
|
||
public TestEntity(Integer id, String name) { | ||
this.id = id; | ||
this.name = name; | ||
} | ||
|
||
public Integer getId() { | ||
return id; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public void setName(String name) { | ||
this.name = name; | ||
} | ||
} |
100 changes: 100 additions & 0 deletions
100
src/test/java/org/hibernate/orm/test/util/ClassLoaderAccessImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
/* | ||
* 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.util; | ||
|
||
import java.net.URL; | ||
import java.util.Collections; | ||
import java.util.HashSet; | ||
import java.util.Set; | ||
|
||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; | ||
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; | ||
import org.hibernate.boot.spi.ClassLoaderAccess; | ||
|
||
import org.jboss.logging.Logger; | ||
|
||
/** | ||
* Mostly a copy of {@link org.hibernate.boot.internal.ClassLoaderAccessImpl}, just to | ||
* "override" {@link #isSafeClass(String)} | ||
* | ||
* @author Steve Ebersole | ||
*/ | ||
public class ClassLoaderAccessImpl implements ClassLoaderAccess { | ||
private static final Logger log = Logger.getLogger( ClassLoaderAccessImpl.class ); | ||
|
||
private final ClassLoaderService classLoaderService; | ||
private final ClassLoader tempClassLoader; | ||
|
||
private final Set<String> classesLoadedFromTempClassLoader; | ||
|
||
public ClassLoaderAccessImpl(ClassLoader tempClassLoader, ClassLoaderService classLoaderService) { | ||
this.tempClassLoader = tempClassLoader; | ||
this.classLoaderService = classLoaderService; | ||
|
||
this.classesLoadedFromTempClassLoader = tempClassLoader == null | ||
? Collections.emptySet() | ||
: new HashSet<>(); | ||
} | ||
|
||
@Override | ||
@SuppressWarnings("unchecked") | ||
public Class<?> classForName(String name) { | ||
if ( name == null ) { | ||
throw new IllegalArgumentException( "Name of class to load cannot be null" ); | ||
} | ||
|
||
if ( isSafeClass( name ) ) { | ||
return classLoaderService.classForName( name ); | ||
} | ||
else { | ||
log.debugf( "Not known whether passed class name [%s] is safe", name ); | ||
if ( tempClassLoader == null ) { | ||
log.debugf( | ||
"No temp ClassLoader provided; using live ClassLoader " + | ||
"for loading potentially unsafe class : %s", | ||
name | ||
); | ||
return classLoaderService.classForName( name ); | ||
} | ||
else { | ||
log.debugf( | ||
"Temp ClassLoader was provided, so we will use that : %s", | ||
name | ||
); | ||
try { | ||
classesLoadedFromTempClassLoader.add( name ); | ||
return tempClassLoader.loadClass( name ); | ||
} | ||
catch (ClassNotFoundException e) { | ||
throw new ClassLoadingException( name ); | ||
} | ||
} | ||
} | ||
} | ||
|
||
private boolean isSafeClass(String name) { | ||
// classes in any of these packages are safe to load through the "live" ClassLoader | ||
return name.startsWith( "java." ) | ||
|| name.startsWith( "javax." ) | ||
|| name.startsWith( "jakarta." ) | ||
|| ( name.startsWith( "org.hibernate." ) && !name.contains( ".test." ) ); | ||
|
||
} | ||
|
||
public ClassLoader getTempClassLoader() { | ||
return tempClassLoader; | ||
} | ||
|
||
public Set<String> getClassesLoadedFromTempClassLoader() { | ||
return classesLoadedFromTempClassLoader; | ||
} | ||
|
||
@Override | ||
public URL locateResource(String resourceName) { | ||
return classLoaderService.locateResource( resourceName ); | ||
} | ||
} |
Oops, something went wrong.