2

I'm seeing odd behavior in my application running on standalone jetty.

Starting the application throws an error:

2011-12-14 16:46:20.634:WARN::Error starting handlers java.lang.IllegalAccessError: class sun.reflect.GeneratedConstructorAccessor2 cannot access its superclass sun.reflect.ConstructorAccessorImpl at sun.misc.Unsafe.defineClass(Native Method)

Which is triggered by the line

if (f.getAnnotation(Persist.class) != null) //f is a Field instance (a public one, no less), Persist is an annotation

Some funny facts about this

  • the code runs fine in tomcat

  • the code runs fine in an ant jetty task

  • the code throws this error on standalone jetty (tried v6 & v8), even if I run it with the identical jetty jars running the jetty ant task.

Running with a minimal jetty.xml (basically just pointing to a directory).

Steve B.
  • 55,454
  • 12
  • 93
  • 132

2 Answers2

6

Since I just came across this, and since it seems a bit ... obscure, think it's worth posting for whatever other poor soul runs into this same pit of seemingly random behavior.

Came across a message here, the relevant quote of which is

The problem is the AOP proxy classes are being generated in a separate classloader and this is the cause of the visibility issues, as package-private types are not visible from other classloaders. Guice tries to detect this to avoid introducing the separate classloader, but this seems not to be happening in your example.

So my application will work if I take all the app jars and dump them directly into the JETTY_HOME/lib, which apparently causes aop to generate the classes in a way guice approves of.

Correction - as it turns out, this had nothing at all to do with guice, but with the way Jetty loads classes. The actual fix for this is to alter the way jetty loads classes, adding this to the jetty.xml webappcontext definition:

 <Set name="handler">
      <New class="org.mortbay.jetty.webapp.WebAppContext">
     <Set name="parentLoaderPriority">true</Set>
Steve B.
  • 55,454
  • 12
  • 93
  • 132
2

I had a similar problem with an embedded Jetty and @Async annotation. I solved it by forcing the Jetty's classLoader to be the same as my application's classloader :

context.setClassLoader(Thread.currentThread().getContextClassLoader());

Here is the full code :

public class Jetty {
    public static Server createServer(int port) {
        Server server = new Server(port);
        WebAppContext context = new WebAppContext();
        context.setResourceBase("src/main/webapp");
        context.setClassLoader(Thread.currentThread().getContextClassLoader());
        HandlerList handlers = new HandlerList();
        handlers.setHandlers(new Handler[]{context});
        server.setHandler(handlers);
        return server;
    }
}