Classpath issue between jetty-maven-plugin and tomcat-jdbc 8.0.9+ leading to ServiceConfigurationError
Asked Answered
H

3

19

I'm working on an app using :

jetty-maven-plugin:9.3.2.v20150730
tomcat-jdbc:8.0.8 (which has tomcat-juli as dependency)

After trying to upgrade the tomcat-jdbc jar to any version beyond 8.0.9+ I get the following error:

java.util.ServiceConfigurationError: org.apache.juli.logging.Log: Provider org.eclipse.jetty.apache.jsp.JuliLog not a subtype

Looking the changelog between those 2 versions I've found something that looks suspicious:

"Add a simple ServiceLoader based discovery mechanism to the JULI LogFactory to make it easier to use JULI and Tomcat components that depend on JULI (such as Jasper) independently from Tomcat. Patch provided by Greg Wilkins. (markt)"

Also, I've found that a new system property was introduced in the Apache Tomcat JDBC Connection Pool:

org.apache.tomcat.jdbc.pool.onlyAttemptCurrentClassLoader

"Controls classloading of dynamic classes, such as JDBC drivers, interceptors and validators. If set to false, default value, the pool will first attempt to load using the current loader (i.e. the class loader that loaded the pool classes) and if class loading fails attempt to load using the thread context loader. Set this value to true, if you wish to remain backwards compatible with Apache Tomcat 8.0.8 and earlier, and only attempt the current loader. If not set then the default value is false."

Unfortunately, starting the plugin with jetty:run using this property didn't resolve the issue.

Any help would be appreciated! Thanks!

Stack trace and dependencies tree :

Caused by: 
java.util.ServiceConfigurationError: org.apache.juli.logging.Log: Provider org.eclipse.jetty.apache.jsp.JuliLog not a subtype
    at java.util.ServiceLoader.fail(ServiceLoader.java:239)
    at java.util.ServiceLoader.access$300(ServiceLoader.java:185)
    at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:376)
    at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:404)
    at java.util.ServiceLoader$1.next(ServiceLoader.java:480)
    at org.apache.juli.logging.LogFactory.(LogFactory.java:78)
    at org.apache.juli.logging.LogFactory.(LogFactory.java:66)
    at org.apache.tomcat.jdbc.pool.DataSourceFactory.(DataSourceFactory.java:58)
    at local.ristretto.persistence.datasource.mail.MailDataSourceConfiguration.dataSource(MailDataSourceConfiguration.java:31)
    at local.ristretto.persistence.datasource.mail.MailDataSourceConfiguration$$EnhancerBySpringCGLIB$$497970dd.CGLIB$dataSource$0()
    at local.ristretto.persistence.datasource.mail.MailDataSourceConfiguration$$EnhancerBySpringCGLIB$$497970dd$$FastClassBySpringCGLIB$$2ba2dde9.invoke()
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:309)
    at local.ristretto.persistence.datasource.mail.MailDataSourceConfiguration$$EnhancerBySpringCGLIB$$497970dd.dataSource()
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1119)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1014)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1120)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1044)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:942)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:813)
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:464)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1119)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1014)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:956)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:747)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:434)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
    at org.eclipse.jetty.server.handler.ContextHandler.callContextInitialized(ContextHandler.java:798)
    at org.eclipse.jetty.servlet.ServletContextHandler.callContextInitialized(ServletContextHandler.java:530)
    at org.eclipse.jetty.server.handler.ContextHandler.startContext(ContextHandler.java:771)
    at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:342)
    at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1368)
    at org.eclipse.jetty.maven.plugin.JettyWebAppContext.startWebapp(JettyWebAppContext.java:320)
    at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1335)
    at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:735)
    at org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContextHandler.java:259)
    at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:511)
    at org.eclipse.jetty.maven.plugin.JettyWebAppContext.doStart(JettyWebAppContext.java:403)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114)
    at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61)
    at org.eclipse.jetty.server.handler.ContextHandlerCollection.doStart(ContextHandlerCollection.java:161)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114)
    at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132)
    at org.eclipse.jetty.server.Server.start(Server.java:405)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:106)
    at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61)
    at org.eclipse.jetty.server.Server.doStart(Server.java:372)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
    at org.eclipse.jetty.maven.plugin.AbstractJettyMojo.startJetty(AbstractJettyMojo.java:457)
    at org.eclipse.jetty.maven.plugin.AbstractJettyMojo.execute(AbstractJettyMojo.java:328)
    at org.eclipse.jetty.maven.plugin.JettyRunMojo.execute(JettyRunMojo.java:170)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:132)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:208)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:80)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:120)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:347)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:154)
    at org.apache.maven.cli.MavenCli.execute(MavenCli.java:582)
    at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:214)
    at org.apache.maven.cli.MavenCli.main(MavenCli.java:158)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
    at org.codehaus.classworlds.Launcher.main(Launcher.java:46)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
[INFO] |  +- org.springframework.data:spring-data-jpa:jar:1.8.2.RELEASE:compile               
[INFO] |  |  +- org.springframework.data:spring-data-commons:jar:1.10.2.RELEASE:compile       
[INFO] |  |  +- org.springframework:spring-orm:jar:4.1.7.RELEASE:compile                      
[INFO] |  |  |  \- org.springframework:spring-jdbc:jar:4.1.7.RELEASE:compile                  
[INFO] |  |  +- org.springframework:spring-tx:jar:4.1.7.RELEASE:compile                       
[INFO] |  |  \- org.aspectj:aspectjrt:jar:1.8.6:compile                                       
[INFO] |  +- org.postgresql:postgresql:jar:9.4-1202-jdbc42:compile                            
[INFO] |  +- org.apache.tomcat:tomcat-jdbc:jar:8.0.9:compile                                 
[INFO] |  |  \- org.apache.tomcat:tomcat-juli:jar:8.0.9:compile                              
[INFO] |  +- org.hibernate:hibernate-entitymanager:jar:5.0.1.Final:compile                    
[INFO] |  |  +- org.jboss.logging:jboss-logging:jar:3.3.0.Final:compile                       
[INFO] |  |  +- org.hibernate:hibernate-core:jar:5.0.1.Final:compile                          
[INFO] |  |  |  +- antlr:antlr:jar:2.7.7:compile                                              
[INFO] |  |  |  \- org.jboss:jandex:jar:1.2.2.Final:compile                                   
[INFO] |  |  +- dom4j:dom4j:jar:1.6.1:compile                                                 
[INFO] |  |  |  \- xml-apis:xml-apis:jar:1.0.b2:compile                                       
[INFO] |  |  +- org.hibernate.common:hibernate-commons-annotations:jar:5.0.0.Final:compile    
[INFO] |  |  +- org.hibernate.javax.persistence:hibernate-jpa-2.1-api:jar:1.0.0.Final:compile 
[INFO] |  |  +- org.apache.geronimo.specs:geronimo-jta_1.1_spec:jar:1.1.1:compile             
[INFO] |  |  \- org.javassist:javassist:jar:3.18.1-GA:compile                                 
[INFO] |  \- com.fasterxml.jackson.core:jackson-databind:jar:2.6.1:compile                    
[INFO] |     +- com.fasterxml.jackson.core:jackson-annotations:jar:2.6.1:compile              
[INFO] |     \- com.fasterxml.jackson.core:jackson-core:jar:2.6.1:compile                     

[INFO] |  +- org.slf4j:jcl-over-slf4j:jar:1.7.12:compile                                      
[INFO] |  +- org.slf4j:jul-to-slf4j:jar:1.7.12:compile                                        
[INFO] |  +- org.slf4j:log4j-over-slf4j:jar:1.7.12:compile                                    
[INFO] |  +- org.slf4j:slf4j-api:jar:1.7.12:compile                                           
[INFO] |  +- ch.qos.logback:logback-classic:jar:1.1.3:compile                                 
[INFO] |  |  \- ch.qos.logback:logback-core:jar:1.1.3:compile                                 
[INFO] |  +- org.wicketstuff:wicketstuff-logback:jar:6.20.0:compile                           
[INFO] |  +- org.apache.commons:commons-lang3:jar:3.4:compile                                 
[INFO] |  +- org.apache.commons:commons-collections4:jar:4.0:compile                          
[INFO] |  +- commons-io:commons-io:jar:2.4:compile                                            
[INFO] |  +- commons-codec:commons-codec:jar:1.10:compile                                     
[INFO] |  +- commons-beanutils:commons-beanutils:jar:1.9.2:compile                            
[INFO] |  |  \- commons-collections:commons-collections:jar:3.2.1:compile                     
[INFO] |  \- com.google.guava:guava:jar:18.0:compile                                          
[INFO] +- junit:junit:jar:4.12:test                                                           
[INFO] |  \- org.hamcrest:hamcrest-core:jar:1.3:test                                          
[INFO] +- org.springframework:spring-test:jar:4.1.7.RELEASE:test                              
[INFO] |  \- org.springframework:spring-core:jar:4.1.7.RELEASE:compile                        
[INFO] +- org.springframework:spring-web:jar:4.1.7.RELEASE:compile                            
[INFO] |  +- org.springframework:spring-aop:jar:4.1.7.RELEASE:compile                         
[INFO] |  |  \- aopalliance:aopalliance:jar:1.0:compile                                       
[INFO] |  +- org.springframework:spring-beans:jar:4.1.7.RELEASE:compile                       
[INFO] |  \- org.springframework:spring-context:jar:4.1.7.RELEASE:compile                     
[INFO] |     \- org.springframework:spring-expression:jar:4.1.7.RELEASE:compile               
[INFO] \- javax:javaee-web-api:jar:7.0:provided
Hausmann answered 18/9, 2015 at 3:47 Comment(4)
Added stack trace and dependencies tree @ChristopherSchultzHausmann
Have you copied tomcat-juli.jar from Tomcat's conf/ directory to your web application's WEB-INF/lib directory, or anywhere else that might end up in the class path of your web application?Maladjustment
Yes, today it's declared with a compile scope in my pom. Can I safely change it to provided?Hausmann
I'm no Maven expert, but tomcat-juli.jar is in fact provided by Tomcat, so you shouldn't need to mention it at all, unless you need to build against it.Maladjustment
B
20

The spring boot starter web dependency will include tomcat by default. This will confuse jetty when you start it, since it uses different versions of the juli lib.

Simply fix in your pom.xml, exlude the starter-tomcat and separately include the jetty dependency:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jetty</artifactId>
    </dependency>
Bulldoze answered 2/7, 2016 at 8:50 Comment(0)
C
9

It appears, that this is caused by Jetty using a modified Apache JSP package Jasper. It has its own version of Juli logging (check lib/apache-jsp/org.mortbay.jasper.apache-jsp-8.0.27.jar under Jetty home directory) which seems to cause all the confusion. I think, that Jetty's default webapp class loading logic causes Juli LogFactory from your webapp to be loaded everytime that class is requested. It's all good and dandy when that LogFactory has to load tomcat-jdbc classes. It gets tricky when it gets passed Jetty's modified Jasper classes, because it realises that there are type conflicts.

How you can solve this? I think there are 2 ways to do so:

1. Change Jetty webapp classloader logic

You can modify classloader logic, to always delegate class loading to parent classloader. You just need to call setParentLoaderPriority(true) on particular WebAppContext. You can do that either by Jetty configuration or by including jetty-web.xml file with your war.

2. Exclude tomcat-juli dependency

Using Maven's Dependency exclusions you can skip any transitive dependency you do not like. So just include tomcat-jdbc without tomcat-juli and you're done.

The only problem is that both solutions force you to use Jetty's modified Juli package. Haven't seen a problem with such scenario yet, but I guess at some point you might find you're missing some feature, because Jetty's modified Juli wasn't synced with Apache latest version.

Cordie answered 13/11, 2015 at 12:2 Comment(2)
Just a note, if you use setParentLoaderPriority(true) you are switching form Servlet spec classloader behavior (webapp first) to Java spec classloader behavior (parent first). If your webapp expects Servlet spec behavior, then this is not the correct way to solve this issue.Quid
With the second apporach, my JUnits fail.Susian
A
0

IF IT'S NOT A SPRING PROJECT

Here is the exclusion that I provided in pom.xml:

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-maven-plugin</artifactId>
            <version>9.4.24.v20191120</version>
             <exclusions>
                <exclusion>
                    <groupId>org.eclipse.jetty</groupId>
                    <artifactId>apache-jsp</artifactId>
                </exclusion>
             </exclusions>
        </dependency>

Also provided the plugin:

           <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.24.v20191120</version>

                <configuration>
                    <scanIntervalSeconds>10</scanIntervalSeconds>
                    <webApp>
                        <contextPath>/ezops-preprocessor</contextPath>
                    </webApp>
                </configuration>

            </plugin>

With the above exclusion, apache-jsp(Jule Logging), I am not getting that exception.

Hope this helps.!!!

Amberlyamberoid answered 2/1, 2020 at 17:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.