Reputation: 965
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:
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.
Upvotes: 21
Views: 15061
Reputation: 49495
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)
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.
Upvotes: 8
Reputation: 60
You can
provide EmptyResource.INSTANCE
if you do not need static resources
add AnnotationConfiguration and override scanForAnnotations
method, adding classpath resource to WebAppContext
Metadata, possibly with path to root package for a scan
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/");
webapp.setBaseResource(EmptyResource.INSTANCE);
webapp.setConfigurations(new Configuration[]{
new AnnotationConfiguration(){
@Override
protected void scanForAnnotations(WebAppContext context) throws Exception {
Resource classPathResource = Resource.newResource(EmbeddedServerApp.class.getResource("/my/learn/jetty/servlet").toURI());
context.getMetaData().addContainerResource(classPathResource);
super.scanForAnnotations(context);
}
},
});
server.setHandler(webapp);
server.start();
Upvotes: 1
Reputation: 193
I have come up with a different approach rather specific to Jetty & Spring. Instead of letting Jetty scan for classes, I manually called initializer
classes in startContext()
method of a custom Jetty ServletContextHandler
. Code is as follows:
public class CustomServletContextHandler extends ServletContextHandler {
@Override
protected void startContext() throws Exception {
SpringServletContainerInitializer initer = new SpringServletContainerInitializer();
HashSet<Class<?>> classes = new HashSet<>();
// Add annotated classes here such as
//classes.add(SpringSecurityInitializer.class);
//classes.add(SpringWebInitilializer.class);
try {
initer.onStartup(classes, this.getServletContext());
}catch(Exception e)
{
e.printStackTrace();
}
super.startContext();
}
}
And then when creating context, use custom handler:
ServletContextHandler ctx = new CustomServletContextHandler();
ctx.setContextPath("/");
...
Upvotes: 1
Reputation: 1615
In our case these lines helped in Jetty startup code:
ClassList cl = Configuration.ClassList.setServerDefault(server);
cl.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration", "org.eclipse.jetty.annotations.AnnotationConfiguration");
Upvotes: 0
Reputation: 176
AnntationConfiguration
class scans annotations via its scanForAnnotations(WebAppContext)
method.
In the method AnnotationConfiguration
class scans following path.
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)));
Upvotes: 8
Reputation: 747
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
Upvotes: 1
Reputation: 2343
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();
}
}
Upvotes: 5