HHH-13343 : Bytecode enhancement using ByteBuddy fails when the class is not available from the provided ClassLoader

(cherry picked from commit af3f485193)
This commit is contained in:
Gail Badner 2019-03-27 22:56:07 -07:00 committed by gbadner
parent 374ba35809
commit de09e67872
1 changed files with 39 additions and 11 deletions

View File

@ -7,26 +7,22 @@
package org.hibernate.bytecode.enhance.internal.bytebuddy; package org.hibernate.bytecode.enhance.internal.bytebuddy;
import static net.bytebuddy.matcher.ElementMatchers.isDefaultFinalizer; import static net.bytebuddy.matcher.ElementMatchers.isDefaultFinalizer;
import static net.bytebuddy.matcher.ElementMatchers.isGetter;
import java.io.IOException;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale;
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.Function;
import java.util.stream.Collectors;
import javax.persistence.Access; import javax.persistence.Access;
import javax.persistence.AccessType; import javax.persistence.AccessType;
import javax.persistence.Transient; import javax.persistence.Transient;
import org.hibernate.MappingException;
import org.hibernate.bytecode.enhance.internal.tracker.CompositeOwnerTracker; import org.hibernate.bytecode.enhance.internal.tracker.CompositeOwnerTracker;
import org.hibernate.bytecode.enhance.internal.tracker.DirtyTracker; import org.hibernate.bytecode.enhance.internal.tracker.DirtyTracker;
import org.hibernate.bytecode.enhance.spi.CollectionTracker; import org.hibernate.bytecode.enhance.spi.CollectionTracker;
@ -64,12 +60,10 @@ import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.description.type.TypeDescription.Generic; import net.bytebuddy.description.type.TypeDescription.Generic;
import net.bytebuddy.dynamic.ClassFileLocator; import net.bytebuddy.dynamic.ClassFileLocator;
import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.scaffold.MethodGraph;
import net.bytebuddy.implementation.FieldAccessor; import net.bytebuddy.implementation.FieldAccessor;
import net.bytebuddy.implementation.FixedValue; import net.bytebuddy.implementation.FixedValue;
import net.bytebuddy.implementation.Implementation; import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.implementation.StubMethod; import net.bytebuddy.implementation.StubMethod;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.pool.TypePool; import net.bytebuddy.pool.TypePool;
public class EnhancerImpl implements Enhancer { public class EnhancerImpl implements Enhancer {
@ -79,6 +73,7 @@ public class EnhancerImpl implements Enhancer {
protected final ByteBuddyEnhancementContext enhancementContext; protected final ByteBuddyEnhancementContext enhancementContext;
private final ByteBuddyState byteBuddyState; private final ByteBuddyState byteBuddyState;
private final EnhancerClassFileLocator classFileLocator;
private final TypePool typePool; private final TypePool typePool;
/** /**
@ -112,7 +107,8 @@ public class EnhancerImpl implements Enhancer {
public EnhancerImpl(final EnhancementContext enhancementContext, final ByteBuddyState byteBuddyState) { public EnhancerImpl(final EnhancementContext enhancementContext, final ByteBuddyState byteBuddyState) {
this.enhancementContext = new ByteBuddyEnhancementContext( enhancementContext ); this.enhancementContext = new ByteBuddyEnhancementContext( enhancementContext );
this.byteBuddyState = byteBuddyState; this.byteBuddyState = byteBuddyState;
this.typePool = buildTypePool( this.enhancementContext ); this.classFileLocator = new EnhancerClassFileLocator( enhancementContext.getLoadingClassLoader() );
this.typePool = buildTypePool( classFileLocator );
} }
/** /**
@ -130,6 +126,7 @@ public class EnhancerImpl implements Enhancer {
public synchronized byte[] enhance(String className, byte[] originalBytes) throws EnhancementException { public synchronized 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.addNameAndBytes( safeClassName, originalBytes );
try { try {
final TypeDescription typeDescription = typePool.describe( safeClassName ).resolve(); final TypeDescription typeDescription = typePool.describe( safeClassName ).resolve();
@ -143,8 +140,8 @@ public class EnhancerImpl implements Enhancer {
} }
} }
private TypePool buildTypePool(final ByteBuddyEnhancementContext enhancementContext) { private TypePool buildTypePool(final ClassFileLocator classFileLocator) {
return TypePool.Default.WithLazyResolution.of( enhancementContext.getLoadingClassLoader() ); return TypePool.Default.WithLazyResolution.of( classFileLocator );
} }
private DynamicType.Builder<?> doEnhance(DynamicType.Builder<?> builder, TypeDescription managedCtClass) { private DynamicType.Builder<?> doEnhance(DynamicType.Builder<?> builder, TypeDescription managedCtClass) {
@ -539,4 +536,35 @@ public class EnhancerImpl implements Enhancer {
} }
} }
} }
private class EnhancerClassFileLocator extends ClassFileLocator.ForClassLoader {
private Map<String,Resolution> nameToResolutionMap = new HashMap<>();
/**
* Creates a new class file locator for the given class loader.
*
* @param classLoader The class loader to query which must not be the bootstrap class loader, i.e. {@code null}.
*/
protected EnhancerClassFileLocator(ClassLoader classLoader) {
super( classLoader );
}
@Override
public Resolution locate(String name) throws IOException {
Resolution resolution = nameToResolutionMap.get( name );
if ( resolution != null ) {
return resolution;
}
else {
return super.locate( name );
}
}
void addNameAndBytes(String name, byte[] bytes ) {
assert name != null;
assert bytes != null;
nameToResolutionMap.put( name, new Resolution.Explicit( bytes) );
}
}
} }