How to depend on log4j in a Sonarqube plugin? - java

I am developing a SonarQube 5.6 plugin. This plugin depends on a library X (a third party library). Library X depends on Log4J. To resolve the dependency problem I am adding log4j dependency in pom.xml with provided scope as defined in SonarQube documentation. But at runtime I am getting class not found exceptions related to log4j.
When I change my third party library, so that it does not use log4j anymore (basically log4j related code is commented out), the problem is gone.
How should I add the log4j dependency in SonarQube or what should I do so that the problem with log4j is resolved in my SonarQube plugin? Or what is the best way to deal with such problem when container says it will provide the dependency but it is not?
The dependency is declared like this:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>

You should exclude any log4j dependency, and instead rely on log4j-over-slf4j to redirect any log4j call to slf4j.
log4j-over-slf4j should be already provided in the runtime plugin classloader, so basically it should work out of the box. What kind of problem are you facing?

Related

Dependencies version conflict -> different slf4j versions but can't exclude wrong one

I've got almost same question like was asked here:
Maven + SLF4J: Version conflict when using two different dependencies that require two different SLF4J versions
(but unfortunately all answers didn't help our case)
Case:
I need to include firebase dependency
<dependency>
<groupId>com.google.firebase</groupId>
<artifactId>firebase-admin</artifactId>
<version>5.11.0</version>
</dependency>
Which depends on slf4j version 1.7.25.
Afterwards we implemented some integration test (using spring and junit) and now we're facing the clash
SLF4J: The requested version 1.5.6 by your slf4j binding is not compatible with [1.6, 1.7]
SLF4J: See http://www.slf4j.org/codes.html#version_mismatch for further details.
But when I run " mvn dependency:tree" I don't see any other dependency on slf4j. So it's clearly something "outside" of the project.
I'm also unable to just exclude the slf4j from firebase because it's mandatory and I'm unable to use it without it.
Is there any chance how to check where the dependency comes from or how to exclude the older version (in case that it's gonna work with the newer one)?
Important rule: Declaring a dependency on an artifact A, say version v, in a local project P overrides other declarations made by the dependencies of P on A. Your project will have A version v imported, regardless the version(s) declared by your other dependencies for A.
In your case, declare explicitly the dependencies you want for slf4j-api as well as the desired binding.
See also Introduction to the Dependency Mechanism which states:
Dependency mediation - this determines what version of a dependency
will be used when multiple versions of an artifact are encountered.
Currently, Maven 2.0 only supports using the "nearest definition"
which means that it will use the version of the closest dependency to
your project in the tree of dependencies. You can always guarantee a
version by declaring it explicitly in your project's POM

Mixing log4j 1.x and log4j 2 with third party libraries dependending on log4j 1.x

I'm maintaining a Maven project that uses log4j 1.x with a large codebase. Not only is log4j 1.x used in existing code, it is also used by some third party libraries on which the project depends.
I want to start using log4j 2 now, but I wonder if it is worth the hassle.
I know it is possible to mix the two (cf. Mixing log4j 1.x and log4j 2) but what about the third party libraries that depend on log4j 1.x, I'm afraid there will be conflicts.
So should I rather stick to log4j 1.x or risk a dependency hell by upgrading to log4j 2?
I've done so myself. I don't think there will be any issue.
Even the project I did for had third party libraries.
You can use log4j-1.2-api-2.x.jar simply.
Remove your older log4j-1.2.x.jar and replace with below three jars:
log4j-1.2-api-2.x - will handle third party libraries depending on older log4j version.
log4j-api-2.x.jar
log4j-core-2.x.jar
Moreover, for your own code, you can follow migration steps to start using log4j2 api and third party libraries will continue using bridge between older and newer version that is log4j-1.2-api-2.x.jar (aka log4j 1.x bridge)
Below is the official documentation:
Migrate from log4j-1.x to log4j-2
It seems that perhaps the naming has changed since #Nitin answered the question. According to the log4j site, the Maven dependency is:
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-1.2-api</artifactId>
<version>2.2</version>
</dependency>
</dependencies>

Using spring boot how to exclude module from spring-data-releasetrain

I am migrating everything to spring-boot version 1.4.3.RELEASE.
Before the migration I was already using spring-data-solr version 2.1.0.RELEASE.
After introduction of spring boot i started noticing some errors, missing methods etc...
So i did some digging and found that within spring boot dependencies, spring-data-releasetrain uses older version of spring-data-solr than the version that is mandatory for me.
I have attempted to redeclare dependency with the version in my pom.xml, with no luck.
What is odd is that when i check my build path under the maven dependencies, the dependency is right for spring-data-solr version 2.1.0.RELEASE. So this does not cause any compile time issues, this happens only at run time...
I was wondering whether i can just exclude spring-data-solr and reimport my own? or is there better way to manage that?
Yes you can exclude the unwanted versions and reimport your own.
But this makes only sense, if your version of spring-data-solr is compatible with the spring-boot version you are using, at compile-time as well as at run-time.
The easiest way to do this, is to declare the desired version in the dependencyManagement section of your pom. See introduction-to-dependency-mechanism
dependency management takes precedence over dependency mediation for transitive dependencies
Which means, the version you declare in dependency management should override the versions from transitive dependencies.
I had constellations, where this was not sufficient and I still found the unwanted version in my classpath. If this happens, you have to exclude that unwanted dependency.
In Maven an exclusion looks like this :
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.0.7.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
</exclusions>
</dependency>
In the above code I am excluding spring-beans, so it is not introduced in the unwanted version required by spring-security-oauth2.
You need to do this for all dependencies, that somehow tear in your spring-data-solr in an unwanted version.
Your best friend when doing this is
mvn dependency:tree -Dverbose -Dincludes=org.springframework.data:spring-data-solr
Which shows you exactly, which dependencies your project has to spring-data-solr and why they are there. See Maven for details
So you make mvn dependency:tree, add exclusion and repeat until you have no dependency to the unwanted version anymore.
Than finally you add once the dependency to the desired version.

Solving Maven dependency convergence issues

I use the maven-enforcer-plugin to check for dependency convergence issues. A typical output would be:
[WARNING] Rule 1: org.apache.maven.plugins.enforcer.DependencyConvergence failed
with message:
Failed while enforcing releasability the error(s) are [
Dependency convergence error for junit:junit:3.8.1 paths to dependency are:
+-foo:bar:1.0-SNAPSHOT
+-ca.juliusdavies:not-yet-commons-ssl:0.3.9
+-commons-httpclient:commons-httpclient:3.0
+-junit:junit:3.8.1
and
+-foo:bar:1.0-SNAPSHOT
+-junit:junit:4.11
]
Seeing this message, I would normally "solve" it by excluding the transitive dependency, e.g.
<dependency>
<groupId>ca.juliusdavies</groupId>
<artifactId>not-yet-commons-ssl</artifactId>
<version>0.3.9</version>
<exclusions>
<!-- This artifact links to another artifact which stupidly includes
junit in compile scope -->
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
I'd like to understand whether this is truly a fix and the risks involved in excluding libraries in this fashion. As I see it:
The "fix" is normally safe, provided I'm choosing to use the newer version. This relies on the library authors maintaining backwards compatibility.
There is typically no impact on the Maven build (since the nearer definition wins), however by excluding the dependency I'm telling Maven that I know about this problem and thus appeasing the maven-enforcer-plugin.
Are my thoughts correct and is there an alternative way of handling this issue? I'm interested in answers that focus on the general case - I realise the junit example above is a little strange.
We all agree that JUnit should never be set to another scope than test. Generally speaking I don't think either that there is another solution than excluding the unwanted dependency, so we all agree that your are right to do it.
A SIMPLE CASE :
As Andreas Krueger says, there may be a risk with versions (I actually encountered it). Let say that the project's dependencies are the following:
+-foo:bar:1.0-SNAPSHOT
+-group1:projectA:2.0
+-group2:projectB:3.8.1
+-group2:projectB:4.11
Note that it is only a mere simplification of your case. Seeing this dependency tree, you would exclude the dependency projectB given by projectA :
<dependency>
<groupId>group1</groupId>
<artifactId>projectA</artifactId>
<version>2.0</version>
<exclusions>
<exclusion>
<groupId>group2</groupId>
<artifactId>projectB</artifactId>
</exclusion>
</exclusions>
</dependency>
After packaging the project with maven, the remaining dependency would be group2-someProjectB-4.11.jar, version 4.11 and not 3.8.1. Everything would be fine and the project would run without encountering any problem at all.
Then, a while after, let say that you decide to upgrade to the next version of project A, version 3.0 which adds new great features :
<dependency>
<groupId>group1</groupId>
<artifactId>projectA</artifactId>
<version>3.0</version>
<exclusions>
<exclusion>
<groupId>group2</groupId>
<artifactId>projectB</artifactId>
</exclusion>
</exclusions>
</dependency>
The problem is that you are not aware yet that projectA version 3.0 also have upgraded its dependency projectB to version 5.0 :
+-foo:bar:1.0-SNAPSHOT
+-group1:projectA:3.0
+-group2:projectB:5.0
+-group2:projectB:4.11
In that case, the exclusion you would have made a while ago excludes projectB version 5.0.
However, projectA version 3.0 needs the improvements from project B version 5.0. Because of the exclusion, after packaging the project with maven, the remaining dependency would be group2-someProjectB-4.11.jar, version 4.11 and not 5.0. At the moment you use any of projectA's new features, the program wouldn't run correctly.
WHAT WAS THE SOLUTION ?
I encountered this problem in a Java-EE project.
A team developped database services. They packaged it as projectA. Each time they updated the services, they also updated a file listing all their current dependencies and the current versions.
ProjectA was a dependency for the Java-EE project I was working on. Each time the service-team updated ProjectA, I also checked the versions' updates.
In fact, there is no harm in excluding a dependency. But each time you update a dependency where an exclusion has been set, You have to check :
if this exclusion still makes sense.
if you need to upgrade the version of the excluded dependency in your own project.
I guess maven exclusions are like kitchen knifes. It's sharp, cuts vegetables with no effort, but requires care when handling it...
If JUnit as an artifact is coming through as a dependency in compile scope, it is a bug of one of your libraries, here: ca.juliusdavies.
JUnit should always be included in test scope. Thus, it is not packed into the produced .jar, .war or .ear file, on successful build.
Generally speaking, there is no harm in excluding already included dependencies, as when library 1 and library 2 share one common dependency.
The only problem, of course, that can occur, is when library 1 and library 2 include different versions of the same dependent artifact. This can cause run-time errors, when the features of the library have changed.
Fortunately, this is not often the case, unless the difference in the version numbers is great. In general, it is advisable to include the latest dependency version and exlude the older one. This is most of the time viable.
If not, check wheter there are updates to the first-level dependencies of your project.

Changing dependency of a inherited dependency

I'm using JBoss AS 7 with Maven, and also added RichFaces, that I'm almost sure, don't come with JBoss. So I added that to my pom.xml:
<dependency>
<groupId>org.richfaces.core</groupId>
<artifactId>richfaces-core-impl</artifactId>
<version>4.1.0.Final</version>
<scope>compile</scope>
</dependency>
But Richfaces also have its dependencies, so cssparser and sac also comes with compile scope, but they are also inside JBoss AS 7, so the following warning comes when I run JBoss:
Deployment "deployment.test.war" is using a private module ("org.w3c.css.sac:main") which may be changed or removed in future versions without notice.
Deployment "deployment.test.war" is using a private module ("net.sourceforge.cssparser:main") which may be changed or removed in future versions without notice.
I believe that this warning appears because I have this module both on my war and on JBoss, so I want to know: There is a way to change the scope of them to provided, in my POM? Even if they are inherited?
No, you can't change transitive dependencies' scopes. The best you can do is to exclude these dependencies using <exclusions> in your dependency declaration.

Categories