Module xyz reads package org.apache.commons.logging from both commons.logging and jcl.over.slf4j

Module xyz reads package org.apache.commons.logging from both commons.logging and jcl.over.slf4j

modulesWhen I tried to migrate one of my projects to Java 9 and modules, I encountered this error - module xyz reads package org.apache.commons.logging from both commons.logging and jcl.over.slf4j. As this package (org.apache.commons.logging) is very popular, it might happen to you also. That is why I want to share with you some background of this issue and a solution that worked for me.

Background

This error may occur when you use Java module system in Java 9 and your project contains at least two JARs that have a package with the same name. It sounds crazy, but there are such JARs. In my case one of them is commons-logging and another is jcl-over-slf4j. The problematic package is already mentioned in the error message - org.apache.commons.logging. When I take a look at these two JARs, I can see they both contain the same package.

commonsLogging

slf4j

Such case is called split packages and it is an error made by the JAR creator. In a normal, healthy project each package should be defined in only one module/JAR.

You may wonder why it is such a big issue in Java 9 as it worked correctly in Java 8 - exactly the same JARs. The difference is in the approach. In Java 8 such problems were handled by the classpath in runtime. It does not mean there was no problem. It was but usually invisible. It was vulnerable to the classpath configuration in each environment the application was deployed. Java 9 developers decided to favor fail fast approach and implemented Java module system which takes responsibility of handling such issues from the classpath. As the Java module system is used in the application code, problems with dependencies can be acted upon at the compilation time. If anything violates the rules, the compiler says NO.

 

Solution to module xyz reads package from both ...

There is no way to disable this check. A solution that worked for me was to find libraries that had dependencies on these two JARs. I found out that spring-boot-starter-data-jpa instructed Gradle to download commons-logging.

Then I excluded commons-logging from dependencies of spring-boot-starter-data-jpa.

dependencies {
    compile(
group: "org.springframework.boot", name: "spring-boot-starter-data-jpa", version: spring_boot_version) {
        exclude
group: 'commons-logging', module: 'commons-logging'
   
}
}

It helped me. I no longer had commons-logging in the libraries. Obviously, there are other libraries that depends on commons-logging, their configuration have to be changed also.

Logging is still possible because as you remember, there is also jcl-over-slf4j. with org.apache.commons.logging package.

 

Final solution

The above solution worked for me but it is definitely not the utlimate way of solving it. The ball is in the libraries' developers court. It is them who should fix their JARs so we could use them without solving such issues :-)