Does Spring Data force dependency on SLF4j? - spring

The Spring docs explicitly mention that spring only depends on on commons-logging.
However, if i add a dependency to Spring Data MongoDb, gradle adds a dependency on slf4j.
org.springframework.data:spring-data-commons:1.5.1.RELEASE
+--- org.springframework:spring-core:3.1.4.RELEASE (*)
+--- org.springframework:spring-beans:3.1.4.RELEASE (*)
+--- org.slf4j:slf4j-api:1.7.1
\--- org.slf4j:jcl-over-slf4j:1.7.1
Does this mean I am forced to use SLF4j if i use spring data?

Yes, we have a compile time dependency on the Slf4j API as it's the de-facto standard logging API for Java and the one causing the least hassle of all the options available: JUL - I better don't leave a word on this one (see this one if you still need to be convinced), Commons Logging - runtime provider detection has proven a PITA.
We additionally require jcl-over-slf4j to provide a Commons Logging implementation to satisfy the Commons Logging dependency of the core Spring framework, a dependency it has to maintain for legacy reasons but would have not been introduced in the first place if Slf4j had been available back in the days.
So, yes. We're setting incentives to do the "right thing" (tm), read: "the way the Java community has agreed on at large". If you really want to stick to Commons Logging, simply add the slf4j-jcl bridge and you're set. If you want to remove the jcl-over-slf4j bridge, simply exclude the dependency.

You can disable SLF4J logging in Spring Data by adding to pom.xml:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${spring-data-jpa.version}</version>
<!-- Exclude slf4j logging in favor of log4j -->
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>${commons-logging.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>

SLF4J is only a Logging Facade that in spring case will delegate in commons logging, using the jcl-over-slf4j dependency.
If you want your app to use commons-logging you can simply exclude slf4j dependencies.

Related

Spring Boot 3 JSP Issue

I've been having issues with JSP since moving to Java 17 and Spring Boot 3. I know that we need to use jakarta.* instead of javax.*, but is there something I'm missing? I am using Spring Tools 4 and just running a basic web app using JSP. When using the following dependencies
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jakarta.servlet.jsp.jstl</artifactId>
</dependency>
The project runs, but I get the following error
The superclass "javax.servlet.http.HttpServlet", determined from the Dynamic Web Module facet version (2.5), was not found on the Java Build Path
I can get rid of it by adding the javax servlet dependency
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
But that goes against using javax.* dependencies with Spring Boot 3.
I have read these articles and tried adding the jakarta.servlet.jsp dependency with no luck.
https://debugah.com/solved-tomcat10-error-jakarta-servlet-servletexception-class-com-kuang-servlet-helloservlet-is-not-a-servlet-22749/
https://howtodoinjava.com/java/exception-handling/solved-the-superclass-javax-servlet-http-httpservlet-was-not-found-on-the-java-build-path-in-eclipse/
Solved!
All I had to do was go into Project Properties and under Project Faces, change my Dynamic Web Module from 2.5 to 5.0
The JSTL warning can be suppressed under Properties->Web->JSP Files->Validation->Custom actions->Other problems with TagExtraInfo class (Just change from 'Warning' to 'Ignore')

Maven transitive dependency on system scoped dependency

I have a spring boot project (2.1.3) in which I had to add a jar file supplied by one of our partners (Referred with com.aesenc group id). I added it as a system scoped dependency even though it is against the recommendation as this repo already had other system scoped dependencies (will address this in future). This broke one of the API calls due to a transitive dependency in the parnter-supplied jar (commons-codec). Spring boot started using this commons-codec instead of the one that came with the spring bom. To resolve the issue I added exclusion to the system scoped dependency
<dependency>
<groupId>aesenc.group</groupId>
<artifactId>com.aesenc</artifactId>
<version>1.0</version>
<scope>system</scope>
<exclusions>
<exclusion> <!-- declare the exclusion here -->
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</exclusion>
</exclusions>
<systemPath>${basedir}/src/main/resources/libs/AESEnc/AESEnc.jar</systemPath>
</dependency>
This didn't solve the issue. So after going through the maven documentation I added commons-codec updated version as a dependency in the current project to make it an immediate child in the dependency graph
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
This alone also didn't solve the issue. But by moving it above the com.aesenc in the pom file the issue got resolved. So I'm confused about my understanding of how dependency resolution is happening in Maven.
This didn't work:
My project +
|
+-aesenc-+
| |
| +commons-codec-v1.10
|
+commons-codec-v1.15
My assumption is that this is how the dependency tree is and just by adding v1.15 as a dependency would have solved the issue irrespective of the ordering of it in pom.
This worked:
My project +
|
+commons-codec-v1.15
|
+-aesenc-+
|
+commons-codec-v1.10
Would like to know where my assumptions have gone wrong.

How does spring boot check for classes that don't exist on the classpath using conditionalonclass annotation?

Somewhere it is mentioned that asm is used behind the scenes. If anyone can point me where it is done in the framework or an example would be greatly appreciated.
Imagine the following case
dependencyA contains dependencyB
and your POM looks like the following
<dependency>
<groupId>com.company.name</groupId>
<artifactId>dependencyA</artifactId>
<version>1.1.1</version>
<exclusions>
<exclusion>
<groupId>com.company.name</groupId>
<artifactId>dependencyB</artifactId>
</exclusion>
</exclusions>
</dependency>
so you added dependencyA excluding dependencyB to your project in the other word the dependencyB is not in your classPath --> so if you used #ConditionOnClass(com.company.name.dependencyB.myService.class) it wont execute the code

Perfomance Test and API test are not working together in same framework

#ptrthomas - I am able to perform API test and performance test separate in karate. But when I try to merge both in same framework, either of them stopped working.
Reason that I can see here - karate-core is sub dependency of both karate-junit4 and karate-apache. But both of them install different version of karate-core. Hence either have to exclude one of them. But wherever you exclude it, it will stop working. If you exclude it from karate-junit4 then API test will not work, if you exclude it from karate-apache or gatling, performance will not work.
Is there any common version for dependencies for both performance and API test (which run through junit) or any github location where someone might have integrated both in one project?
Below are the version that I am using -
UTF-8 1.8 3.6.0 0.9.0.RC3 2.2.4
<dependency>
<groupId>com.intuit.karate</groupId>
<artifactId>karate-junit4</artifactId>
<version>0.2.7</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>com.intuit.karate</groupId>
<artifactId>karate-core</artifactId>
</exclusion>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.intuit.karate</groupId>
<artifactId>karate-apache</artifactId>
<version>${karate.version}</version>
</dependency>
<dependency>
<groupId>com.intuit.karate</groupId>
<artifactId>karate-gatling</artifactId>
<version>${karate.version}</version>
<scope>test</scope>
</dependency>
Can someone please help here?
Just use this sample project: https://github.com/ptrthomas/karate-gatling-demo
This has the right dependencies set as a simple, stand-alone project and many teams have used and validated it.
If you are still facing issues, please follow the instructions here: https://github.com/intuit/karate/wiki/How-to-Submit-an-Issue

Add log4j maven dependency to war without having it in compile time

Our application uses slf4j, but has dependency to
slf4j api
slf4j over log4j
log4j
The problem is that very often IDE imports classes from log4j and not from slf4j.
Ideally, i want to have only slf4j api as a maven dependency for my application and pack slf4j binding with log4j only at the time i building a war.
I found several solutions so far:
Add libs to WEB-INF/lib folder. This is bad, because i have no maven dependency control and have to store binary in my repo which is not the best thing to do.
Use maven-war plugin with overlays. But as i understand adding dependency to overlay will require to declare dependency (at least as compile)
Is it ok to have only dependency for slf4j api? How to package other dependencies to war without declaring them as project dependencies?
Thanks!
Please simply specify dependency to slf4j-log4j in runtime scope.
So during compile and test time class from runtime scope will not be available.
Also in IDE it shouldn't be visible - I checked it in IntelliJ.
Of course all artifacts with runtime scope will be put in WEB-INF/lib directory.
Example:
...
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
<scope>runtime</scope>
</dependency>
...

Resources