Felix
Felix

Reputation: 6104

Access servlet-api within javaagent

I'm trying to access classes from the servlet-api within a javaagent jar that is added to my application via the -javaagent:my-agent.jar flag. My application runs on Tomcat. The problem is that I get a ClassNotFoundException, because the agent jar is loaded by a classloader that has no access to the servlet-api classes.

More specifically, I want to include a ServletContainerInitializer in my javaagent

public class MyInitializer implements ServletContainerInitializer {
    @Override
    public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
        System.out.println(ctx);
    }
}

META-INF/services/javax.servlet.ServletContainerInitializer

org.example.MyInitializer

The result is a ClassNotFoundException because ServletContainerInitializer could not be found.

Is there any way to access the servlet-api within a javaagent? Or more generally, is it possible to access any class that is loaded via the ApplicationClassLoader, like classes from the spring framework?

Upvotes: 4

Views: 848

Answers (2)

presci
presci

Reputation: 363

What worked for me was I added servlet-api.jar file in the ClassPool.insertClassPath. And that resolved the issue.

    ClassPool $pool = ClassPool.getDefault();
            try {
                $pool.insertClassPath("/apache-tomcat-7.0.50/lib/servlet-api.jar");
            } catch (NotFoundException e) {
                throw new RuntimeException(e);
            }
    return $pool;

https://github.com/presci/MyAgent.git

Upvotes: 0

Holger
Holger

Reputation: 298173

If your agent has a premain method with a signature like

public static void premain(String agentArgs, Instrumentation inst)

You get hands on an Instrumentation object which provides the methods getAllLoadedClasses() and getInitiatedClasses(ClassLoader). Now it would be awkward to search these arrays each time and use the Class instances via Reflection only. But you can use these methods to find the desired API class, determine its runtime ClassLoader and create a new ClassLoader using it as a resolve parent and pointing to your agent classes which require them.

Upvotes: 1

Related Questions