|
@@ -5,8 +5,16 @@
|
|
|
|
|
|
package io.opentelemetry.javaagent.tooling.muzzle;
|
|
|
|
|
|
+import io.opentelemetry.instrumentation.api.config.Config;
|
|
|
import io.opentelemetry.instrumentation.api.internal.cache.Cache;
|
|
|
+import io.opentelemetry.javaagent.bootstrap.InstrumentationHolder;
|
|
|
+import io.opentelemetry.javaagent.bootstrap.VirtualFieldAccessorMarker;
|
|
|
+import java.lang.instrument.Instrumentation;
|
|
|
import java.lang.ref.WeakReference;
|
|
|
+import java.lang.reflect.Method;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.List;
|
|
|
import javax.annotation.Nullable;
|
|
|
import net.bytebuddy.agent.builder.AgentBuilder;
|
|
|
import net.bytebuddy.description.annotation.AnnotationList;
|
|
@@ -15,7 +23,9 @@ import net.bytebuddy.description.method.MethodList;
|
|
|
import net.bytebuddy.description.type.TypeDescription;
|
|
|
import net.bytebuddy.description.type.TypeList;
|
|
|
import net.bytebuddy.dynamic.ClassFileLocator;
|
|
|
+import net.bytebuddy.dynamic.loading.ClassInjector;
|
|
|
import net.bytebuddy.pool.TypePool;
|
|
|
+import net.bytebuddy.utility.JavaModule;
|
|
|
|
|
|
/**
|
|
|
*
|
|
@@ -37,6 +47,10 @@ public class AgentCachingPoolStrategy implements AgentBuilder.PoolStrategy {
|
|
|
// Many things are package visible for testing purposes --
|
|
|
// others to avoid creation of synthetic accessors
|
|
|
|
|
|
+ private static final boolean REFLECTION_ENABLED =
|
|
|
+ Config.get().getBoolean("otel.instrumentation.internal-reflection.enabled", true);
|
|
|
+ private static final Method findLoadedClassMethod = getFindLoadedClassMethod();
|
|
|
+
|
|
|
static final int TYPE_CAPACITY = 64;
|
|
|
|
|
|
static final int BOOTSTRAP_HASH = 7236344; // Just a random number
|
|
@@ -61,42 +75,81 @@ public class AgentCachingPoolStrategy implements AgentBuilder.PoolStrategy {
|
|
|
final SharedResolutionCacheAdapter bootstrapCacheProvider =
|
|
|
new SharedResolutionCacheAdapter(BOOTSTRAP_HASH, null, sharedResolutionCache);
|
|
|
|
|
|
- @Override
|
|
|
- public final TypePool typePool(ClassFileLocator classFileLocator, ClassLoader classLoader) {
|
|
|
- if (classLoader == null) {
|
|
|
- return createCachingTypePool(bootstrapCacheProvider, classFileLocator);
|
|
|
- }
|
|
|
+ private final AgentLocationStrategy locationStrategy;
|
|
|
|
|
|
- WeakReference<ClassLoader> loaderRef =
|
|
|
- loaderRefCache.computeIfAbsent(classLoader, WeakReference::new);
|
|
|
+ public AgentCachingPoolStrategy(AgentLocationStrategy locationStrategy) {
|
|
|
+ this.locationStrategy = locationStrategy;
|
|
|
+ }
|
|
|
|
|
|
- int loaderHash = classLoader.hashCode();
|
|
|
- return createCachingTypePool(loaderHash, loaderRef, classFileLocator);
|
|
|
+ private static Method getFindLoadedClassMethod() {
|
|
|
+ // instrumentation is null when this code is called from muzzle
|
|
|
+ Instrumentation instrumentation = InstrumentationHolder.getInstrumentation();
|
|
|
+ if (instrumentation == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ if (JavaModule.isSupported()) {
|
|
|
+ // ensure that we have access to ClassLoader.findLoadedClass
|
|
|
+ // if modular runtime is used export java.lang package from java.base module to the
|
|
|
+ // module of this class
|
|
|
+ JavaModule currentModule = JavaModule.ofType(AgentCachingPoolStrategy.class);
|
|
|
+ JavaModule javaBase = JavaModule.ofType(ClassLoader.class);
|
|
|
+ if (javaBase != null && javaBase.isNamed() && currentModule != null) {
|
|
|
+ ClassInjector.UsingInstrumentation.redefineModule(
|
|
|
+ instrumentation,
|
|
|
+ javaBase,
|
|
|
+ Collections.emptySet(),
|
|
|
+ Collections.emptyMap(),
|
|
|
+ Collections.singletonMap("java.lang", Collections.singleton(currentModule)),
|
|
|
+ Collections.emptySet(),
|
|
|
+ Collections.emptyMap());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ Method method = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
|
|
|
+ method.setAccessible(true);
|
|
|
+ return method;
|
|
|
+ } catch (NoSuchMethodException exception) {
|
|
|
+ throw new IllegalStateException(exception);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public final TypePool typePool(
|
|
|
- ClassFileLocator classFileLocator, ClassLoader classLoader, String name) {
|
|
|
- return typePool(classFileLocator, classLoader);
|
|
|
+ private static boolean canUseFindLoadedClass() {
|
|
|
+ return findLoadedClassMethod != null;
|
|
|
}
|
|
|
|
|
|
- private TypePool.CacheProvider createCacheProvider(
|
|
|
- int loaderHash, WeakReference<ClassLoader> loaderRef) {
|
|
|
- return new SharedResolutionCacheAdapter(loaderHash, loaderRef, sharedResolutionCache);
|
|
|
+ private static Class<?> findLoadedClass(ClassLoader classLoader, String className) {
|
|
|
+ try {
|
|
|
+ return (Class<?>) findLoadedClassMethod.invoke(classLoader, className);
|
|
|
+ } catch (Exception exception) {
|
|
|
+ throw new IllegalStateException(exception);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- private TypePool createCachingTypePool(
|
|
|
- int loaderHash, WeakReference<ClassLoader> loaderRef, ClassFileLocator classFileLocator) {
|
|
|
- return new TypePool.Default.WithLazyResolution(
|
|
|
- createCacheProvider(loaderHash, loaderRef),
|
|
|
+ @Override
|
|
|
+ public AgentTypePool typePool(ClassFileLocator classFileLocator, ClassLoader classLoader) {
|
|
|
+ return new AgentTypePool(
|
|
|
+ getCacheProvider(classLoader),
|
|
|
classFileLocator,
|
|
|
+ classLoader,
|
|
|
TypePool.Default.ReaderMode.FAST);
|
|
|
}
|
|
|
|
|
|
- private static TypePool createCachingTypePool(
|
|
|
- TypePool.CacheProvider cacheProvider, ClassFileLocator classFileLocator) {
|
|
|
- return new TypePool.Default.WithLazyResolution(
|
|
|
- cacheProvider, classFileLocator, TypePool.Default.ReaderMode.FAST);
|
|
|
+ @Override
|
|
|
+ public AgentTypePool typePool(
|
|
|
+ ClassFileLocator classFileLocator, ClassLoader classLoader, String name) {
|
|
|
+ return typePool(classFileLocator, classLoader);
|
|
|
+ }
|
|
|
+
|
|
|
+ private TypePool.CacheProvider getCacheProvider(ClassLoader classLoader) {
|
|
|
+ if (classLoader == null) {
|
|
|
+ return bootstrapCacheProvider;
|
|
|
+ }
|
|
|
+
|
|
|
+ WeakReference<ClassLoader> loaderRef =
|
|
|
+ loaderRefCache.computeIfAbsent(classLoader, WeakReference::new);
|
|
|
+
|
|
|
+ int loaderHash = classLoader.hashCode();
|
|
|
+ return new SharedResolutionCacheAdapter(loaderHash, loaderRef, sharedResolutionCache);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -108,7 +161,7 @@ public class AgentCachingPoolStrategy implements AgentBuilder.PoolStrategy {
|
|
|
*
|
|
|
* <p>The loaderHash exists to avoid calling get & strengthening the Reference.
|
|
|
*/
|
|
|
- static final class TypeCacheKey {
|
|
|
+ private static final class TypeCacheKey {
|
|
|
private final int loaderHash;
|
|
|
private final WeakReference<ClassLoader> loaderRef;
|
|
|
private final String className;
|
|
@@ -172,7 +225,7 @@ public class AgentCachingPoolStrategy implements AgentBuilder.PoolStrategy {
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public final int hashCode() {
|
|
|
+ public int hashCode() {
|
|
|
return hashCode;
|
|
|
}
|
|
|
|
|
@@ -190,10 +243,10 @@ public class AgentCachingPoolStrategy implements AgentBuilder.PoolStrategy {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- static final class SharedResolutionCacheAdapter implements TypePool.CacheProvider {
|
|
|
+ private static final class SharedResolutionCacheAdapter implements TypePool.CacheProvider {
|
|
|
private static final String OBJECT_NAME = "java.lang.Object";
|
|
|
private static final TypePool.Resolution OBJECT_RESOLUTION =
|
|
|
- new TypePool.Resolution.Simple(new CachingTypeDescription(TypeDescription.OBJECT));
|
|
|
+ new TypePool.Resolution.Simple(TypeDescription.OBJECT);
|
|
|
|
|
|
private final int loaderHash;
|
|
|
private final WeakReference<ClassLoader> loaderRef;
|
|
@@ -229,8 +282,6 @@ public class AgentCachingPoolStrategy implements AgentBuilder.PoolStrategy {
|
|
|
return resolution;
|
|
|
}
|
|
|
|
|
|
- resolution = new CachingResolution(resolution);
|
|
|
-
|
|
|
sharedResolutionCache.put(new TypeCacheKey(loaderHash, loaderRef, className), resolution);
|
|
|
return resolution;
|
|
|
}
|
|
@@ -241,89 +292,268 @@ public class AgentCachingPoolStrategy implements AgentBuilder.PoolStrategy {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private static class CachingResolution implements TypePool.Resolution {
|
|
|
- private final TypePool.Resolution delegate;
|
|
|
- private TypeDescription cachedResolution;
|
|
|
-
|
|
|
- public CachingResolution(TypePool.Resolution delegate) {
|
|
|
-
|
|
|
- this.delegate = delegate;
|
|
|
+ /** Based on TypePool.Default.WithLazyResolution */
|
|
|
+ private class AgentTypePool extends TypePool.Default {
|
|
|
+ private final WeakReference<ClassLoader> classLoaderRef;
|
|
|
+
|
|
|
+ public AgentTypePool(
|
|
|
+ TypePool.CacheProvider cacheProvider,
|
|
|
+ ClassFileLocator classFileLocator,
|
|
|
+ ClassLoader classLoader,
|
|
|
+ TypePool.Default.ReaderMode readerMode) {
|
|
|
+ super(cacheProvider, classFileLocator, readerMode);
|
|
|
+ this.classLoaderRef = new WeakReference<>(classLoader);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public boolean isResolved() {
|
|
|
- return delegate.isResolved();
|
|
|
+ protected TypePool.Resolution doDescribe(String name) {
|
|
|
+ return new AgentTypePool.LazyResolution(classLoaderRef, name);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public TypeDescription resolve() {
|
|
|
- // Intentionally not "thread safe". Duplicate work deemed an acceptable trade-off.
|
|
|
- if (cachedResolution == null) {
|
|
|
- cachedResolution = new CachingTypeDescription(delegate.resolve());
|
|
|
- }
|
|
|
- return cachedResolution;
|
|
|
+ protected TypePool.Resolution doCache(String name, TypePool.Resolution resolution) {
|
|
|
+ return resolution;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- /**
|
|
|
- * TypeDescription implementation that delegates and caches the results for the expensive calls
|
|
|
- * commonly used by our instrumentation.
|
|
|
- */
|
|
|
- private static class CachingTypeDescription
|
|
|
- extends TypeDescription.AbstractBase.OfSimpleType.WithDelegation {
|
|
|
- private final TypeDescription delegate;
|
|
|
-
|
|
|
- // These fields are intentionally not "thread safe".
|
|
|
- // Duplicate work deemed an acceptable trade-off.
|
|
|
- private Generic superClass;
|
|
|
- private TypeList.Generic interfaces;
|
|
|
- private AnnotationList annotations;
|
|
|
- private MethodList<MethodDescription.InDefinedShape> methods;
|
|
|
-
|
|
|
- public CachingTypeDescription(TypeDescription delegate) {
|
|
|
- this.delegate = delegate;
|
|
|
+ /**
|
|
|
+ * Non-lazily resolves a type name.
|
|
|
+ *
|
|
|
+ * @param name The name of the type to resolve.
|
|
|
+ * @return The resolution for the type of this name.
|
|
|
+ */
|
|
|
+ protected TypePool.Resolution doResolve(String name) {
|
|
|
+ TypePool.Resolution resolution = cacheProvider.find(name);
|
|
|
+ if (resolution == null) {
|
|
|
+ // calling super.doDescribe that will locate the class bytes and parse them unlike
|
|
|
+ // doDescribe in this class that returns a lazy resolution without parsing the class bytes
|
|
|
+ resolution = cacheProvider.register(name, super.doDescribe(name));
|
|
|
+ }
|
|
|
+ return resolution;
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- protected TypeDescription delegate() {
|
|
|
- return delegate;
|
|
|
- }
|
|
|
+ /** Based on TypePool.Default.WithLazyResolution.LazyResolution */
|
|
|
+ private class LazyResolution implements TypePool.Resolution {
|
|
|
+ private final WeakReference<ClassLoader> classLoaderRef;
|
|
|
+ private final String name;
|
|
|
|
|
|
- @Override
|
|
|
- public Generic getSuperClass() {
|
|
|
- if (superClass == null) {
|
|
|
- superClass = delegate.getSuperClass();
|
|
|
+ LazyResolution(WeakReference<ClassLoader> classLoaderRef, String name) {
|
|
|
+ this.classLoaderRef = classLoaderRef;
|
|
|
+ this.name = name;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean isResolved() {
|
|
|
+ return doResolve(name).isResolved();
|
|
|
+ }
|
|
|
+
|
|
|
+ private volatile TypeDescription cached;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public TypeDescription resolve() {
|
|
|
+ // unlike byte-buddy implementation we cache the descriptor to avoid having to find
|
|
|
+ // super class and interfaces multiple times
|
|
|
+ if (cached == null) {
|
|
|
+ cached = new AgentTypePool.LazyTypeDescription(classLoaderRef, name);
|
|
|
+ }
|
|
|
+ return cached;
|
|
|
}
|
|
|
- return superClass;
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public TypeList.Generic getInterfaces() {
|
|
|
- if (interfaces == null) {
|
|
|
- interfaces = delegate.getInterfaces();
|
|
|
+ private abstract class CachingTypeDescription
|
|
|
+ extends TypeDescription.AbstractBase.OfSimpleType.WithDelegation {
|
|
|
+ private volatile TypeDescription delegate;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected TypeDescription delegate() {
|
|
|
+ if (delegate == null) {
|
|
|
+ delegate = doResolve(getName()).resolve();
|
|
|
+ }
|
|
|
+ return delegate;
|
|
|
+ }
|
|
|
+
|
|
|
+ private volatile AnnotationList annotations;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public AnnotationList getDeclaredAnnotations() {
|
|
|
+ if (annotations == null) {
|
|
|
+ annotations = delegate().getDeclaredAnnotations();
|
|
|
+ }
|
|
|
+ return annotations;
|
|
|
+ }
|
|
|
+
|
|
|
+ private volatile MethodList<MethodDescription.InDefinedShape> methods;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public MethodList<MethodDescription.InDefinedShape> getDeclaredMethods() {
|
|
|
+ if (methods == null) {
|
|
|
+ methods = delegate().getDeclaredMethods();
|
|
|
+ }
|
|
|
+ return methods;
|
|
|
}
|
|
|
- return interfaces;
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public AnnotationList getDeclaredAnnotations() {
|
|
|
- if (annotations == null) {
|
|
|
- annotations = delegate.getDeclaredAnnotations();
|
|
|
+ /**
|
|
|
+ * Based on TypePool.Default.WithLazyResolution.LazyTypeDescription
|
|
|
+ *
|
|
|
+ * <p>Class description that attempts to use already loaded super classes for navigating class
|
|
|
+ * hierarchy.
|
|
|
+ */
|
|
|
+ private class LazyTypeDescription extends AgentTypePool.CachingTypeDescription {
|
|
|
+ // using WeakReference to ensure that caching this descriptor won't keep class loader alive
|
|
|
+ private final WeakReference<ClassLoader> classLoaderRef;
|
|
|
+ private final String name;
|
|
|
+
|
|
|
+ LazyTypeDescription(WeakReference<ClassLoader> classLoaderRef, String name) {
|
|
|
+ this.classLoaderRef = classLoaderRef;
|
|
|
+ this.name = name;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String getName() {
|
|
|
+ return name;
|
|
|
+ }
|
|
|
+
|
|
|
+ private volatile Generic cachedSuperClass;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Generic getSuperClass() {
|
|
|
+ if (cachedSuperClass == null) {
|
|
|
+ Generic superClassDescription = delegate().getSuperClass();
|
|
|
+ ClassLoader classLoader = classLoaderRef.get();
|
|
|
+ if (canUseFindLoadedClass() && classLoader != null && superClassDescription != null) {
|
|
|
+ String superName = superClassDescription.getTypeName();
|
|
|
+ Class<?> superClass = findLoadedClass(classLoader, superName);
|
|
|
+ if (superClass != null) {
|
|
|
+ // here we use raw type and loose generic info
|
|
|
+ // we don't expect to have matchers that would use the generic info
|
|
|
+ superClassDescription = newTypeDescription(superClass).asGenericType();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ cachedSuperClass = superClassDescription;
|
|
|
+ }
|
|
|
+ return cachedSuperClass;
|
|
|
+ }
|
|
|
+
|
|
|
+ private volatile TypeList.Generic cachedInterfaces;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public TypeList.Generic getInterfaces() {
|
|
|
+ if (cachedInterfaces == null) {
|
|
|
+ TypeList.Generic interfaces = delegate().getInterfaces();
|
|
|
+ ClassLoader classLoader = classLoaderRef.get();
|
|
|
+ if (canUseFindLoadedClass() && classLoader != null && !interfaces.isEmpty()) {
|
|
|
+ // here we use raw types and loose generic info
|
|
|
+ // we don't expect to have matchers that would use the generic info
|
|
|
+ List<TypeDescription> result = new ArrayList<>();
|
|
|
+ for (Generic interfaceDescription : interfaces) {
|
|
|
+ String interfaceName = interfaceDescription.getTypeName();
|
|
|
+ Class<?> interfaceClass = findLoadedClass(classLoader, interfaceName);
|
|
|
+ if (interfaceClass != null) {
|
|
|
+ result.add(newTypeDescription(interfaceClass));
|
|
|
+ } else {
|
|
|
+ result.add(interfaceDescription.asErasure());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ interfaces = new TypeList.Generic.Explicit(result);
|
|
|
+ }
|
|
|
+
|
|
|
+ cachedInterfaces = interfaces;
|
|
|
+ }
|
|
|
+ return cachedInterfaces;
|
|
|
}
|
|
|
- return annotations;
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public MethodList<MethodDescription.InDefinedShape> getDeclaredMethods() {
|
|
|
- if (methods == null) {
|
|
|
- methods = delegate.getDeclaredMethods();
|
|
|
+ private AgentTypePool.LazyTypeDescriptionWithClass newTypeDescription(Class<?> clazz) {
|
|
|
+ return newLazyTypeDescriptionWithClass(
|
|
|
+ AgentTypePool.this, AgentCachingPoolStrategy.this, clazz);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Based on TypePool.Default.WithLazyResolution.LazyTypeDescription
|
|
|
+ *
|
|
|
+ * <p>Class description that uses an existing class instance for navigating super class
|
|
|
+ * hierarchy. This should be much more efficient than finding super types through resource
|
|
|
+ * lookups and parsing bytecode. We are not using TypeDescription.ForLoadedType as it can cause
|
|
|
+ * additional classes to be loaded.
|
|
|
+ */
|
|
|
+ private class LazyTypeDescriptionWithClass extends AgentTypePool.CachingTypeDescription {
|
|
|
+ // using WeakReference to ensure that caching this descriptor won't keep class loader alive
|
|
|
+ private final WeakReference<Class<?>> classRef;
|
|
|
+ private final String name;
|
|
|
+ private final int modifiers;
|
|
|
+
|
|
|
+ LazyTypeDescriptionWithClass(Class<?> clazz) {
|
|
|
+ this.name = clazz.getName();
|
|
|
+ this.modifiers = clazz.getModifiers();
|
|
|
+ this.classRef = new WeakReference<>(clazz);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String getName() {
|
|
|
+ return name;
|
|
|
+ }
|
|
|
+
|
|
|
+ private volatile Generic cachedSuperClass;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Generic getSuperClass() {
|
|
|
+ if (cachedSuperClass == null) {
|
|
|
+ Class<?> clazz = classRef.get();
|
|
|
+ if (clazz == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ Class<?> superClass = clazz.getSuperclass();
|
|
|
+ if (superClass == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ // using raw type
|
|
|
+ cachedSuperClass = newTypeDescription(superClass).asGenericType();
|
|
|
+ }
|
|
|
+
|
|
|
+ return cachedSuperClass;
|
|
|
+ }
|
|
|
+
|
|
|
+ private volatile TypeList.Generic cachedInterfaces;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public TypeList.Generic getInterfaces() {
|
|
|
+ if (cachedInterfaces == null) {
|
|
|
+ List<TypeDescription> result = new ArrayList<>();
|
|
|
+ Class<?> clazz = classRef.get();
|
|
|
+ if (clazz != null) {
|
|
|
+ for (Class<?> interfaceClass : clazz.getInterfaces()) {
|
|
|
+ // virtual field accessors are removed by internal-reflection instrumentation
|
|
|
+ // we do this extra check for tests run with internal-reflection disabled
|
|
|
+ if (!REFLECTION_ENABLED
|
|
|
+ && VirtualFieldAccessorMarker.class.isAssignableFrom(interfaceClass)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // using raw type
|
|
|
+ result.add(newTypeDescription(interfaceClass));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ cachedInterfaces = new TypeList.Generic.Explicit(result);
|
|
|
+ }
|
|
|
+
|
|
|
+ return cachedInterfaces;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int getModifiers() {
|
|
|
+ return modifiers;
|
|
|
}
|
|
|
- return methods;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- @Override
|
|
|
- public String getName() {
|
|
|
- return delegate.getName();
|
|
|
+ private static AgentTypePool.LazyTypeDescriptionWithClass newLazyTypeDescriptionWithClass(
|
|
|
+ AgentTypePool pool, AgentCachingPoolStrategy poolStrategy, Class<?> clazz) {
|
|
|
+ // if class and existing pool use different class loaders create a new pool with correct class
|
|
|
+ // loader
|
|
|
+ if (pool.classLoaderRef.get() != clazz.getClassLoader()) {
|
|
|
+ ClassFileLocator classFileLocator =
|
|
|
+ poolStrategy.locationStrategy.classFileLocator(clazz.getClassLoader());
|
|
|
+ pool = poolStrategy.typePool(classFileLocator, clazz.getClassLoader());
|
|
|
}
|
|
|
+ return pool.new LazyTypeDescriptionWithClass(clazz);
|
|
|
}
|
|
|
}
|