AFTER upgrade from Spring boot 1.2 to 1.5.2, FileNotFoundException during Tomcat 8.5 Startup
Asked Answered
I

4

30

I upgraded Spring Boot from 1.2.0 to 1.5.2.

After that upgrade, Tomcat 8.5 is throwing FileNotFoundException during startup.

Below is one of those exceptions, It is throwing more than ~10 similar exceptions.

I have no idea about the purpose of these jars, In other words, I didn't add <dependency> for these jars in pom.xml.

INFO: Starting Servlet Engine: Apache Tomcat/8.5.11
Apr 06, 2017 3:53:57 PM org.apache.tomcat.util.scan.StandardJarScanner scan
WARNING: Failed to scan [file:/C:/Users/myname/.m2/repository/com/sun/xml/ws/jaxws-rt/2.1.7/jaxws-api.jar] from classloader hierarchy
java.io.FileNotFoundException: C:\Users\myname\.m2\repository\com\sun\xml\ws\jaxws-rt\2.1.7\jaxws-api.jar (The system cannot find the file specified)
    at java.util.zip.ZipFile.open(Native Method)
    at java.util.zip.ZipFile.<init>(ZipFile.java:219)
    at java.util.zip.ZipFile.<init>(ZipFile.java:149)
    at java.util.jar.JarFile.<init>(JarFile.java:166)
    at java.util.jar.JarFile.<init>(JarFile.java:130)
    at org.apache.tomcat.util.scan.JarFileUrlJar.<init>(JarFileUrlJar.java:60)
    at org.apache.tomcat.util.scan.JarFactory.newInstance(JarFactory.java:48)
    at org.apache.tomcat.util.scan.StandardJarScanner.process(StandardJarScanner.java:338)
    at org.apache.tomcat.util.scan.StandardJarScanner.scan(StandardJarScanner.java:288)
    at org.apache.jasper.servlet.TldScanner.scanJars(TldScanner.java:262)
    at org.apache.jasper.servlet.TldScanner.scan(TldScanner.java:104)
    at org.apache.jasper.servlet.JasperInitializer.onStartup(JasperInitializer.java:101)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5178)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1419)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

Any help would be appreciated.

Individuality answered 6/4, 2017 at 20:9 Comment(1)
@AntonNovopashin, Thanks for the response, I solved this error and documented the solution as answer.Individuality
I
44

RootCause:

As per Tomcat Wiki, Servlet 3.0 specification requires Jar scanning during server startup.

Tomcat is using org.apache.tomcat.util.scan.StandardJarScanner for this purpose.

From the javadoc of StandardJarScanner.

The default JarScanner implementation scans the WEB-INF/lib directory followed by the provided classloader and then works up the classloader hierarchy. This implementation is sufficient to meet the requirements of the Servlet 3.0 specification as well as to provide a number of Tomcat specific extensions. The extensions are:

  • Scanning the classloader hierarchy (enabled by default) Testing all files to see if they are JARs (disabled by default)

  • Testing all directories to see if they are exploded JARs (disabled by default)

  • All of the extensions may be controlled via configuration.

Solution1: Spring Boot specific.

We can disable this jar scanning.

I disabled it by adding below property in application-xxx.properties file. This property is Spring Boot specific.

# Comma-separated list of additional patterns that match jars to ignore for TLD scanning.    
server.tomcat.additional-tld-skip-patterns=*.jar

You can find similar properties from Tomcat here.

These properties can be used to configure traditional tomcat (non-spring boot) applications.

Solution2: Spring specific

You can disable the JarScanner for manifest files as below.

@Bean
public EmbeddedServletContainerFactory embeddedServletContainerFactory() {
  return new TomcatEmbeddedServletContainerFactory() {
    @Override
    protected void postProcessContext(Context context) {
      ((StandardJarScanner) context.getJarScanner()).setScanManifest(false);
    }
  };
}

Solution3 : Traditional Standalone Tomcat:

<Context>
  ...
  <JarScanner scanManifest="false"/>
  ...
</Context>

Refer : The Jar Scanner Component.

Individuality answered 7/4, 2017 at 14:18 Comment(3)
But since those are part of the JDK why is it scanning the maven repo for them? Disable works but shouldn't it not search those jar in their ?Outride
Great. Helped me identify issue. In my case I filtered the specific jars as a comma separated list: server.tomcat.additional-tld-skip-patterns=oraclepki.jar,osdt_core.jar,osdt_cert.jarRubicund
Are those solution good if you have a tag library in your JSP files? The jar will not be included in your runtime.Annoyance
S
18

Just to improve Sundaraj's findings... disabling TLD scanning completely will break JSP/JSTL support.

The issue is that the classpath itself is OK, only Tomcat additionally scans the manifest files of each Jar, and since with Maven each Jar is in its own directory, that generates meaningless paths (probably running from Eclipse?).

So if you want to keep using JSP with JSTL, you should disable just the manifest scanning.

For Spring Boot 2.0, add this to your application's configuration:

  @Bean
  public TomcatServletWebServerFactory tomcatFactory() {
    return new TomcatServletWebServerFactory() {
      @Override
      protected void postProcessContext(Context context) {
        ((StandardJarScanner) context.getJarScanner()).setScanManifest(false);
      }
    };
  }
Spinet answered 7/9, 2018 at 20:31 Comment(3)
probably why it was necessary for us to add the tld files to the classpath ;)Wrote
@Spinet hello, your solution will break jstl support too, actually - my thread linkDistant
Works for me with Spring Boot 2.4.1.Nudibranch
F
1

JarScannerFactory loaded StandardJarScanner which we need to configure here, so this (for spring boot 2.1.8) works also.

import org.apache.tomcat.JarScanner;
import org.apache.tomcat.util.scan.StandardJarScanner;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class WebContextConfiguration {

    @Bean
    public ServletContextInitializer servletContextInitializer() {
        return context -> context.setAttribute(
                JarScanner.class.getName(),
                new StandardJarScanner() {{
                    setScanManifest(false);
                }}
        );
    }
}
Ferroconcrete answered 13/3, 2020 at 22:46 Comment(0)
S
0

For me it working after I add to

tomcat.util.scan.StandardJarScanFilter.jarsToSkip=\

*.jar

In catalina.properties.

She answered 30/5, 2022 at 15:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.