2 Replies Latest reply on Feb 5, 2018 4:31 AM by Martin Kouba

    Weld JettyContainer incompatible with Google App Engine's Jetty 9 fork

    erwin de ley Newbie

      I’m trying to get Weld CDI (2.4.6) working on GAE standard with Java 8 / Jetty 9.x.

      Almost there, i.e. my beans & annotations get processed by Weld etc, but the link to the servlet container and my servlets is not working.

       

      In the startup logs I get a message that there is no recognized servlet container :

       

      [INFO] GCLOUD: Feb 01, 2018 12:19:15 AM org.jboss.weld.environment.servlet.WeldServletLifecycle initialize

      [INFO] GCLOUD: INFO: WELD-ENV-001001: No supported servlet container detected, CDI injection will NOT be available in Servlets, Filters or Listeners

      [INFO] GCLOUD: Feb 01, 2018 12:19:15 AM org.jboss.weld.environment.servlet.WeldServletLifecycle initialize

      [INFO] GCLOUD: DEBUG: Exception dump from Container lookup: org.jboss.weld.environment.tomcat.TomcatContainer@6ed06f69->WELD-ENV-000029: Cannot load class for org.apache.catalina.connector.Request.

      [INFO] GCLOUD: org.jboss.weld.environment.gwtdev.GwtDevHostedModeContainer@7f9ab969->WELD-ENV-000029: Cannot load class for com.google.gwt.dev.HostedMode.

       

      While debugging, I passed through org.jboss.weld.environment.jetty.JettyContainer.

      It appears that GAE’s Jetty fork does not return its ServletContext.getServerInfo with “jetty” in the info, but with “Google App Engine Development/1.9.56”.

      And whereas TomcatContainer and GwtDevHostedModeContainer simply check if a given class can be found, JettyContainer looks at that serverinfo which fails for GAE’s jetty…

       

      Is there a concrete reason why Weld should not be allowed to work on that GAE Jetty variation?

       

      I found several (apparently outdated) SO questions, blogs etc that hint at solutions for weld CDI on GAE, but it all seems to be about older versions on both sides.

       

      thanks

      erwin

        • 1. Re: Weld JettyContainer incompatible with Google App Engine's Jetty 9 fork
          erwin de ley Newbie

          One step further : I found the info about being able to set your own custom container impl and added the following in my web.xml:

            <context-param>

              <param-name>org.jboss.weld.environment.container.class</param-name>

              <param-value>org.jboss.weld.environment.jetty.JettyContainer</param-value>

            </context-param>

           

          That succeeds in initializing the JettyContainer partially, but then results in NoClassDefFoundError where trying to load a Jetty class org/eclipse/jetty/servlet/ServletContextHandler$Decorator (cfr below for the stack trace).

          I did set a jetty-context.xml and jetty-env.xml files (cfr attachments) as documented elsewhere, but it seems my development launch of GAE doesn't handle that correctly.

           

          As a hack I then added a dependency on GAE's Jetty wrapper :

          <dependency>

          <groupId>com.google.appengine</groupId>

          <artifactId>jetty9-compat-base</artifactId>

          <version>1.9.31</version>

          </dependency>

          This drags in all Jetty classes in the WAR build, and then everything starts up smoothly.

           

          But once I try to access the servlet with injected bean, it's still null (i.e. not injected). Complete log file is in attach (gae_weld_hello_NPE).

          I guess this could be caused by the fact that the real GAE Jetty was not reached in the weld container initialization, as it was using the jetty classes packaged in the war...

          (classloader isolation stuff, a bit too advanced for me)

           

          Anyway, I guess this is not a WELD issue.

          But if there is an interest to get it working on GAE, are there suggestions on what would be a good approach?

          Should I try to get WELD running outside of the container, in a kind of SE mode within my application (which is a web application with servlets)?

          Or try to get the GAE people looking into it to support it "natively"?

           

          cheers

          erwin

           

          Some more details :

           

          Servlet is trivial (copied from a blog somewhere I forgot) :

           

          public class HelloServlet extends HttpServlet {

            @Inject

            Hello hello;

           

            @Override

            protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

              System.out.println(this);

              PrintWriter out = resp.getWriter();

              out.println(hello.sayHelloWorld());

              out.close();

            }

           

            private String saySomething() {

              return hello.sayHelloWorld();

            }

          }

           

          Hello & World trivial as well :

           

          @ApplicationScoped

          public class Hello {

            @Inject

            private World world;

           

            public Hello() {

              System.err.println("Hello instantiated");

            }

            public String sayHelloWorld() {

              return "" + world.sayWorld();

            }

          }

           

          public class World {

            public String sayWorld() {

               return "World !!!";

            }

          }

           

           

          And here's the initial NoClassDefFoundError stacktrace :

           

          [INFO] GCLOUD: Feb 01, 2018 1:49:18 PM org.jboss.weld.environment.servlet.WeldServletLifecycle findContainer

          [INFO] GCLOUD: INFO: WELD-ENV-001002: Container detection skipped - custom container class loaded: org.jboss.weld.environment.jetty.JettyContainer.

          [INFO] GCLOUD: 2018-02-01 13:49:18.376:INFO:oejs.AbstractConnector:main: Started NetworkTrafficSelectChannelConnector@60e21209{HTTP/1.1,[http/1.1]}{0.0.0.0:8888}

          [INFO] GCLOUD: Exception in thread "main" java.lang.NoClassDefFoundError: org/eclipse/jetty/servlet/ServletContextHandler$Decorator

          [INFO] GCLOUD:    at java.lang.ClassLoader.defineClass1(Native Method)

          [INFO] GCLOUD:    at java.lang.ClassLoader.defineClass(ClassLoader.java:760)

          [INFO] GCLOUD:    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)

          [INFO] GCLOUD:    at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)

          [INFO] GCLOUD:    at java.net.URLClassLoader.access$100(URLClassLoader.java:73)

          [INFO] GCLOUD:    at java.net.URLClassLoader$1.run(URLClassLoader.java:368)

          [INFO] GCLOUD:    at java.net.URLClassLoader$1.run(URLClassLoader.java:362)

          [INFO] GCLOUD:    at java.security.AccessController.doPrivileged(Native Method)

          [INFO] GCLOUD:    at java.net.URLClassLoader.findClass(URLClassLoader.java:361)

          [INFO] GCLOUD:    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)

          [INFO] GCLOUD:    at com.google.appengine.tools.development.IsolatedAppClassLoader.loadClass(IsolatedAppClassLoader.java:195)

          [INFO] GCLOUD:    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)

          [INFO] GCLOUD:    at org.jboss.weld.environment.jetty.JettyContainer.initialize(JettyContainer.java:74)

          [INFO] GCLOUD:    at org.jboss.weld.environment.servlet.WeldServletLifecycle.initialize(WeldServletLifecycle.java:220)

          [INFO] GCLOUD:    at org.jboss.weld.environment.servlet.EnhancedListener.onStartup(EnhancedListener.java:62)

          [INFO] GCLOUD:    at org.eclipse.jetty.plus.annotation.ContainerInitializer.callStartup(ContainerInitializer.java:140)

          [INFO] GCLOUD:    at org.eclipse.jetty.annotations.ServletContainerInitializersStarter.doStart(ServletContainerInitializersStarter.java:63)

          [INFO] GCLOUD:    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)

          [INFO] GCLOUD:    at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:330)

          [INFO] GCLOUD:    at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1406)

          [INFO] GCLOUD:    at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1368)

          [INFO] GCLOUD:    at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:778)

          [INFO] GCLOUD:    at org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContextHandler.java:262)

          [INFO] GCLOUD:    at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:522)

          [INFO] GCLOUD:    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)

          [INFO] GCLOUD:    at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:131)

          [INFO] GCLOUD:    at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:105)

          [INFO] GCLOUD:    at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61)

          [INFO] GCLOUD:    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)

          [INFO] GCLOUD:    at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:131)

          [INFO] GCLOUD:    at org.eclipse.jetty.server.Server.start(Server.java:422)

          [INFO] GCLOUD:    at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:105)

          [INFO] GCLOUD:    at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61)

          [INFO] GCLOUD:    at org.eclipse.jetty.server.Server.doStart(Server.java:389)

          [INFO] GCLOUD:    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)

          [INFO] GCLOUD:    at com.google.appengine.tools.development.jetty9.JettyContainerService.startContainer(JettyContainerService.java:346)

          [INFO] GCLOUD:    at com.google.appengine.tools.development.AbstractContainerService.startup(AbstractContainerService.java:284)

          [INFO] GCLOUD:    at com.google.appengine.tools.development.AutomaticInstanceHolder.startUp(AutomaticInstanceHolder.java:26)

          [INFO] GCLOUD:    at com.google.appengine.tools.development.AbstractModule.startup(AbstractModule.java:87)

          [INFO] GCLOUD:    at com.google.appengine.tools.development.Modules.startup(Modules.java:105)

          [INFO] GCLOUD:    at com.google.appengine.tools.development.DevAppServerImpl.doStart(DevAppServerImpl.java:274)

          [INFO] GCLOUD:    at com.google.appengine.tools.development.DevAppServerImpl.access$000(DevAppServerImpl.java:47)

          [INFO] GCLOUD:    at com.google.appengine.tools.development.DevAppServerImpl$1.run(DevAppServerImpl.java:219)

          [INFO] GCLOUD:    at com.google.appengine.tools.development.DevAppServerImpl$1.run(DevAppServerImpl.java:217)

          [INFO] GCLOUD:    at java.security.AccessController.doPrivileged(Native Method)

          [INFO] GCLOUD:    at com.google.appengine.tools.development.DevAppServerImpl.start(DevAppServerImpl.java:217)

          [INFO] GCLOUD:    at com.google.appengine.tools.development.DevAppServerMain$StartAction.apply(DevAppServerMain.java:368)

          [INFO] GCLOUD:    at com.google.appengine.tools.util.Parser$ParseResult.applyArgs(Parser.java:47)

          [INFO] GCLOUD:    at com.google.appengine.tools.development.DevAppServerMain.run(DevAppServerMain.java:223)

          [INFO] GCLOUD:    at com.google.appengine.tools.development.DevAppServerMain.main(DevAppServerMain.java:214)

          [INFO] GCLOUD: Caused by: java.lang.ClassNotFoundException: org.eclipse.jetty.servlet.ServletContextHandler$Decorator

          [INFO] GCLOUD:    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)

          [INFO] GCLOUD:    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)

          [INFO] GCLOUD:    at com.google.appengine.tools.development.IsolatedAppClassLoader.loadClass(IsolatedAppClassLoader.java:195)

          [INFO] GCLOUD:    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)

          [INFO] GCLOUD:    ... 50 more

          • 2. Re: Weld JettyContainer incompatible with Google App Engine's Jetty 9 fork
            Martin Kouba Master

            Hi Erwin,

            Weld officially does not support GAE for some time. If I remember correctly GAE was using quite old version of Jetty (minimum version supported by Weld is currently 7.2, and that's probably the reason for NoClassDefFoundError) and had some Tomcat libs on the classpath. Also weld-servlet support is somehow limited as it's not the primary target environment. And yes, it is possible to use a custom container impl and enhance the objects created by the servlet container (e.g. Jetty impl currently adds a Weld-specific decorator in org.jboss.weld.environment.jetty.WeldDecorator#process(ServletContext)).