I have a stripped down test project which contains a Servlet version 3.0, declared with annotations like so:
@WebServlet(\"/test\")
public class TestServ
Well I finally solved it by looking in the Tomcat7 sources, namely in the unit tests that deal with EmbeddedTomcat and servlet 3.0 annotations.
Basically, you must start your Embedded Tomcat 7 like this to make it aware of your annotated classes:
String webappDirLocation = "src/main/webapp/";
Tomcat tomcat = new Tomcat();
tomcat.setPort(8080);
StandardContext ctx = (StandardContext) tomcat.addWebapp("/embeddedTomcat",
new File(webappDirLocation).getAbsolutePath());
//declare an alternate location for your "WEB-INF/classes" dir:
File additionWebInfClasses = new File("target/classes");
VirtualDirContext resources = new VirtualDirContext();
resources.setExtraResourcePaths("/WEB-INF/classes=" + additionWebInfClasses);
ctx.setResources(resources);
tomcat.start();
tomcat.getServer().await();
For the sake of clarity I should mention that this works for a standard Maven project where your "web resources" (such as static and dynamic pages, WEB-INF directory etc) are found in:
[your project's root dir]/src/main/webapp
and your classes get compiled into
[your project's root dir]/target/classes
(such that you'd have [your project's root dir]/target/classes/[some package]/SomeCompiledServletClass.class)
For other directories layouts, these locations need to be changed accordingly.
==== UPDATE: Embedded Tomcat 8 ====
Thanks to @kwak for noticing this.
The APIs have changed a bit, here how the above example changes when using Embedded Tomcat 8:
String webappDirLocation = "src/main/webapp/";
Tomcat tomcat = new Tomcat();
tomcat.setPort(8080);
StandardContext ctx = (StandardContext) tomcat.addWebapp("/embeddedTomcat",
new File(webappDirLocation).getAbsolutePath());
//declare an alternate location for your "WEB-INF/classes" dir:
File additionWebInfClasses = new File("target/classes");
WebResourceRoot resources = new StandardRoot(ctx);
resources.addPreResources(new DirResourceSet(resources, "/WEB-INF/classes", additionWebInfClasses.getAbsolutePath(), "/"));
ctx.setResources(resources);
tomcat.start();
tomcat.getServer().await();
Tomcat tomcat = new Tomcat();
tomcat.setPort(port);
Context ctx = tomcat.addWebapp("/", new File(docBase).getAbsolutePath());
StandardJarScanner scan = (StandardJarScanner) ctx.getJarScanner();
scan.setScanClassPath(true);
scan.setScanBootstrapClassPath(true); // just guessing here
scan.setScanAllDirectories(true);
scan.setScanAllFiles(true);
tomcat.start();
tomcat.getServer().await();
it works well for me using Tomcat Embed 7.0.90 from MVN
Given the JNDI magic in the snippet you posted:
try {
listBindings = context.getResources().listBindings(
"/WEB-INF/classes");
} catch (NameNotFoundException ignore) {
// Safe to ignore
}
could you maybe set up the same sort of entries in JNDI yourself?
Context ctx = tomcat.addWebapp(...);
FileDirContext fdc = new FileDirContext();
fdc.setDocBase(new File("/path/to/my/classes").getAbsolutePath());
ctx.getResources().createSubcontext("/WEB-INF/classes").bind("myclasses", fdc);
I think in 8.5 and later it's just one liner:
Context.setAddWebinfClassesResources(true);
Sets the flag that indicates if /WEB-INF/classes should be treated like an exploded JAR and JAR resources made available as if they were in a JAR.
http://tomcat.apache.org/tomcat-8.5-doc/api/org/apache/catalina/core/StandardContext.html#setAddWebinfClassesResources(boolean)