Monday, February 15, 2010

Solving Tomcat + JSF 2.0 Error: java.lang.LinkageError: loader constraint violation

What happens when you try running JSF 2.0 web framework on Tomcat 6? This error:

HTTP Status 500 -


type Exception report
message
description The server encountered an internal error () that prevented it from fulfilling this request.
exception
javax.servlet.ServletException: java.lang.LinkageError: loader constraint violation: when resolving interface method "javax.servlet.jsp.JspApplicationContext.getExpressionFactory()Ljavax/el/ExpressionFactory;" the class loader (instance of org/apache/jasper/servlet/JasperLoader) of the current class, org/apache/jsp/index_jsp, and the class loader (instance of org/apache/catalina/loader/StandardClassLoader) for resolved class, javax/servlet/jsp/JspApplicationContext, have different Class objects for the type javax/el/ExpressionFactory used in the signature org.apache.jasper.servlet.JspServlet.service(JspServlet.java:275) javax.servlet.http.HttpServlet.service(HttpServlet.java:717) root cause
java.lang.LinkageError: loader constraint violation: when resolving interface method "javax.servlet.jsp.JspApplicationContext.getExpressionFactory()Ljavax/el/ExpressionFactory;" the class loader (instance of org/apache/jasper/servlet/JasperLoader) of the current class, org/apache/jsp/index_jsp, and the class loader (instance of org/apache/catalina/loader/StandardClassLoader) for resolved class, javax/servlet/jsp/JspApplicationContext, have different Class objects for the type javax/el/ExpressionFactory used in the signature org.apache.jsp.index_jsp._jspInit(index_jsp.java:25) org.apache.jasper.runtime.HttpJspBase.init(HttpJspBase.java:52) org.apache.jasper.servlet.JspServletWrapper.getServlet(JspServletWrapper.java:159) org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:329) org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342) org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267) javax.servlet.http.HttpServlet.service(HttpServlet.java:717) note The full stack trace of the root cause is available in the Apache Tomcat/6.0.20 logs.

Apache Tomcat/6.0.20

The problem is simple: Tomcat ships with an old version of el-api, the Expression Language used by JSP, JSTL, and JSF.

JSF 2.0 uses the new Java EE 6 version that is EL 2.2. Unfortunately you can't just put the new EL libraries in your WEB-INF/lib because of Tomcat's restriction.

To fix this, you don't need to change your project.. but you need to patch your Tomcat installation:
  1. Delete el-api.jar from your Tomcat's lib folder.
  2.  Get the new el-api-2.2.jar from java.net and save it as el-api.jar on the Tomcat's lib folder.
You will also need to put the new el-impl.jar on your web application's WEB-INF/lib folder.

For a Maven web project, put this in your pom.xml :
                <dependency>
                    <groupId>javax.el</groupId>
                    <artifactId>el-api</artifactId>
                    <version>2.2</version>
                    <scope>provided</scope>
                </dependency>
                <dependency>
                    <groupId>org.glassfish.web</groupId>
                    <artifactId>el-impl</artifactId>
                    <version>2.2</version>
                    <scope>runtime</scope>
                </dependency>
You also need to use java.net's Maven repository:
<repositories>
    <repository>
        <id>java.net.m2</id>
        <url>http://download.java.net/maven/2</url>
        <snapshots>
           <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>
Related Articles:

6 comments:

  1. We were facing the same problem and tracked it down to the fact that we were bundling all of juel into our war file.

    I switched our build to only bundle juel-impl (not juel-api), and it fixed the issue. Example maven dependency :

    <dependency>
    <groupId>de.odysseus.juel</groupId>
    <artifactId>juel-impl</artifactId>
    <version>2.1.3</version>
    </dependency>

    ReplyDelete
  2. Actually, strike my previous comment... I did end up having to do what you outlined originally (replace the el-api.jar in tomcat/lib).

    I also had to add an exclusion to the maven dependency that I referenced above, to exclude the juel-api.jar (which comes in as a transitive dependency of juel-impl.jar).

    Here's the juel maven dependency now:

    <dependency>
    <groupId>de.odysseus.juel</groupId>
    <artifactId>juel-impl</artifactId>
    <version>2.1.3</version>
    <exclusions>
    <exclusion>
    <groupId>de.odysseus.juel</groupId>
    <artifactId>juel-api</artifactId>
    </exclusion>
    </exclusions>
    </dependency>

    Also... for what its worth, I'm using tomcat 6.0.28

    Thanks for your post - it definitely saved me time.

    ReplyDelete
  3. Thank you Lance for sharing your experience.

    I'm glad you found the article useful.

    ReplyDelete
  4. Gracias brother... En verdad, no sabía porque era ese error. Hasta que encontré tu página.
    Te debo la nota de mi proyecto.

    Ò.Ó

    ReplyDelete