mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-08 20:24:46 +00:00
HHH-17240 Make ClassTransformer enhancement thread safe
This commit is contained in:
parent
884e1b1b82
commit
3345658d9d
@ -15,6 +15,8 @@
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.hibernate.Version;
|
import org.hibernate.Version;
|
||||||
import org.hibernate.bytecode.enhance.VersionMismatchException;
|
import org.hibernate.bytecode.enhance.VersionMismatchException;
|
||||||
@ -145,12 +147,14 @@ public EnhancerImpl(final EnhancementContext enhancementContext, final ByteBuddy
|
|||||||
public byte[] enhance(String className, byte[] originalBytes) throws EnhancementException {
|
public byte[] enhance(String className, byte[] originalBytes) throws EnhancementException {
|
||||||
//Classpool#describe does not accept '/' in the description name as it expects a class name. See HHH-12545
|
//Classpool#describe does not accept '/' in the description name as it expects a class name. See HHH-12545
|
||||||
final String safeClassName = className.replace( '/', '.' );
|
final String safeClassName = className.replace( '/', '.' );
|
||||||
classFileLocator.setClassNameAndBytes( safeClassName, originalBytes );
|
classFileLocator.registerClassNameAndBytes( safeClassName, originalBytes );
|
||||||
try {
|
try {
|
||||||
final TypeDescription typeDescription = typePool.describe( safeClassName ).resolve();
|
final TypeDescription typeDescription = typePool.describe( safeClassName ).resolve();
|
||||||
|
|
||||||
return byteBuddyState.rewrite( typePool, safeClassName, byteBuddy -> doEnhance(
|
return byteBuddyState.rewrite( typePool, safeClassName, byteBuddy -> doEnhance(
|
||||||
byteBuddy.ignore( isDefaultFinalizer() ).redefine( typeDescription, ClassFileLocator.Simple.of( safeClassName, originalBytes ) ),
|
() -> byteBuddy.ignore( isDefaultFinalizer() )
|
||||||
|
.redefine( typeDescription, ClassFileLocator.Simple.of( safeClassName, originalBytes ) )
|
||||||
|
.annotateType( HIBERNATE_VERSION_ANNOTATION ),
|
||||||
typeDescription
|
typeDescription
|
||||||
) );
|
) );
|
||||||
}
|
}
|
||||||
@ -160,12 +164,15 @@ public byte[] enhance(String className, byte[] originalBytes) throws Enhancement
|
|||||||
catch (RuntimeException e) {
|
catch (RuntimeException e) {
|
||||||
throw new EnhancementException( "Failed to enhance class " + className, e );
|
throw new EnhancementException( "Failed to enhance class " + className, e );
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
classFileLocator.deregisterClassNameAndBytes( safeClassName );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void discoverTypes(String className, byte[] originalBytes) {
|
public void discoverTypes(String className, byte[] originalBytes) {
|
||||||
if ( originalBytes != null ) {
|
if ( originalBytes != null ) {
|
||||||
classFileLocator.setClassNameAndBytes( className, originalBytes );
|
classFileLocator.registerClassNameAndBytes( className, originalBytes );
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
final TypeDescription typeDescription = typePool.describe( className ).resolve();
|
final TypeDescription typeDescription = typePool.describe( className ).resolve();
|
||||||
@ -175,13 +182,16 @@ public void discoverTypes(String className, byte[] originalBytes) {
|
|||||||
catch (RuntimeException e) {
|
catch (RuntimeException e) {
|
||||||
throw new EnhancementException( "Failed to discover types for class " + className, e );
|
throw new EnhancementException( "Failed to discover types for class " + className, e );
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
classFileLocator.deregisterClassNameAndBytes( className );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TypePool buildTypePool(final ClassFileLocator classFileLocator) {
|
private TypePool buildTypePool(final ClassFileLocator classFileLocator) {
|
||||||
return TypePool.Default.WithLazyResolution.of( classFileLocator );
|
return TypePool.Default.WithLazyResolution.of( classFileLocator );
|
||||||
}
|
}
|
||||||
|
|
||||||
private DynamicType.Builder<?> doEnhance(DynamicType.Builder<?> builder, TypeDescription managedCtClass) {
|
private DynamicType.Builder<?> doEnhance(Supplier<DynamicType.Builder<?>> builderSupplier, TypeDescription managedCtClass) {
|
||||||
// can't effectively enhance interfaces
|
// can't effectively enhance interfaces
|
||||||
if ( managedCtClass.isInterface() ) {
|
if ( managedCtClass.isInterface() ) {
|
||||||
log.debugf( "Skipping enhancement of [%s]: it's an interface", managedCtClass.getName() );
|
log.debugf( "Skipping enhancement of [%s]: it's an interface", managedCtClass.getName() );
|
||||||
@ -202,10 +212,9 @@ private DynamicType.Builder<?> doEnhance(DynamicType.Builder<?> builder, TypeDes
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
builder = builder.annotateType( HIBERNATE_VERSION_ANNOTATION );
|
|
||||||
|
|
||||||
if ( enhancementContext.isEntityClass( managedCtClass ) ) {
|
if ( enhancementContext.isEntityClass( managedCtClass ) ) {
|
||||||
log.debugf( "Enhancing [%s] as Entity", managedCtClass.getName() );
|
log.debugf( "Enhancing [%s] as Entity", managedCtClass.getName() );
|
||||||
|
DynamicType.Builder<?> builder = builderSupplier.get();
|
||||||
builder = builder.implement( ManagedEntity.class )
|
builder = builder.implement( ManagedEntity.class )
|
||||||
.defineMethod( EnhancerConstants.ENTITY_INSTANCE_GETTER_NAME, Object.class, Visibility.PUBLIC )
|
.defineMethod( EnhancerConstants.ENTITY_INSTANCE_GETTER_NAME, Object.class, Visibility.PUBLIC )
|
||||||
.intercept( FixedValue.self() );
|
.intercept( FixedValue.self() );
|
||||||
@ -357,6 +366,7 @@ private DynamicType.Builder<?> doEnhance(DynamicType.Builder<?> builder, TypeDes
|
|||||||
else if ( enhancementContext.isCompositeClass( managedCtClass ) ) {
|
else if ( enhancementContext.isCompositeClass( managedCtClass ) ) {
|
||||||
log.debugf( "Enhancing [%s] as Composite", managedCtClass.getName() );
|
log.debugf( "Enhancing [%s] as Composite", managedCtClass.getName() );
|
||||||
|
|
||||||
|
DynamicType.Builder<?> builder = builderSupplier.get();
|
||||||
builder = builder.implement( ManagedComposite.class );
|
builder = builder.implement( ManagedComposite.class );
|
||||||
builder = addInterceptorHandling( builder, managedCtClass );
|
builder = addInterceptorHandling( builder, managedCtClass );
|
||||||
|
|
||||||
@ -390,12 +400,13 @@ else if ( enhancementContext.isCompositeClass( managedCtClass ) ) {
|
|||||||
else if ( enhancementContext.isMappedSuperclassClass( managedCtClass ) ) {
|
else if ( enhancementContext.isMappedSuperclassClass( managedCtClass ) ) {
|
||||||
log.debugf( "Enhancing [%s] as MappedSuperclass", managedCtClass.getName() );
|
log.debugf( "Enhancing [%s] as MappedSuperclass", managedCtClass.getName() );
|
||||||
|
|
||||||
|
DynamicType.Builder<?> builder = builderSupplier.get();
|
||||||
builder = builder.implement( ManagedMappedSuperclass.class );
|
builder = builder.implement( ManagedMappedSuperclass.class );
|
||||||
return createTransformer( managedCtClass ).applyTo( builder );
|
return createTransformer( managedCtClass ).applyTo( builder );
|
||||||
}
|
}
|
||||||
else if ( enhancementContext.doExtendedEnhancement( managedCtClass ) ) {
|
else if ( enhancementContext.doExtendedEnhancement( managedCtClass ) ) {
|
||||||
log.debugf( "Extended enhancement of [%s]", managedCtClass.getName() );
|
log.debugf( "Extended enhancement of [%s]", managedCtClass.getName() );
|
||||||
return createTransformer( managedCtClass ).applyExtended( builder );
|
return createTransformer( managedCtClass ).applyExtended( builderSupplier.get() );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
log.debugf( "Skipping enhancement of [%s]: not entity or composite", managedCtClass.getName() );
|
log.debugf( "Skipping enhancement of [%s]: not entity or composite", managedCtClass.getName() );
|
||||||
@ -634,11 +645,7 @@ else if ( access != null && access.load().value() == AccessType.FIELD ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class EnhancerClassFileLocator extends ClassFileLocator.ForClassLoader {
|
private static class EnhancerClassFileLocator extends ClassFileLocator.ForClassLoader {
|
||||||
|
private final ConcurrentHashMap<String, Resolution> resolutions = new ConcurrentHashMap<>();
|
||||||
// The name of the class to (possibly be) transformed.
|
|
||||||
private String className;
|
|
||||||
// The explicitly resolved Resolution for the class to (possibly be) transformed.
|
|
||||||
private Resolution resolution;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new class file locator for the given class loader.
|
* Creates a new class file locator for the given class loader.
|
||||||
@ -652,7 +659,8 @@ protected EnhancerClassFileLocator(ClassLoader classLoader) {
|
|||||||
@Override
|
@Override
|
||||||
public Resolution locate(String className) throws IOException {
|
public Resolution locate(String className) throws IOException {
|
||||||
assert className != null;
|
assert className != null;
|
||||||
if ( className.equals( this.className ) ) {
|
final Resolution resolution = resolutions.get( className );
|
||||||
|
if ( resolution != null ) {
|
||||||
return resolution;
|
return resolution;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -660,11 +668,14 @@ public Resolution locate(String className) throws IOException {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setClassNameAndBytes(String className, byte[] bytes) {
|
void registerClassNameAndBytes(String className, byte[] bytes) {
|
||||||
assert className != null;
|
assert className != null;
|
||||||
assert bytes != null;
|
assert bytes != null;
|
||||||
this.className = className;
|
resolutions.put( className, new Resolution.Explicit( bytes ) );
|
||||||
this.resolution = new Resolution.Explicit( bytes);
|
}
|
||||||
|
|
||||||
|
void deregisterClassNameAndBytes(String className) {
|
||||||
|
resolutions.remove( className );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user