Gradle & SLF4J refusing to exclude transitive dependencies results in IllegalStateException - spring

I am getting this error when running unit tests on my project:
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)
... 29 more
I need SLF4J, but not the clash that the following dependencies is setting up:
dependencies {
compile("org.springframework:spring-core:$springVersion")
compile("org.springframework:spring-jdbc:$springVersion")
// compile("org.springframework:spring-orm:$springVersion"
compile("org.springframework:spring-tx:$springVersion")
compile("org.springframework.data:spring-data-jpa:1.10.1.RELEASE") {
exclude module: "slf4j-api"
exclude module: "slf4j-over-slf4j"
exclude module: "jcl-over-slf4j"
}
// tag::jetty[]
compile("org.springframework.boot:spring-boot-starter-web:1.3.5.RELEASE") {
exclude module: "spring-boot-starter-tomcat"
exclude module: "slf4j-api"
exclude module: "slf4j-over-slf4j"
exclude module: "jcl-over-slf4j"
}
compile("org.springframework.boot:spring-boot-starter-jetty")
// end::jetty[]
// tag::actuator[]
compile("org.springframework.boot:spring-boot-starter-actuator")
// end::actuator[]
testCompile("junit:junit")
compile(group: 'org.hibernate.javax.persistence', name: 'hibernate-jpa-2.1-api', version: '1.0.0.Final')
compile("org.apache.velocity:velocity:1.7")
compile(group: 'org.slf4j', name: 'slf4j-api', version: '1.7.21')
compile('org.slf4j:log4j-over-slf4j:1.7.21')
compile(group: 'org.projectlombok', name: 'lombok', version: '1.16.8')
testCompile("org.springframework.boot:spring-boot-starter-test")
testCompile(group: 'junit', name: 'junit', version: '4.11')
}
I can stop the error via:
configurations {
all*.exclude group: "org.slf4j"
}
but then I get ClassNotFoundExceptions at runtime because slf4j is needed (and its adapters).
Any ideas? I just want to exclude slf4j from Spring's dependencies. I have seen plenty of threads on this issue but not resolve it -- are my exclusions correct?

I just excluded spring-boot-starter-logging:
configurations {
all*.exclude module: 'spring-boot-starter-logging'
}
My dependencies now look like this:
dependencies {
compile "org.springframework:spring-core:$springVersion"
compile "org.springframework:spring-jdbc:$springVersion"
compile "org.springframework:spring-orm:$springVersion"
compile "org.springframework:spring-tx:$springVersion"
compile "org.springframework.data:spring-data-jpa:1.10.1.RELEASE"
compile("org.springframework.boot:spring-boot-starter-web") {
exclude module: "spring-boot-starter-tomcat"
}
compile("org.springframework.boot:spring-boot-starter-jetty")
compile group: 'org.hibernate.javax.persistence', name: 'hibernate-jpa-2.1-api', version: '1.0.0.Final'
compile "org.apache.velocity:velocity:1.7"
compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.21'
compile group: 'org.slf4j', name: 'slf4j-log4j12', version: '1.7.21'
compile group: 'org.projectlombok', name: 'lombok', version: '1.16.8'
testCompile("junit:junit")
testCompile "org.springframework.boot:spring-boot-starter-test"
testCompile group: 'junit', name: 'junit', version: '4.11'
}

Your problem is, that you have log4j-over-slf4j - which redirects all log4j logging to slf4j - and slf4j-log4j12 - which outputs all slf4j logging to log4j - in your classpath. This means you would have an endless loop which is wrong of course.
So you have to decide what you want. Do you want to redirect all log4j logging to slf4j and then direct all slf4j logging to some other logging framework (or slf4j-simple e. g. for logging to System.out or no binding to suppress the logging) or do you want to direct all slf4j logging to log4j, then it doesn't make sense to redirect log4j logging to slf4j in the first place.
How you correctly resolve your problem heavily depends on the desired result.
You can also find out what pulls in a dependency using the gradle task dependencyInsight.

Related

Unable to fetch gradle dependency net.devh:grpc-server-spring-boot-starter

I am using grpc springboot. I can download all dependencies apart from 'net.devh:grpc-server-spring-boot-starter:2.12.0.RELEASE'.
Due to the I can't use annotation #GrpcService
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
implementation 'javax.annotation:javax.annotation-api:1.3.2'
implementation 'io.grpc:grpc-netty-shaded:1.37.0'
implementation 'io.grpc:grpc-protobuf:1.37.0'
implementation 'io.grpc:grpc-stub:1.37.0'
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.0'
implementation group: 'commons-io', name: 'commons-io', version: '2.6'
implementation 'org.springframework.boot:spring-boot-starter:2.4.5'
implementation 'net.devh:grpc-server-spring-boot-starter:2.12.0.RELEASE'
compileOnly 'jakarta.annotation:jakarta.annotation-api:1.3.5'
}
Any help much appreciated
Just try the install dependencies and reimport them.
If it doesn't work, close the IDE and open it again.

unable to start embedded tomcat server

I use eclipse spring boot ide.
and it works fine inside eclipse.
but, build when I run jar, I get an error.
The error details are as follows.
Application run failed
org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat server
my build.Gradle dependencies config as follows.
dependencies {
compile group: 'com.google.code.gson', name: 'gson', version: '2.8.6'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.2.4.RELEASE'
implementation 'org.springframework.boot:spring-boot-starter-websocket'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}

How to use Spring's reactive WebClient in a Spring Web Application which runs on Tomcat

Unable to use Spring's reactive WebClient in a Spring boot based Web Application which runs on Tomcat. Application startup itself is failing due to unresolved dependencies.
I looked at https://github.com/spring-projects/spring-boot/issues/9690 but unfortunately thats not an option for me as I cannot set the WebApplication type to None
My gradle file:
dependencies {
compile(group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa') {
exclude(module: 'tomcat-juli')
}
compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-redis'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-web'
compile group: 'org.springframework.session', name: 'spring-session'
compile group: 'org.hibernate', name: 'hibernate-java8'
compile group: 'org.hibernate', name: 'hibernate-validator', version: '5.2.4.Final'
compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-guava'
compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-hibernate5'
compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310'
compile group: 'com.google.guava', name: 'guava'
compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.3.2'
compile group: 'org.postgresql', name: 'postgresql'
compile group: 'io.jsonwebtoken', name: 'jjwt', version:'0.9.0'
compile group: 'com.nimbusds', name: 'nimbus-jose-jwt', version:'5.12'
// Spring managed dependency is not working, so resorted to using specific version
// compile('org.springframework.boot:spring-boot-starter-webflux')
compile group: 'org.springframework.boot', name: 'spring-boot-starter-webflux', version: '2.1.4.RELEASE'
/*
compile group: 'org.springframework', name: 'spring-web-reactive', version: '5.0.0.M1'
compile group: 'org.springframework', name: 'spring-web', version: '5.1.6.RELEASE'
*/
implementation 'com.auth0:jwks-rsa:0.7.0
}
bootRepackage {
enabled = false
}
Error:
Caused by: java.lang.NoClassDefFoundError: org/springframework/http/client/reactive/ClientHttpConnector
at org.springframework.web.reactive.function.client.WebClient.create(WebClient.java:144)
I then tried adding,
compile group: 'org.springframework', name: 'spring-web-reactive', version: '5.0.0.M1'
Which then complained about something else, which made me add
compile group: 'org.springframework', name: 'spring-web', version: '5.1.6.RELEASE'
But then another error shows up while starting my application, which makes me think there is some other problem.
To be precise,I simply want to call a MicroService using Reactive WebClient from within another MicroService (which is Spring Boot based Web Application).
Using RestTemplate works fine but I just wanted to try the reactive WebClient and stuck with error.
Due to the way we host our dependencies, managed dependencies are not working. Our dependency server is unable to resolve them. That's the reason for having specific version of spring boot dependencies
org.springframework.http.client.reactive.ClientHttpConnector is part of the spring-web jar so it should be available if use use spring-boot-starter-webflux or spring-boot-starter-web. If you're writing a traditional servlet based application then you should be using spring-boot-starter-web.
Check the output of gradle dependencies to ensure that you have a spring-web jar. If you do, the chances are it's somehow been corrupted and you should clear your gradle cache.
I'd also recommend that you use Spring Boot's managed dependencies rather than specifify version numbers on each dependency. This will ensure that you get versions that are known to work well together.

dependencies syntax in gradle (closed)

I am trying to understand Gradle.I got this in my code
testCompile group: 'org.mockito', name: 'mockito-core', version: '2.9.0'
It works.
I wanted to understand the concepts.
Remote dependencies in Gradle follow the same format as Maven. Dependencies are structured as follows
compile 'group:name:version'
or this alternative syntax:
compile group: 'xxx', name: 'xxxxx', version: 'xxxx'
The same syntax is valid also for tests.
dependencies {
testCompile "org.mockito:mockito-core:2.9.0"
}
or
dependencies {
testCompile group: 'org.mockito', name: 'mockito-core', version: '2.9.0'
}

how to exclude jar from fileTree in upstream projects?

We have the following configuration in a project...
configurations {
//compile.exclude module: 'commons'
//all*.exclude group: 'org.gradle.test.excludes', module: 'reports'
all*.exclude module: 'log4j'
}
dependencies {
compile group: 'org.slf4j', name: 'slf4j-api', version: '1.6.6'
compile group: 'org.slf4j', name: 'log4j-over-slf4j', version: '1.6.6'
compile group: 'com.google.inject', name: 'guice', version: '3.0'
compile group: 'com.google.protobuf',name: 'protobuf-java', version: '2.4.1'
//compile group: 'org.asteriskjava',name: 'asterisk-java', version: '1.0.0.M3'
//to be erased soon
compile group: 'commons-configuration',name:'commons-configuration',version: '1.8'
//compile group: 'org.bouncycastle', name: 'bcpg-jdk16', version: '1.46'
compile project(':sdi-master')
compile project(':sdi-webserver')
}
unfortunately, the project sdi-webserver has it's own log4j brought in from a filetree like so
project(':sdi-webserver') {
project.ext.genLibDir = file('lib')
dependencies {
compile project(':sdi-master')
compile fileTree(dir: '../webserver/lib', include: '*.jar')
compile fileTree(dir: '../webserver/play-1.2.4/framework/lib', include: '*.jar')
compile fileTree(dir: '../webserver/play-1.2.4/framework', include: 'play-*.jar')
}
How do we exclude this jar so it is not part of the dependencies. The above excludes that we have only works for repositories and transitive dependencies and doesn't work for fileTree, but we still need to somehow exclude the jar file as we want eclipse task building correct .classpath, we want configurations.compile having accurate info for copying jars, etc. etc.
thanks,
Dean
Simply use an exclude on fileTree. Syntax is the same as for include.

Resources