Skip to content

Working around a classloading issue #597

@wwftw

Description

@wwftw

Use case

We're building a Java agent using bytebuddy to instrument classes in web app running in a web container, to detect code patterns that are considered bad practices.

Background and specific problem

We're implementing our own classloader to isolate classpath of web app and web container (I'll call the classloaders as service classloader and system classloader from now on). It works fine until I realized the agent wasn't instrumenting classes loaded by service classloader. Then I tried to set the java system class loader JVM property to use service loader as system default classloader, as it just so happened we had other issues that prompted us to set this going forward. Now the agent is able to find classes on service classloader path.

However, I am using method delegation to delegate the calls, and the interceptor class is in my agent, which is loaded by service classloader as it's the default system classloader during JVM init. Now it seems instrumentation is complete, but when the instrumented class is called, and gets to my interceptor, it throws class not found because it's trying to use the actual system classloader (the Java AppClassloader) to load that class. We are setting the Java app classloader as parent classloader of service classloader, btw. This only happens to classes loaded by java app classloader, service classloader loaded class was instrumented and called with no issues.

Caused by: java.lang.NoClassDefFoundError: Lcom/cerner/alva/agent/interceptor/OAuthSecurityProxyInterceptor;
	at java.base/java.lang.Class.getDeclaredFields0(Native Method)
	at java.base/java.lang.Class.privateGetDeclaredFields(Class.java:3062)
	at java.base/java.lang.Class.getDeclaredField(Class.java:2410)
	at net.bytebuddy.implementation.LoadedTypeInitializer$ForStaticField.onLoad(LoadedTypeInitializer.java:120)
	at net.bytebuddy.implementation.LoadedTypeInitializer$Compound.onLoad(LoadedTypeInitializer.java:187)
	at net.bytebuddy.agent.builder.AgentBuilder$InitializationStrategy$SelfInjection$Dispatcher$InjectingInitializer.onLoad(AgentBuilder.java:3144)
	... 56 more
Caused by: java.lang.ClassNotFoundException: com.cerner.alva.agent.interceptor.OAuthSecurityProxyInterceptor
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)

Any workaround to this? Is there a way to tell delegated method to be loaded by service classloader, this way when it fails to find in system class path, it will fall back to look for it in service classpath. Or method delegation is not the way to go, I can try advice approach but not sure it won't have other related issues, since there seem to be something fundamental going on here.

Metadata

Metadata

Assignees

Labels

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions