Reputation: 1111
I am trying to use clj-tika
and ring-middleware-logger
in the same project. If I use either of them, everything compiles and works as expected.
However, as soon as I start using both at the same time, I am getting this error at compile time:
CompilerException java.lang.NoClassDefFoundError: org/slf4j/impl/StaticLoggerBinder
Normally this means that SLF4J is not in the classpath. However, if I do a lein classpath
in my project folder, I can clearly see:
C:\Users\Proprietaire\.m2\repository\org\slf4j\slf4j-api\1.5.6\slf4j-api-1.5.6.jar
So, it should be something else.
Then I ran: mvn dependency:tree
to see if there could be SLF4J compatibility issues, and here is what I got for ring-middleware-logger
:
[INFO] +- ring.middleware.logger:ring.middleware.logger:jar:0.4.3:compile
[INFO] | +- onelog:onelog:jar:0.4.3:compile
[INFO] | | +- org.clojure:tools.logging:jar:0.2.3:compile
[INFO] | | \- clj-logging-config:clj-logging-config:jar:1.9.6:compile
[INFO] | | +- log4j:log4j:jar:1.2.16:compile
[INFO] | | \- swank-clojure:swank-clojure:jar:1.3.2:compile
[INFO] | \- org.clojars.pjlegato:clansi:jar:1.3.0:compile
And for Tika
:
[INFO] +- clj-tika:clj-tika:jar:1.2.0:compile
[INFO] | \- org.apache.tika:tika-parsers:jar:1.2:compile
[INFO] | +- org.apache.tika:tika-core:jar:1.2:compile
[INFO] | +- org.gagravarr:vorbis-java-tika:jar:0.1:compile
[INFO] | | \- org.gagravarr:vorbis-java-core:jar:tests:0.1:test,provided
[INFO] | +- edu.ucar:netcdf:jar:4.2-min:compile
[INFO] | | \- org.slf4j:slf4j-api:jar:1.5.6:compile
[INFO] | +- org.apache.james:apache-mime4j-core:jar:0.7.2:compile
[INFO] | +- org.apache.james:apache-mime4j-dom:jar:0.7.2:compile
[INFO] | +- org.apache.commons:commons-compress:jar:1.4.1:compile
[INFO] | | \- org.tukaani:xz:jar:1.0:compile
[INFO] | +- org.apache.pdfbox:pdfbox:jar:1.7.0:compile
[INFO] | | +- org.apache.pdfbox:fontbox:jar:1.7.0:compile
[INFO] | | \- org.apache.pdfbox:jempbox:jar:1.7.0:compile
[INFO] | +- org.bouncycastle:bcmail-jdk15:jar:1.45:compile
[INFO] | +- org.bouncycastle:bcprov-jdk15:jar:1.45:compile
[INFO] | +- org.apache.poi:poi:jar:3.8:compile
[INFO] | +- org.apache.poi:poi-scratchpad:jar:3.8:compile
[INFO] | +- org.apache.poi:poi-ooxml:jar:3.8:compile
[INFO] | | +- org.apache.poi:poi-ooxml-schemas:jar:3.8:compile
[INFO] | | | \- org.apache.xmlbeans:xmlbeans:jar:2.3.0:compile
[INFO] | | \- dom4j:dom4j:jar:1.6.1:compile
[INFO] | +- org.apache.geronimo.specs:geronimo-stax-api_1.0_spec:jar:1.0.1:c
ompile
[INFO] | +- org.ccil.cowan.tagsoup:tagsoup:jar:1.2.1:compile
[INFO] | +- asm:asm:jar:3.1:compile
[INFO] | +- com.googlecode.mp4parser:isoparser:jar:1.0-RC-1:compile
[INFO] | | \- org.aspectj:aspectjrt:jar:1.6.11:compile
[INFO] | +- com.drewnoakes:metadata-extractor:jar:2.4.0-beta-1:compile
[INFO] | +- de.l3s.boilerpipe:boilerpipe:jar:1.1.0:compile
[INFO] | +- rome:rome:jar:0.9:compile
[INFO] | | \- jdom:jdom:jar:1.0:compile
[INFO] | +- org.gagravarr:vorbis-java-core:jar:0.1:compile
[INFO] | \- com.googlecode.juniversalchardet:juniversalchardet:jar:1.0.3:com
So, one use LOG4J and the other one SLF4J. If I stop using one of these packages, I do not get that error, as soon as I start using both I start getting the one above...
I am not a Java developer, so I am kind of stuck to fix this error. I have the intuition that I can probably make something available in my classpath or something such that the compiler finds it.
In any case, I am not sure why adding ring-middleware-logger
conflict with Tika
when none use the same packages (even if they are probably related in ways I don't know).
Upvotes: 2
Views: 858
Reputation: 96394
There are two slf4j jars, an api jar that the library depends on, and the implementation jar that the application uses. This is from the Libraries section of the slf4j manual:
Authors of widely-distributed components and libraries may code against the SLF4J interface in order to avoid imposing an logging framework on their end-user. Thus, the end-user may choose the desired logging framework at deployment time by inserting the corresponding slf4j binding on the classpath, which may be changed later by replacing an existing binding with another on the class path and restarting the application. This approach has proven to be simple and very robust.
As of SLF4J version 1.6.0, if no binding is found on the class path, then slf4j-api will default to a no-operation implementation discarding all log requests. Thus, instead of throwing a NoClassDefFoundError because the org.slf4j.impl.StaticLoggerBinder class is missing, SLF4J version 1.6.0 and later will emit a single warning message about the absence of a binding and proceed to discard all log requests without further protest. For example, let Wombat be some biology-related framework depending on SLF4J for logging. In order to avoid imposing a logging framework on the end-user, Wombat's distribution includes slf4j-api.jar but no binding. Even in the absence of any SLF4J binding on the class path, Wombat's distribution will still work out-of-the-box, and without requiring the end-user to download a binding from SLF4J's web-site. Only when the end-user decides to enable logging will she need to install the SLF4J binding corresponding to the logging framework chosen by her.
Basic rule Embedded components such as libraries or frameworks should not declare a dependency on any SLF4J binding but only depend on slf4j-api. When a library declares a transitive dependency on a specific binding, that binding is imposed on the end-user negating the purpose of SLF4J. Note that declaring a non-transitive dependency on a binding, for example for testing, does not affect the end-user.
SLF4J usage in embedded components is also discussed in the FAQ in relation with logging configuration, dependency reduction and testing.
Since you're using 1.5 version of the api jar, you're seeing it throw the NoClassDefFoundError. It sounds like you have a library using the 1.5.6 version of the api jar that you're trying to use with the 1.6.2 version of the implementation jar.
There is a compatibility report on the slf4j website but it appears to not be updated yet for 1.6 or later. I would expect you'd have better chances getting 1.6.2 to work with the 1.5.6 version than the opposite (if the logger tool is using 1.6-specific features then downgrading the version won't work). I'd try naming the 1.6.2 version as an explicit dependency and see if that works.
Upvotes: 2
Reputation: 1111
Thanks to @nathan-hughes for the pointers. Here is the final resolution of this issue.
The problem I had is that I didn't initially saw with the maven
dependencies report that the org.clojure:tools.logging:jar
library was including the slf4j
jar version 1.6.2, which I found on the project's GitHub pom.xml
file.
Then the next question was: how can we fix this slf4j incompatibilities issues? As @nathan-hughes suggested, just to make the version 1.6.2 a dependency.
So, what I did is simple to add the following two dependencies into my project.clj
file:
[org.slf4j/slf4j-api "1.6.2"]
[org.slf4j/slf4j-log4j12 "1.6.2"]
(both are required otherwise logging won't work with the ring middleware)
Now that my Clojure project has these two libraries as direct dependencies, then this force the other packages to use it as well.
Now the compilation errors are gone, and the ring.middleware.logger
package is working as expected, and Tika is not complaining neither which suggest that it works with this version of SLF4J without any issues.
Upvotes: 3