Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate-annotations 3.4.0.GA and slf4j?

I have a maven project A that use hibernate-annotations 3.4.0.GA which use the slf4j-api version 1.5.5 (checked through the dependency tree in the pom.xml file). Further project A specifies slf4j-log4j12 version 1.4.2 as a dependency.

I have another maven project B which depend on project A. In project B I have specified the following dependencies:

slf4j-api version 1.6.1,
logback-core version 0.9.24
logback-classic version 0.9.24

which builds fine with maven from the command line. But when I run the project from eclipse launch configuration I get:

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/C:/Users/mm/.m2/repository/org/slf4j/slf4j-log4j12/1.4.2/slf4j-log4j12-1.4.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/Users/mm/.m2/repository/ch/qos/logback/logback-classic/0.9.24/logback-classic-0.9.24.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: slf4j-api 1.6.x (or later) is incompatible with this binding.
SLF4J: Your binding is version 1.5.5 or earlier.
SLF4J: Upgrade your binding to version 1.6.x. or 2.0.x

From this message its indicated to that I need to upgrade the binding in project A to 1.6.x, but I don't see how that is possible since its included in the hibernate dependency.

Is it possible to switch the binding (updating the classpath info) when running project B so it use the 1.6.1 version instead of the version from the hibernate project?

like image 847
u123 Avatar asked Jan 21 '23 13:01

u123


1 Answers

I have a maven project A that use hibernate-annotations 3.4.0.GA which use the slf4j-api version 1.5.5 (checked through the dependency tree in the pom.xml file). Further project A specifies slf4j-log4j12 version 1.4.2 as a dependency.

That's not recommended, you should use the same versions of slf4j artifacts. From the FAQ:

Are SLF4J versions backward compatible?

With rare theoretical exceptions, SLF4J versions are backward compatible. This means than you can upgrade from SLF4J version 1.0 to any later version without problems.

However, while the SLF4J API is very stable from the client's perspective, SLF4J bindings such as slf4j-simple or slf4j-log4j12 may require a specific version of slf4j-api. Mixing different versions of slf4j artifacts can be problematic and is strongly discouraged. For instance, if you are using slf4j-api-1.5.6.jar, then you should also use slf4j-simple-1.5.6.jar, using slf4j-simple-1.4.2.jar will not work.

At initialization time, if SLF4J suspects that there may be a version mismatch problem, it emits a warning about the said mismatch. For the exact details of the version mismatch detection mechanism, please refer to the relevant entry in this FAQ.

That's something to fix.

which builds fine with maven from the command line. But when I run the project from eclipse launch configuration I get (...)

The problem is that you get the SLF4J artifacts from B and those from A (transitively) and you thus end up mixing several versions of the slf4j-api (1.5.5 and 1.6.1) and several bindings (slf4j-log4j12 and logback-classic). SLF4J is complaining about the later problem at runtime but you should fix both.

From this message its indicated to that I need to upgrade the binding in project A to 1.6.x, but I don't see how that is possible since its included in the hibernate dependency.

Yes, the message suggests upgrading a binding to a more recent version. But, more important, it reports that you have more than ONE binding on the class path: you need to choose between log4j and logback as logging backed and to provide the appropriate binding, but not both of them.

Is it possible to switch the binding (updating the classpath info) when running project B so it use the 1.6.1 version instead of the version from the hibernate project?

To strictly answer this question about controlling versions in transitive dependencies, this can be done using the dependencyManagement element. Here is an example:

<project>
  ...
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.6.1</version>
      </dependency>
    </dependencies>
  </dependencyManagement>
  ...
  <dependencies>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-entitymanager</artifactId>
      <version>3.4.0.GA</version>
    </dependency>
  </dependencies>
  ...
</project>

And artifacts having slf4j-api as dependency, such as Hibernate EntityManager, would use version 1.6.1 as shown below:

$ mvn dependency:tree
...
[INFO] +- org.hibernate:hibernate-entitymanager:jar:3.4.0.GA:compile
[INFO] |  +- org.hibernate:ejb3-persistence:jar:1.0.2.GA:compile
[INFO] |  +- org.hibernate:hibernate-commons-annotations:jar:3.1.0.GA:compile
[INFO] |  +- org.hibernate:hibernate-annotations:jar:3.4.0.GA:compile
[INFO] |  +- org.hibernate:hibernate-core:jar:3.3.0.SP1:compile
[INFO] |  |  +- antlr:antlr:jar:2.7.6:compile
[INFO] |  |  \- commons-collections:commons-collections:jar:3.1:compile
[INFO] |  +- org.slf4j:slf4j-api:jar:1.6.1:compile
[INFO] |  +- dom4j:dom4j:jar:1.6.1:compile
[INFO] |  |  \- xml-apis:xml-apis:jar:1.0.b2:compile
[INFO] |  +- javax.transaction:jta:jar:1.1:compile
[INFO] |  \- javassist:javassist:jar:3.4.GA:compile

But as I said, the real problem is that you need to have only one binding on the classpath. Either choose log4j or logback, just not both, and provide the appropriate binding.

like image 161
Pascal Thivent Avatar answered Jan 26 '23 10:01

Pascal Thivent