Search code examples
javabyte-buddy

Byte Buddy - java.lang.NoClassDefFoundError: javax/servlet/ServletRequest


I am trying to instrument service method of javax.servlet.Servlet interface implementations as following:

.transform(
                        new AgentBuilder.Transformer.ForAdvice()
                                .include(MyAgent.class.getClassLoader())
                                .advice(
                                        named("service")
                                                .and(takesArgument(0, ServletRequest.class))
                                                .and(takesArgument(1, ServletResponse.class))
                                        , "com.MyAdvice"
                                )
                )

Now, if I attach this agent to an already running Spring boot application via agentmain - I see below exception on trying to access any web page

java.lang.LinkageError: loader constraint violation: when resolving method 'void javax.servlet.http.HttpServletRequestWrapper.<init>(javax.servlet.http.HttpServletRequest)' 
the class loader org.springframework.boot.loader.LaunchedURLClassLoader @18be83e4 of the current class,
org/springframework/web/servlet/resource/ResourceUrlEncodingFilter$ResourceUrlEncodingRequestWrapper, and the class loader 'app' for the method's defining class, javax/servlet/http/HttpServletRequestWrapper, 
have different Class objects for the type javax/servlet/http/HttpServletRequest used in the signature (org.springframework.web.servlet.resource.ResourceUrlEncodingFilter$ResourceUrlEncodingRequestWrapper is in unnamed module of loader org.springframework.boot.loader.LaunchedURLClassLoader @18be83e4, parent loader 'app'; javax.servlet.http.HttpServletRequestWrapper is in unnamed module of loader 'app')

I understand its because javax/servlet/http/HttpServletRequest instance is loaded from 2 different jars - one that came through agent and another through spring boot embedded tomcat. If I try to set scope as provided in agent's pom.xml [ since I do not want to include servlet-api in agent bundled jar and try use already provided servlet-api implementation from Spring boot ], I get Caused by: java.lang.NoClassDefFoundError: javax/servlet/ServletRequest - possibly because the classloader loading the agent can't see spring boot provided servlet api.

Is there any possible workaround or fix to resolve this situation? Thank you for your time and feedback.


Solution

  • Ideally, your agent does not contain such classes. Rather, match classes by their name: takesArgument(0, named("javax.servlet.ServletRequest")), for instance.