Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't get Jetty to scan for annotated classes

Tags:

I have an application with an embedded jetty server which I'm starting up like this (placed in main() and launched with eclipse):

Server server = new Server(port);

WebAppContext context = new WebAppContext();
context.setResourceBase("web/");
context.setDescriptor("web/WEB-INF/web.xml");
context.setConfigurations(new Configuration[]{
            new AnnotationConfiguration(), new WebXmlConfiguration(),
            new WebInfConfiguration(), new TagLibConfiguration(),
            new PlusConfiguration(), new MetaInfConfiguration(),
            new FragmentConfiguration(), new EnvConfiguration()});

context.setContextPath("/");
context.setParentLoaderPriority(true);
server.setHandler(context);
server.start();
server.join();

My web.xml looks like this (empty for now, I'm not sure if I can remove it completely):

<web-app 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    metadata-complete="false"
    version="3.0">
</web-app>

And I have a simple class set up like this:

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(urlPatterns={"/test"})
public class TestServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException  {
        request.getRequestDispatcher("/WEB-INF/html/index.html").forward(request,response);
    }
}

My application works fine when I use traditional servlet mappings in web.xml. But when I remove the web.xml mappings and use annotations, I only get 404s. It doesn't look like it's scanning for annotations at all. The console looks like this:

2012-08-01 17:40:37.021:INFO:oejs.Server:jetty-8.1.5.v20120716
2012-08-01 17:40:37.227:INFO:oejpw.PlusConfiguration:No Transaction manager found - if your webapp requires one, please configure one.
2012-08-01 17:40:37.294:INFO:oejsh.ContextHandler:started o.e.j.w.WebAppContext{/,file:/Users/me/project/web/}
2012-08-01 17:40:37.547:INFO:oejsh.ContextHandler:started o.e.j.w.WebAppContext{/,file:/Users/me/project/web/}
2012-08-01 17:40:37.547:INFO:oejsh.ContextHandler:started o.e.j.w.WebAppContext{/,file:/Users/me/project/web/}
2012-08-01 17:40:37.547:INFO:oejsh.ContextHandler:started o.e.j.w.WebAppContext{/,file:/Users/me/project/web/}
2012-08-01 17:40:37.641:INFO:oejs.AbstractConnector:Started [email protected]:8080

Some things that I have checked already from my research:

  • servlet-3.0 jar is in the classpath
  • metadata-complete set to false in web.xml
  • I made sure to include AnnotationConfiguration in web app context

I've run out of ideas and am about to just revert back to the old web.xml, but it's killing me why I can't get this to work.

like image 827
Ryan Silva Avatar asked Aug 01 '12 21:08

Ryan Silva


4 Answers

Update: June 2021

The example project has been updated to be Jetty version neutral.

https://github.com/jetty-project/embedded-servlet-server

It has branches for specific versions of Jetty now.

The older example projects have been archived.

Update: June 2015

The example project has been updated for Jetty 9 and Servlet 3.1

See: https://github.com/jetty-project/embedded-servlet-3.1

Original Answer:

From your description, and a sample project I whipped up using your code, you are doing everything correctly.

Sample project: https://github.com/jetty-project/embedded-servlet-3.0

In order for this to work, you'll want the following (only mentioning this as your question didn't include this detail)

  • JDK 1.6+
  • jetty-webapps jar (+ dependencies) from Jetty 8.1.x (or newer)
  • jetty-annotations jar (+ dependencies) from Jetty 8.1.x (or newer)

Just from these limited requirements you'll see the following list of dependencies present.

$ mvn dependency:tree
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building sample-webapp 1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-dependency-plugin:2.1:tree (default-cli) @ sample-webapp ---
[INFO] com.company.sample:sample-webapp:war:1-SNAPSHOT
[INFO] +- org.eclipse.jetty.orbit:javax.servlet:jar:3.0.0.v201112011016:provided
[INFO] +- org.eclipse.jetty:jetty-webapp:jar:8.1.5-SNAPSHOT:test
[INFO] |  +- org.eclipse.jetty:jetty-xml:jar:8.1.5-SNAPSHOT:test
[INFO] |  |  \- org.eclipse.jetty:jetty-util:jar:8.1.5-SNAPSHOT:test
[INFO] |  \- org.eclipse.jetty:jetty-servlet:jar:8.1.5-SNAPSHOT:test
[INFO] |     \- org.eclipse.jetty:jetty-security:jar:8.1.5-SNAPSHOT:test
[INFO] |        \- org.eclipse.jetty:jetty-server:jar:8.1.5-SNAPSHOT:test
[INFO] |           +- org.eclipse.jetty:jetty-continuation:jar:8.1.5-SNAPSHOT:test
[INFO] |           \- org.eclipse.jetty:jetty-http:jar:8.1.5-SNAPSHOT:test
[INFO] |              \- org.eclipse.jetty:jetty-io:jar:8.1.5-SNAPSHOT:test
[INFO] \- org.eclipse.jetty:jetty-annotations:jar:8.1.5-SNAPSHOT:test
[INFO]    +- org.eclipse.jetty:jetty-plus:jar:8.1.5-SNAPSHOT:test
[INFO]    |  +- org.eclipse.jetty.orbit:javax.transaction:jar:1.1.1.v201105210645:test
[INFO]    |  \- org.eclipse.jetty:jetty-jndi:jar:8.1.5-SNAPSHOT:test
[INFO]    |     \- org.eclipse.jetty.orbit:javax.mail.glassfish:jar:1.4.1.v201005082020:test
[INFO]    |        \- org.eclipse.jetty.orbit:javax.activation:jar:1.1.0.v201105071233:test
[INFO]    +- org.eclipse.jetty.orbit:javax.annotation:jar:1.1.0.v201108011116:test
[INFO]    \- org.eclipse.jetty.orbit:org.objectweb.asm:jar:3.1.0.v200803061910:test
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.771s
[INFO] Finished at: Fri Aug 10 18:17:46 MST 2012
[INFO] Final Memory: 6M/180M
[INFO] ------------------------------------------------------------------------

It is quite likely that you are just missing a dependency or JDK requirement.

like image 106
Joakim Erdfelt Avatar answered Sep 19 '22 00:09

Joakim Erdfelt


AnntationConfiguration class scans annotations via its scanForAnnotations(WebAppContext) method. In the method AnnotationConfiguration class scans following path.

  • container jars
  • WEB-INF/classes
  • WEB-INF/libs

So if you want your servlet classes in your production code(i.e. the sources in the directory src/main/java) to be scanned, add your production code into the WebAppContext's metadata as WEB-INF/classes.

Try the code bellow, for adding your code into WebAppContext's metadata.

URL classes = getClass()
        .getProtectionDomain()
        .getCodeSource()
        .getLocation();

WebAppContext context = new WebAppContext();
context.getMetaData()
    .setWebInfClassesDirs(
        Arrays.asList(Resource.newResource(classes)));
like image 35
mike_neck Avatar answered Sep 21 '22 00:09

mike_neck


I had this same problem, but after many reads I got the solution! IMPORTANT: remember to have in your build path the following jars:

jetty-all-9.0.6.v20130930.jar

jetty-annotations-9.0.6.v20130930.jar

org.objectweb.asm-3.1.0.v200803061910.jar

javax.servlet-api-3.0.1.jar

jetty-plus-9.0.6.v20130930.jar

public class Main {

   public static void main(String[] args) throws Exception {

       //Create the server
       Server server = new Server(8080);

       ClassList clist = ClassList.setServerDefault(server);

       //clist.addAfter("org.eclipse.jetty.webapp.FragmentConfiguration", "org.eclipse.jetty.plus.webapp.EnvConfiguration",    "org.eclipse.jetty.plus.webapp.PlusConfiguration");
       clist.addBefore(JettyWebXmlConfiguration.class.getName(), AnnotationConfiguration.class.getName());

       //Here is the trick to scan current classpath!
       webapp.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", 
            ".*/build/classes/");

       webapp.setContextPath("/");
       webapp.setResourceBase("./WebContent");


       server.setHandler(webapp);

       server.start();
       server.join();

   }

}
like image 45
Lucas Batistussi Avatar answered Sep 20 '22 00:09

Lucas Batistussi


Based on the previous example provided by Joakim, I've uploaded a modified version that supports annotations in an embedded jetty without packaging the project into a war file. This project is ready to deploy to Heroku just running:

$java -cp target/classes:"target/dependency/*" com.example.Launcher

If you are interested in the details, the important lines are these ones from com.example.Launcher:

context.setConfigurations(new Configuration[] {
            new AnnotationConfiguration(), new WebXmlConfiguration(),
            new WebInfConfiguration(),
            new PlusConfiguration(), new MetaInfConfiguration(),
            new FragmentConfiguration(), new EnvConfiguration() });

// Important! make sure Jetty scans all classes under ./classes looking for annotations. 
//'Classes' directory is generated running 'mvn package'
context.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",".*/classes/.*");

You can change accordingly the JarPattern depending on the classes you want to scan for annotations.

Here you have the full example: https://github.com/pablormier/embedded-jetty-annotations-example

like image 21
Pablo R. Mier Avatar answered Sep 18 '22 00:09

Pablo R. Mier