1 Reply Latest reply on Aug 13, 2010 1:01 PM by kwutzke

    Tomcat 6, Embedded JBoss, Hibernate (future Seam): slf4j LinkageError

    kwutzke
      Hello,

      I'm new to Hibernate and especially setting up Tomcat 6 along with JBoss Embedded and Hibernate 3.5.4 (core) plus annotations and entitymanager (both 3.4.0). I put the JBoss embedded files into tomcat/lib as described here:

      http://community.jboss.org/wiki/Tomcat60x

      After that, I went to get my webapp to deploy, which I managed by using Ant deploy tasks and/or Tomcat's web interface (both work). Entering http://localhost:8080/bbstats gets me to the index.jsp, which is just static html in the following WAR structure:

      root
      +-- index.jsp
      +-- META-INF
      |    +-- MANIFEST.MF
      |    +-- persistence.xml
      +-- WEB-INF
            +-- classes
            |    +-- com ...
            +-- lib
            |    +-- antlr-2.7.6.jar
            |    +-- ... .jar
            |    +-- slf4j-api-1.5.8.jar
            +-- web.xml

      Note, that I'm manually managing the JARs just to get a feel for the material. I will look into Ivy or Maven at some point, but currently I want full control over what goes into my app. The JARs in WEB-INF/lib are:

      antlr-2.7.6.jar
      commons-collections-3.2.1.jar
      commons-lang-2.5.jar
      dom4j-1.6.1.jar
      ejb3-persistence.jar
      hibernate-annotations.jar
      hibernate-commons-annotations.jar
      hibernate-entitymanager.jar
      hibernate3.jar
      javassist-3.9.0.GA.jar
      jsf-api.jar
      jsf-facelets.jar
      jsf-impl.jar
      jta-1.1.jar
      mysql-connector-java-5.1.13-bin.jar
      slf4j-api-1.5.8.jar

      When loading the servlet I get the following exception:

      13.08.2010 13:21:38 org.apache.catalina.core.ApplicationContext log
      INFO: Marking servlet Basketball Stats as unavailable
      13.08.2010 13:21:38 org.apache.catalina.core.StandardContext loadOnStartup
      SCHWERWIEGEND: Servlet /bbstats threw load() exception
      java.lang.LinkageError: loader constraint violation: when resolving method "org.slf4j.impl.StaticLoggerBinder.getLoggerFactory()Lorg/slf4j/ILoggerFactory;" the class loader (instance of org/apache/catalina/loader/WebappClassLoader) of the current class, org/slf4j/LoggerFactory, and the class loader (instance of org/apache/catalina/loader/StandardClassLoader) for resolved class, org/slf4j/impl/StaticLoggerBinder, have different Class objects for the type org/slf4j/ILoggerFactory used in the signature
           at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:274)
           at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:242)
           at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:255)
           at org.hibernate.cfg.Configuration.<clinit>(Configuration.java:165)
           at org.hibernate.ejb.Ejb3Configuration.<clinit>(Ejb3Configuration.java:107)
           at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:124)
           at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:52)
           at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:34)
           at com.mydomain.bbstats.servlet.BasketballStatsServlet.<init>(BasketballStatsServlet.java:33)

      The code I use is:

      public class BasketballStatsServlet extends HttpServlet
      {
           //@PersistenceContext
           private EntityManagerFactory emf = Persistence.createEntityManagerFactory("bbstats");

           public BasketballStatsServlet()
           {     
                  ...

      The persistence context seems to be initialized correctly. (Note, that using @PersistenceContext doesn't seem to be supported by Tomcat).

      Now what this means is that there seem to be two slf4j JARs on the classpath. So I thought, well, let me just remove that JAR from my webapp classpath and it should be ok. However, if I omit the slf4j-api-1.5.8.jar for example, Tomcat throws an exception saying

      13.08.2010 14:18:12 org.apache.catalina.core.ApplicationContext log
      INFO: Marking servlet Basketball Stats as unavailable
      13.08.2010 14:18:12 org.apache.catalina.core.StandardContext loadOnStartup
      SCHWERWIEGEND: Servlet /bbstats threw load() exception
      javax.persistence.PersistenceException: No Persistence provider for EntityManager named bbstats
           at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:56)
           at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:34)
           at com.mydomain.bbstats.servlet.BasketballStatsServlet.<init>(BasketballStatsServlet.java:33)

      This happens when Hibernate dependencies are missing. It concerns other JARs as well.

      Now, I obviously have two of the same class trees on my classpath, but removing the one from my webapp produces even more serious results (the latter exception doesn't even reach the Hibernate code, compare the stack traces). I'm stuck. It appears as if the class loaders collide when slf4j-api.jar is present, but are unable to use the other slf4j jar when it's not in the webapp lib.

      How can I resolve this?

      I looked into the embedded JBoss JARs and thirdparty-all.jar includes slf4j, too. But I don't get why removing the slf4j JAR from the webapp lib dir doesn't work. Can anyone help, please?

      Karsten
        • 1. Re: Tomcat 6, Embedded JBoss, Hibernate (future Seam): slf4j LinkageError
          kwutzke
          Hmmm I resolved this issue. It seems like the slf4j conflict was occurring because the Hibernate entity manager init code uses that JAR. For some reason I left the instantiation of the entity manager in the <init> of the servlet, probably because I was originally using @PersistenceContext, which isn't working on Tomcat 6. I always got HTTP 404 resource not available because of that. When I moved the instantiation of the entity manager into the servlet's doGet method things started to get better. I then still got HTTP 500 errors, but the stack trace was much more helpful.

          I then made the ultimate move to move ALL Hibernate dependency JARs out of my app and put the persistence.xml into <war-root>/WEB-INF/classes/META-INF instead of <war-root>/META-INF and voila, all worked. In the aftermath, a big DUH. So all my webapp ended up needing was commons-lang and my own API. I also moved the MySQL connector JAR into Tomcat lib, but I believe that's a matter of taste. I'm tired of trying. Thank god it's friday.

          Karsten