how to properly configure gradle build to avoid including log4j and slf4j from the resulting jar?
Solution 1
Couple things, it seems to me that your build.gradle should declare :
- spring boot gradle plugin
- apply spring boot plugin
- let spring boot manage most of your dependency versions
This script works for me:
apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'spring-boot'
group = 'uptake'
version = '0.0.1-snapshot'
description = """Spring-Boot-ReceiverAPI"""
sourceCompatibility = 1.8
targetCompatibility = 1.8
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.springframework.boot:spring-boot-gradle-plugin:1.4.1.RELEASE'
}
}
repositories {
maven { url "http://repo.maven.apache.org/maven2" }
}
dependencies {
compile 'org.springframework.boot:spring-boot-starter'
compile 'org.springframework.boot:spring-boot-starter-logging'
compile 'org.springframework.boot:spring-boot-starter-web'
compile 'org.springframework.boot:spring-boot-starter-data-jpa'
compile 'org.postgresql:postgresql'
compile 'com.fasterxml.jackson.datatype:jackson-datatype-hibernate4'
compile 'com.fasterxml.jackson.core:jackson-core'
compile 'org.apache.kafka:kafka_2.10:0.9.0.0'
compile 'org.springframework.integration:spring-integration-kafka:2.0.1.RELEASE'
compile 'org.apache.zookeeper:zookeeper:3.4.5'
compile 'commons-beanutils:commons-beanutils'
compile 'org.json:json'
compile 'org.codehaus.jackson:jackson-mapper-asl:1.5.0'
compile 'org.springframework:spring-core'
compile 'com.spotify:docker-maven-plugin:0.4.13'
}
configurations.all {
exclude module: 'slf4j-log4j12'
exclude module: 'jms'
exclude module: 'jmxtools'
exclude module: 'jmxri'
}
Now, if you check both modules with gradle dependencyInsight, only log4j-over-slf4j will be found:
$ gradle dependencyInsight --dependency slf4j-log4j12
$ No dependencies matching given input were found...
$ gradle dependencyInsight --dependency log4j-over-slf4j
:dependencyInsight
org.slf4j:log4j-over-slf4j:1.7.21 (selected by rule)
\--- org.springframework.boot:spring-boot-starter-logging:1.4.1.RELEASE
+--- compile
\--- org.springframework.boot:spring-boot-starter:1.4.1.RELEASE
+--- compile
+--- org.springframework.boot:spring-boot-starter-web:1.4.1.RELEASE
| \--- compile
+--- org.springframework.boot:spring-boot-starter-data-jpa:1.4.1.RELEASE
| \--- compile
+--- org.springframework.boot:spring-boot-starter-aop:1.4.1.RELEASE
| \--- org.springframework.boot:spring-boot-starter-data-jpa:1.4.1.RELEASE (*)
\--- org.springframework.boot:spring-boot-starter-jdbc:1.4.1.RELEASE
\--- org.springframework.boot:spring-boot-starter-data-jpa:1.4.1.RELEASE (*)
Solution 2
I solved this problem updating kafka to a new version.
Some old versions of Kafka had dependecies with jmxtools and jmxri (from log4j < 1.2.16). And this dependecies doesn't have available licences in maven and gradle.
You can resolve this doing one of this three options:
- Setting kafka in a major version(2.12 works well!)
- Setting log4j in a version upper to 1.2.16
- Excluding jmxtools and jmxri
Like I previously said, I resolved this setting the kafka version in my build.gradle:
compile group: 'org.apache.kafka', name: 'kafka_2.12', version: '2.4.0'
Eugene Goldberg
Updated on June 20, 2022Comments
-
Eugene Goldberg almost 2 years
I'm having an issue with my spring-boot application: I'm able to run it within Eclipse, but unable to run the jar file (built with gradle). I run the following command to build my project:
gradle buid
The build is successful:
gradle build :compileJava UP-TO-DATE :processResources UP-TO-DATE :classes UP-TO-DATE :findMainClass :jar :bootRepackage :assemble :compileTestJava UP-TO-DATE :processTestResources UP-TO-DATE :testClasses UP-TO-DATE :test UP-TO-DATE :check UP-TO-DATE :build BUILD SUCCESSFUL Total time: 1.214 secs
This is a fragment of the resulting jar file:
jar -tvf build/libs/springboot-receiver-api-0.1.0.jar | grep log 9988 Mon Apr 04 20:37:48 CDT 2016 BOOT-INF/lib/slf4j-log4j12-1.7.21.jar 2308 Wed Sep 21 07:11:50 CDT 2016 BOOT-INF/lib/spring-boot-starter-logging-1.4.1.RELEASE.jar 66802 Thu May 28 09:49:34 CDT 2015 BOOT-INF/lib/jboss-logging-3.3.0.Final.jar 304075 Tue Mar 29 22:24:50 CDT 2016 BOOT-INF/lib/logback-classic-1.1.7.jar 23646 Mon Apr 04 20:39:02 CDT 2016 BOOT-INF/lib/log4j-over-slf4j-1.7.21.jar 470782 Tue Mar 29 22:23:42 CDT 2016 BOOT-INF/lib/logback-core-1.1.7.jar 489884 Sun May 06 13:24:48 CDT 2012 BOOT-INF/lib/log4j-1.2.17.jar
when I attempt to run this jar file, I get this error:
java -jar build/libs/springboot-receiver-api-0.1.0.jar SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/Users/eugene/.Trash/springboot-receiverapi/build/libs/springboot-receiver-api-0.1.0.jar!/BOOT-INF/lib/slf4j-log4j12-1.7.21.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: Found binding in [jar:file:/Users/eugene/.Trash/springboot-receiverapi/build/libs/springboot-receiver-api-0.1.0.jar!/BOOT-INF/lib/logback-classic-1.1.7.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation. SLF4J: Detected both log4j-over-slf4j.jar AND bound slf4j-log4j12.jar on the class path, preempting StackOverflowError. Exception in thread "main" java.lang.reflect.InvocationTargetException 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:498) at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48) at org.springframework.boot.loader.Launcher.launch(Launcher.java:87) at org.springframework.boot.loader.Launcher.launch(Launcher.java:50) at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:58) Caused by: java.lang.ExceptionInInitializerError at org.slf4j.impl.StaticLoggerBinder.<init>(StaticLoggerBinder.java:72) 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) ... 19 more
Here is my build.gradle file:
apply plugin: 'java' apply plugin: 'maven' group = 'uptake' version = '0.0.1-snapshot' description = """Spring-Boot-ReceiverAPI""" sourceCompatibility = 1.8 targetCompatibility = 1.8 tasks.withType(JavaCompile) { options.encoding = 'UTF-8' } repositories { maven { url "http://repo.maven.apache.org/maven2" } } dependencies { compile(group: 'org.springframework.boot', name: 'spring-boot-starter-web', version:'1.2.3.RELEASE') { exclude(module: 'log4j-over-slf4j') } compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version:'1.2.3.RELEASE' compile group: 'org.postgresql', name: 'postgresql', version:'9.3-1102-jdbc41' compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-hibernate4', version:'2.8.1' compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version:'2.8.3' compile group: 'org.apache.kafka', name: 'kafka_2.10', version:'0.9.0.0' compile group: 'org.springframework.integration', name: 'spring-integration-kafka', version:'2.0.1.RELEASE' compile group: 'org.apache.zookeeper', name: 'zookeeper', version:'3.4.5' compile(group: 'commons-beanutils', name: 'commons-beanutils', version:'1.9.2') { exclude(module: 'commons-logging') } compile group: 'org.json', name: 'json', version:'20090211' compile group: 'org.codehaus.jackson', name: 'jackson-mapper-asl', version:'1.5.0' compile(group: 'org.springframework', name: 'spring-core', version:'4.3.3.RELEASE') { exclude(module: 'commons-logging') } compile group: 'com.spotify', name: 'docker-maven-plugin', version:'0.4.13' } configurations.all { exclude group: "org.slf4j", module: "slf4j-log4j12" exclude group: "log4j", module: "log4j" }
What can I do, to avoid this clash of logging libraries, and to be able to run my jar file stand-alone?