Reputation: 7279
I am working on a new project and attempting to use Gradle for the first time. The application is a web application so I have configured the war
and jetty
plugins at the top of my gradle.build
:
apply plugin: 'war'
apply plugin: 'jetty'
In my code I program to the Apache Commons Logging API for logging. One of my dependencies (OpenSAML) uses the SLF4J API for its logging. I am most familiar with log4j 1.2 for the actual logging configuration, so that is what I want to use to actually perform the logging.
To configure these dependencies I have the following in my gradle.build
file:
// Logging API
compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.21'
compile group: 'org.slf4j', name: 'jcl-over-slf4j', version: '1.7.21'
// Logging at runtime
runtime group: 'org.slf4j', name: 'slf4j-log4j12', version: '1.7.21'
runtime group: 'log4j', name: 'log4j', version: '1.2.17'
When I run my application using the command gradle jettyRunWar
and the servlet executes which tries to log something I receive the following error:
java.lang.ExceptionInInitializerError
at org.slf4j.impl.StaticLoggerBinder.<init>(StaticLoggerBinder.java:72)
at org.slf4j.impl.StaticLoggerBinder.<clinit>(StaticLoggerBinder.java:45)
at org.slf4j.LoggerFactory.bind(LoggerFactory.java:150)
at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:124)
at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:412)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:357)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:383)
at sso.HomePageServlet.<clinit>(HomePageServlet.java:23)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at java.lang.Class.newInstance(Class.java:442)
at org.mortbay.jetty.servlet.Holder.newInstance(Holder.java:153)
at org.mortbay.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:428)
at org.mortbay.jetty.servlet.ServletHolder.getServlet(ServletHolder.java:339)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:390)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:440)
at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230)
at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:326)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:926)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:549)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:410)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Caused by: java.lang.IllegalStateException: Detected both log4j-over-slf4j.jar AND bound slf4j-log4j12.jar on the class path, preempting StackOverflowError. See also http://www.slf4j.org/codes.html#log4jDelegationLoop for more details.
at org.slf4j.impl.Log4jLoggerFactory.<clinit>(Log4jLoggerFactory.java:54)
... 33 more
The error is obviously that log4j-over-slf4j.jar
is in the classpath as well. My application does not list this. Using gradle dependencies --configuration runtime
does not list this .jar file either. The only place this .jar exists is in the gradle\lib
directory. Is it possible that Gradle is including its own classpath when launching Jetty?
Is there any way to prevent this?
The solution outlined here does not seem to work.
gradle -v
shows:
------------------------------------------------------------
Gradle 2.14.1
------------------------------------------------------------
Build time: 2016-07-18 06:38:37 UTC
Revision: d9e2113d9fb05a5caabba61798bdb8dfdca83719
Groovy: 2.4.4
Ant: Apache Ant(TM) version 1.9.6 compiled on June 29 2015
JVM: 1.8.0_45 (Oracle Corporation 25.45-b02)
OS: Windows 7 6.1 amd64
Upvotes: 0
Views: 459
Reputation: 8463
I know this is a few years and versions too late, but just for complete closure I confirm that internal gradle logging is interfering. My log includes the following:
SLF4J: Found binding in [jar:file:/**/.gradle/**/gradle-2.14.1/lib/gradle-logging-2.14.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/**/build/tmp/jettyRunWar/webapp/WEB-INF/lib/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
Where gradle-logging-2.14.1.jar contains the offending org.apache.log4j.Log4jLoggerFactory class.
Since we're dealing with a legacy monolithic multi-project build, we're just not ready to bump the gradle version up (leave well enough alone). We encountered this problem when the dependency slf4j-log4j12 was update from version 1.7.2 to 1.7.25 (we didn't leave well enough alone). The resolution, for us, was to bump that back down to version 1.7.13, just before the check was added.
Upvotes: 0
Reputation: 7279
Just after posting my question I saw that Gradle 3.0 was released. In the release notes it says that the jetty
plugin has been deprecated and that one should use Gretty
.
Upgrading to Gradle 3.0 and switching to using Gretty
fixed the problem.
The fact that the jetty
plugin includes Gradle's classpath in your webapps' runtime path is a problem with the way the jetty
plugin works and it looks like it will not be fixed.
Upvotes: 4