You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by bu...@apache.org on 2024/08/14 18:46:13 UTC

[Bug 69262] New: Application can fail to start if both jakarta.el::jakarta.el-api and org.apache.tomcat.embed::tomcat-embed-el are on the classpath

https://bz.apache.org/bugzilla/show_bug.cgi?id=69262

            Bug ID: 69262
           Summary: Application can fail to start if both
                    jakarta.el::jakarta.el-api and
                    org.apache.tomcat.embed::tomcat-embed-el are on the
                    classpath
           Product: Tomcat 10
           Version: 10.1.26
          Hardware: All
                OS: All
            Status: NEW
          Severity: normal
          Priority: P2
         Component: EL
          Assignee: dev@tomcat.apache.org
          Reporter: skylar.sutton@gmail.com
  Target Milestone: ------

If both the jakarta.el::jakarta.el-api and
org.apache.tomcat.embed::tomcat-embed-el JARs are on the classpath, the
application can fail to start.

Both JARs contain a jakarta.el.ExpressionFactory, and if the jakarta.el-api
version gets prioritized higher on the classpath, it will trump the
tomcat-embed-el version. This may manifest differently for each application,
but in our case it manifested as a "java.lang.ClassNotFoundException:
com.sun.el.ExpressionFactoryImpl" at startup. 

ref:
https://github.com/jakartaee/expression-language/blob/master/api/src/main/java/jakarta/el/ExpressionFactory.java
ref:
https://github.com/apache/tomcat/blob/main/java/jakarta/el/ExpressionFactory.java

Given that jakarta.el-api is the API spec and tomcat-embed-el is the
implementation, it should be assumed that a) both may be on the classpath and
b) that it is safe for both to be on the classpath (e.g. foo-api and foo-impl).

In reviewing the jakarta.el-api version of the ExpressionFactory, their
documentation outlines a clear workflow of how to tell the Factory what your
implementation class is. I belive the tomcat-embed-el ExpressionFactory should
NOT be an override of the API class, but rather something like
"ExpressionFactoryImpl" which instructions to ExpressionFactory that it should
use ExpressionFactoryImpl.

An example POM below shows a valid use case that triggered this scenario: a
springboot application, running on Tomcat Embed (Jasper), using the JSTL tag
reference implementation. The springboot WAR is generated with jakarta.el-api
prioritized higher than tomcat-embed-el in the "classpath.idx" file, which
determines the classpath order for a springboot application. Adding an
<exclusion /> for "el-api" to "jstl-api" will resolve the issue and allow the
application to start. 

e.g. 
<dependency>
        <!-- Jakarta JSTL (Standard Tag Library) API -->
        <groupId>jakarta.servlet.jsp.jstl</groupId>
        <artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
        <scope>runtime</scope>
        <exclusions>
                <exclusion>
                        <!-- Tomcat Jasper includes a jakarta.el.** package
which overrides "jakarta.el-api" -->
                        <groupId>jakarta.el</groupId>
                        <artifactId>jakarta.el-api</artifactId>
                </exclusion>
        </exclusions>
</dependency>


Broken Example:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.foo</groupId>
        <artifactId>bar</artifactId>
        <version>1.0.0-SNAPSHOT</version>

        <name>foo-bar</name>
        <packaging>war</packaging>

        <parent>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>3.3.2</version>
        </parent>

        <properties>
                <maven.version>3.2.5</maven.version>
        </properties>

        <dependencies>
                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot</artifactId>
                </dependency>
                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-web</artifactId>
                        <scope>runtime</scope>
                </dependency>
                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-autoconfigure</artifactId>
                </dependency>
                <dependency>
                        <groupId>org.apache.tomcat.embed</groupId>
                        <artifactId>tomcat-embed-core</artifactId>
                </dependency>
                <dependency>
                        <groupId>org.apache.tomcat.embed</groupId>
                        <artifactId>tomcat-embed-jasper</artifactId>
                </dependency>
                <dependency>
                        <groupId>jakarta.servlet.jsp.jstl</groupId>
                        <artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
                        <scope>runtime</scope>
                        <exclusions>
                                <exclusion>
                                        <groupId>jakarta.el</groupId>
                                        <artifactId>jakarta.el-api</artifactId>
                                </exclusion>
                        </exclusions>
                </dependency>
                <dependency>
                        <!-- Currently, Tomcat 10 does not ship with a JSTL
implementation out of the box, use the Glassfish
                                reference impl:
https://stackoverflow.com/a/4928309/215166 -->
                        <groupId>org.glassfish.web</groupId>
                        <artifactId>jakarta.servlet.jsp.jstl</artifactId>
                        <scope>runtime</scope>
                </dependency>
        </dependencies>

        <build>
                <plugins>
                        <plugin>
                                <!--
                                        The Spring Boot Maven Plugin packages
the final artifact as a runnable springboot WAR and adds the
                                        correct MANIFEST.MF entries to allow
simple startup like: java -jar artifact.war
                                        ref:
https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/
                                -->
                                <groupId>org.springframework.boot</groupId>
                               
<artifactId>spring-boot-maven-plugin</artifactId>
                                <configuration>
                                       
<mainClass>com.foo.bar.Application</mainClass>
                                        <layout>WAR</layout>
                                </configuration>
                        </plugin>
                </plugins>
        </build>
</project>

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 69262] Application can fail to start if both jakarta.el::jakarta.el-api and org.apache.tomcat.embed::tomcat-embed-el are on the classpath

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=69262

--- Comment #2 from skylar.sutton@gmail.com ---
Then I think there is an argument to be made for Tomcat to provide a JSTL
implementation, so the JSP users do not have to go out and pull in the
Glassfish reference implementation (which brings jakarta.el-api baggage). 

If you search for Tomcat Jasper JSTL the overwhelming community response is:
"Go use the Glassfish JSTL library". Jasper should have it's own JSTL library.

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 69262] Application can fail to start if both jakarta.el::jakarta.el-api and org.apache.tomcat.embed::tomcat-embed-el are on the classpath

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=69262

skylar.sutton@gmail.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |skylar.sutton@gmail.com

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 69262] Application can fail to start if both jakarta.el::jakarta.el-api and org.apache.tomcat.embed::tomcat-embed-el are on the classpath

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=69262

Mark Thomas <ma...@apache.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|---                         |INVALID

--- Comment #1 from Mark Thomas <ma...@apache.org> ---
Tomcat provides its own EL API jar. It doesn't use the version provided by
Jakarta. This is because, despite the name, the EL API contains some
implementation and Tomcat needs the flexibility to use a different
implementation.

Tomcat isn't the only container that does this.

The embedded JARs are, in response to use request, packaged in a minimum number
of JARs. Hence the tomcat-embed-el JAR contains both the EL API and
implementation.

If you add a second EL API JAR then things are going to break.

If you want to use the Jakarta EL API with Tomcat then rather than using the
tomcat-embed-el JAR use the Jakarta EL API JAR with the standard Tomcat EL
implementation - tomcat-jasper-el.

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 69262] Application can fail to start if both jakarta.el::jakarta.el-api and org.apache.tomcat.embed::tomcat-embed-el are on the classpath

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=69262

--- Comment #3 from Mark Thomas <ma...@apache.org> ---
Do you mean you want these published in Maven Central?

https://github.com/apache/tomcat/tree/main/webapps/examples/WEB-INF/lib

There are the latest JSTL JARs from https://tomcat.apache.org/taglibs.html
converted to Jakarta EE using the Tomcat migration tool.

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 69262] Application can fail to start if both jakarta.el::jakarta.el-api and org.apache.tomcat.embed::tomcat-embed-el are on the classpath

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=69262

--- Comment #4 from skylar.sutton@gmail.com ---
If the Tomcat team thinks that is the best solution - sure. 

The root issue is that the community needs JSTL tags, but there is no Apache
JSTL compatible with Jakarta (because the JSTL project was moved to the Apache
Attic).. so the community recommendation is to use a mixed bag of Glassfish
JSTL + Tomcat container. Using the Glassfish JARs is what brings the
jakarta.el-api into the classpath. 

Having an Apache JSTL that is Jakarta compliant would solve that issue. 

(TBH, I'm kind of surprised I'm the first one to report this... but maybe I'm
not and I just didn't find the other reports in my search).

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org