In my embedded tomcat app, StandardJarScanner is doing a minimal Servlet 3.0 annotation scanning, specifically only HandlesTypes. After digging in, it appears that because the classloader that loaded StandardJarScanner is the same that loaded StandardContext and ContextConfig StandardJarScanner.isWebappClassLoader always returns false. Then StandardJarScanner.scan will set htOnly to true since fragment.getWebappJar is false.
// Only need to scan for @HandlesTypes matches if any of the // following are true: // - it has already been determined only @HandlesTypes is required // (e.g. main web.xml has metadata-complete="true" // - this fragment is for a container JAR (Servlet 3.1 section 8.1) // - this fragment has metadata-complete="true" boolean htOnly = handlesTypesOnly || !fragment.getWebappJar() || fragment.isMetadataComplete(); My embedded app looks as follows: Tomcat tomcat = new Tomcat(); File docBase = new File(System.getProperty("java.io.tmpdir")); tomcat.setBaseDir(docBase.getAbsolutePath()); tomcat.setSilent(false); tomcat.setPort(8080); // init http connector tomcat.getConnector(); logger.info("Class loader = " + Thread.currentThread().getContextClassLoader()); Context ctx = tomcat.addContext("", docBase.getAbsolutePath()); ((StandardJarScanner) ctx.getJarScanner()).setScanClassPath(true); ((StandardJarScanner) ctx.getJarScanner()).setScanAllDirectories(true); ((StandardJarScanner) ctx.getJarScanner()).setScanAllFiles(true); ContextConfig contextConfig = new ContextConfig(); ctx.addLifecycleListener(contextConfig); contextConfig.setDefaultWebXml(Constants.NoDefaultWebXml); tomcat.start(); tomcat.getServer().await(); } catch (LifecycleException e) { throw new RuntimeException("Unable to launch tomcat ", e); } What do I need to do, in order to have StandardJarScanner loaded by a seperate loader than the classes that are loaded when tomcat.start() so that StandardJarScanner will honor searching for the remaining Servlet 3.0 annotations?