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.sut...@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-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org