Spring Boot Embedded Tomcat Dependency Throws Exception On Startup
Asked Answered
G

1

10

I'm porting an old application from JBoss/Wildfly to run on tomcat. Most everything I've been able to accomplish with the resources found on the web. However, I am not having much luck with the latest issue. I learned early on that I had to add

providedRuntime('org.apache.tomcat.embed:tomcat-embed-jasper')

as a dependency for request routing. If I don't include this dependency, I will get 404 errors when making a request. Now, this doesn't appear to have any adverse effect on my application, but I don't appreciate startup errors if nothing is wrong.

The target environment for this is AWS running Tomcat 8 and it works just fine when deployed. I only ever see this error running locally (DEBUG enabled):

2017-04-10 09:40:26.957 DEBUG 45630 --- [ost-startStop-1] o.a.tomcat.util.scan.StandardJarScanner  : Scanning JAR [file:/Users/bhodgson/.gradle/caches/modules-2/files-2.1/org.apache.velocity/velocity/1.6.2/1b470ec12a9b8aa69b0458a7e477dacb2cbdd6a0/velocity-1.6.2.jar] from classpath
2017-04-10 09:40:26.958 DEBUG 45630 --- [ost-startStop-1] o.a.tomcat.util.scan.StandardJarScanner  : Scanning JAR [file:/Users/bhodgson/.gradle/caches/modules-2/files-2.1/net.minidev/accessors-smart/1.1/a527213f2fea112a04c9bdf0ec0264e34104cd08/accessors-smart-1.1.jar] from classpath
2017-04-10 09:40:26.958 DEBUG 45630 --- [ost-startStop-1] o.a.tomcat.util.scan.StandardJarScanner  : Scanning JAR [file:/Users/bhodgson/.gradle/caches/modules-2/files-2.1/com.googlecode.json-simple/json-simple/1.1.1/c9ad4a0850ab676c5c64461a05ca524cdfff59f1/json-simple-1.1.1.jar] from classpath
2017-04-10 09:40:26.958 DEBUG 45630 --- [ost-startStop-1] o.a.tomcat.util.scan.StandardJarScanner  : Scanning JAR [file:/Users/bhodgson/.gradle/caches/modules-2/files-2.1/org.objenesis/objenesis/2.1/87c0ea803b69252868d09308b4618f766f135a96/objenesis-2.1.jar] from classpath
2017-04-10 09:40:26.959 DEBUG 45630 --- [ost-startStop-1] o.a.tomcat.util.scan.StandardJarScanner  : Scanning JAR [file:/Users/bhodgson/.gradle/caches/modules-2/files-2.1/com.sun.xml.bind/jaxb-core/2.2.11/c3f87d654f8d5943cd08592f3f758856544d279a/jaxb-api.jar] from classpath
2017-04-10 09:40:26.963  WARN 45630 --- [ost-startStop-1] o.a.tomcat.util.scan.StandardJarScanner  : Failed to scan [file:/Users/bhodgson/.gradle/caches/modules-2/files-2.1/com.sun.xml.bind/jaxb-core/2.2.11/c3f87d654f8d5943cd08592f3f758856544d279a/jaxb-api.jar] from classloader hierarchy

java.io.FileNotFoundException: /Users/bhodgson/.gradle/caches/modules-2/files-2.1/com.sun.xml.bind/jaxb-core/2.2.11/c3f87d654f8d5943cd08592f3f758856544d279a/jaxb-api.jar (No such file or directory)
    at java.util.zip.ZipFile.open(Native Method) ~[na:1.8.0_121]
    at java.util.zip.ZipFile.<init>(ZipFile.java:219) ~[na:1.8.0_121]
    at java.util.zip.ZipFile.<init>(ZipFile.java:149) ~[na:1.8.0_121]
    at java.util.jar.JarFile.<init>(JarFile.java:166) ~[na:1.8.0_121]
    at java.util.jar.JarFile.<init>(JarFile.java:130) ~[na:1.8.0_121]
    at org.apache.tomcat.util.scan.JarFileUrlJar.<init>(JarFileUrlJar.java:60) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.tomcat.util.scan.JarFactory.newInstance(JarFactory.java:48) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.tomcat.util.scan.StandardJarScanner.process(StandardJarScanner.java:338) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.tomcat.util.scan.StandardJarScanner.scan(StandardJarScanner.java:288) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.jasper.servlet.TldScanner.scanJars(TldScanner.java:262) [tomcat-embed-jasper-8.5.11.jar:8.5.11]
    at org.apache.jasper.servlet.TldScanner.scan(TldScanner.java:104) [tomcat-embed-jasper-8.5.11.jar:8.5.11]
    at org.apache.jasper.servlet.JasperInitializer.onStartup(JasperInitializer.java:101) [tomcat-embed-jasper-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5178) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1419) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_121]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_121]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_121]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_121]

java.io.FileNotFoundException: /Users/bhodgson/.gradle/caches/modules-2/files-2.1/com.sun.xml.bind/jaxb-impl/2.2.11/a49ce57aee680f9435f49ba6ef427d38c93247a6/jaxb-core.jar (No such file or directory)
    at java.util.zip.ZipFile.open(Native Method) ~[na:1.8.0_121]
    at java.util.zip.ZipFile.<init>(ZipFile.java:219) ~[na:1.8.0_121]
    at java.util.zip.ZipFile.<init>(ZipFile.java:149) ~[na:1.8.0_121]
    at java.util.jar.JarFile.<init>(JarFile.java:166) ~[na:1.8.0_121]
    at java.util.jar.JarFile.<init>(JarFile.java:130) ~[na:1.8.0_121]

The problem is, the dependency resolution fails because there is no version attached to the JAR path that is scanned. Here is my local repo for the missing file(s):

bhodgson-mbp:a49ce57aee680f9435f49ba6ef427d38c93247a6 bhodgson$ pwd
/Users/bhodgson/.gradle/caches/modules-2/files-2.1/com.sun.xml.bind/jaxb-impl/2.2.11/a49ce57aee680f9435f49ba6ef427d38c93247a6
bhodgson-mbp:a49ce57aee680f9435f49ba6ef427d38c93247a6 bhodgson$ ls -lt
total 2048
-rw-r--r--  1 bhodgson  staff  1047863 Apr 10 08:44 jaxb-impl-2.2.11.jar

This happens for only jaxb-impl and jaxb-core

I've tried cleaning up dependency collisions but didn't find anything other than one older version of jaxb-impl as a transient dependency.

So what can I do? I see that all dependencies are being resolved from a gradle cache, but don't understand why the requested dependency isn't resolving to a correct version. I'm going to guess because this is typically included with either the JRE/JDK or Tomcat itself.

Here is my gradle file:

buildscript {
    ext {
        springBootVersion = '1.5.2.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse-wtp'
apply plugin: 'org.springframework.boot'
apply plugin: 'war'

war {
    archiveName = "ROOT.war"
    destinationDir = new File("${rootDir}/runway/FS_ROOT/opt/tomcat/webapps/")
}

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

configurations {
    providedRuntime
}

dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.springframework.boot:spring-boot-starter-security')
    compile('org.springframework:spring-oxm:4.3.5.RELEASE')
    compile('org.springframework.webflow:spring-webflow:2.4.4.RELEASE')
    compile('org.springframework.security:spring-security-taglibs')

    compile('commons-lang:commons-lang:2.6')
    compile('commons-io:commons-io:2.1')
    compile('commons-logging:commons-logging:1.2')
    compile('commons-digester:commons-digester:2.1')
    compile('commons-beanutils:commons-beanutils:1.9.3')
    compile('commons-fileupload:commons-fileupload:1.2.2')
    compile('commons-codec:commons-codec:1.8')

    compile('joda-time:joda-time:2.1')

    compile('com.jcraft:jsch:0.1.42')

    compile('org.codehaus.jackson:jackson-mapper-asl:1.9.5')

    compile('com.sun.jersey:jersey-client:1.19.3')
    compile('com.sun.jersey.contribs:jersey-spring:1.19.3')
    compile('com.sun.jersey:jersey-json:1.19.3'){
        exclude module: 'jaxb-impl' 
    }

    compile('javax.servlet:javax.servlet-api:3.1.0')
    compile('javax.servlet.jsp:jsp-api:2.2')

    compile('org.apache.cxf:cxf-rt-frontend-jaxws:3.1.6')
    compile('org.apache.cxf:cxf-rt-transports-http:3.1.6')
    compile('org.apache.tiles:tiles-core:3.0.7')
    compile('org.apache.tiles:tiles-extras:3.0.7')
    compile('org.apache.tiles:tiles-servlet:3.0.7')
    compile('org.apache.tiles:tiles-jsp:3.0.7')
    compile('org.apache.tiles:tiles-api:3.0.7')
    compile('org.apache.tiles:tiles-template:3.0.7')

    compile('com.github.dandelion:datatables-jsp:1.1.0')
    compile('com.github.dandelion:datatables-compression-yui:0.9.3')
    compile('com.github.dandelion:datatables-servlet2:0.9.3')

    compile('com.sun.xml.bind:jaxb-core:2.2.11')
    compile('com.sun.xml.bind:jaxb-impl:2.2.11')

    testCompile('org.testng:testng:6.3.1')
    testCompile('org.easymock:easymock:3.1')
    testCompile('org.springframework.boot:spring-boot-starter-test')

    providedRuntime('javax.servlet:jstl')
    providedRuntime('org.apache.tomcat.embed:tomcat-embed-jasper')
    providedRuntime('org.springframework.boot:spring-boot-starter-tomcat')
}
Gesticulatory answered 10/4, 2017 at 16:6 Comment(0)
C
9

I faced with same problem and did some research.

The problem is tomcat TldScanner that searches tld files in jars. It uses StandardJarScanner and according Tomcat Issue 59226 recursively searches jars defined in jar manifest under Class-Path header.

To construct path to dependency found in manifest it appends dependency name to source jar path. It works well for jars in same directory such as lib directory in exploded war or tomcat lib directory, but fail in such cases where classpath constructed from .m2 or .gradle cache:

path from

/Users/bhodgson/.gradle/caches/modules-2/files-2.1/com.sun.xml.bind/jaxb-core/2.2.11/c3f87d654f8d5943cd08592f3f758856544d279a/jaxb-core.jar

concatenated with jaxb-api.jar from manifest and resulting path is invalid

/Users/bhodgson/.gradle/caches/modules-2/files-2.1/com.sun.xml.bind/jaxb-core/2.2.11/c3f87d654f8d5943cd08592f3f758856544d279a/jaxb-api.jar

For example it could happen when you start application from IDE.

Here instructions how to disable manifest scan for JarScanner or filter out jars that you sure not contain tld files: https://mcmap.net/q/468830/-after-upgrade-from-spring-boot-1-2-to-1-5-2-filenotfoundexception-during-tomcat-8-5-startup

Also this answer contains information about Tomcat JarScanner issues: https://mcmap.net/q/340725/-upgrade-from-tomcat-8-0-39-to-8-0-41-results-in-39-failed-to-scan-39-errors

Chasidychasing answered 15/8, 2018 at 11:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.