Search code examples
javajakarta-eejettycdi

Constructor injection with Jetty throws InstantiationException


I feel like I'm missing something obvious here...

I have a number of JEE Filters and Servlets that need various dependencies injected at runtime.

At the moment, we declare the dependencies as fields, like this:

import javax.inject.Inject;

public class ThingFilter implements Filter {
    @Inject
    ThingDependency thing;

    ....

}

This works fine in all situations. However, if I change it to use constructor injection, like this:

import javax.inject.Inject;

public class ThingFilter implements Filter {
    private final ThingDependency thing;

    @Inject
    public ThingFilter(ThingDependency thing) {
        this.thing = thing;
    }

    ....

}

...then it works fine when running under WebSphere Liberty, but not when running using the embedded Jetty server we start for our integration tests. (Ideally we'd use the same thing for both of course, but that's a story for another time.) The exception we get is:

org.eclipse.jetty.servlet.ServletHolder$1: java.lang.InstantiationException: com.thing.ThingFilter
        at org.eclipse.jetty.servlet.ServletHolder.makeUnavailable(ServletHolder.java:593)
        at org.eclipse.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:652)
        at org.eclipse.jetty.servlet.ServletHolder.getServlet(ServletHolder.java:495)
        at org.eclipse.jetty.servlet.ServletHolder.ensureInstance(ServletHolder.java:782)
        at org.eclipse.jetty.servlet.ServletHolder.prepare(ServletHolder.java:767)
        at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:538)
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
        at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:190)
        at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1584)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:188)
        at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1228)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:168)
        at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:481)
        at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1553)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:166)
        at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1130)
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
        at org.eclipse.jetty.server.Server.handle(Server.java:564)
        at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:318)
        at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:251)
        at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)
        at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:112)
        at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)
        at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:672)
        at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:590)
        at java.lang.Thread.run(Thread.java:745)
Caused by:
java.lang.InstantiationException: com.thing.ThingFilter
        at java.lang.Class.newInstance(Class.java:427)
        at org.eclipse.jetty.server.handler.ContextHandler$Context.createInstance(ContextHandler.java:2510)
        at org.eclipse.jetty.servlet.ServletContextHandler$Context.createServlet(ServletContextHandler.java:1326)
        at org.eclipse.jetty.servlet.ServletHolder.newInstance(ServletHolder.java:1208)
        at org.eclipse.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:611)
        at org.eclipse.jetty.servlet.ServletHolder.getServlet(ServletHolder.java:495)
        at org.eclipse.jetty.servlet.ServletHolder.ensureInstance(ServletHolder.java:782)
        at org.eclipse.jetty.servlet.ServletHolder.prepare(ServletHolder.java:767)
        at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:538)
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
        at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:190)
        at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1584)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:188)
        at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1228)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:168)
        at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:481)
        at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1553)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:166)
        at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1130)
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
        at org.eclipse.jetty.server.Server.handle(Server.java:564)
        at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:318)
        at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:251)
        at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)
        at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:112)
        at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)
        at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:672)
        at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:590)
        at java.lang.Thread.run(Thread.java:745)
Caused by:
java.lang.NoSuchMethodException: com.thing.ThingFilter.<init>()
        at java.lang.Class.getConstructor0(Class.java:3082)
        at java.lang.Class.newInstance(Class.java:412)
        at org.eclipse.jetty.server.handler.ContextHandler$Context.createInstance(ContextHandler.java:2510)
        at org.eclipse.jetty.servlet.ServletContextHandler$Context.createServlet(ServletContextHandler.java:1326)
        at org.eclipse.jetty.servlet.ServletHolder.newInstance(ServletHolder.java:1208)
        at org.eclipse.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:611)
        at org.eclipse.jetty.servlet.ServletHolder.getServlet(ServletHolder.java:495)
        at org.eclipse.jetty.servlet.ServletHolder.ensureInstance(ServletHolder.java:782)
        at org.eclipse.jetty.servlet.ServletHolder.prepare(ServletHolder.java:767)
        at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:538)
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
        at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:190)
        at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1584)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:188)
        at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1228)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:168)
        at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:481)
        at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1553)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:166)
        at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1130)
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
        at org.eclipse.jetty.server.Server.handle(Server.java:564)
        at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:318)
        at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:251)
        at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)
        at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:112)
        at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)
        at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:672)
        at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:590)
        at java.lang.Thread.run(Thread.java:745)

It looks like it's trying to just create the object without specifying any constructor parameters, which of course won't work.

We create the embedded Jetty server like this:

String webAppPath = "...path to WAR";

WebAppContext webAppContext = new WebAppContext(webAppPath, "/");
JettyWeldInitializer.initWebApp(webAppContext);
webAppContext.addEventListener(new Listener());

server.setHandler(webAppContext);
server.start();

What am I doing wrong?


Solution

  • Jetty integration for Weld still requires default constructors. The servlet spec is pretty clear, filters, servlets, listeners are not managed components but support injection points. As a result, Weld integration is based on an unmanaged instance that satisfies injection points and does not treat these as managed classes, its Jetty that's instantiating the beans. Jetty in particular does not allow you to manage the life cycle of these classes. Take a look at JettyWeldInjector and AbstractInjector which show that its just processing the injection points.