Apache Struts 1.3.x Forward Compatibility Container Support
Verified application server and JDK combinations for NES for Apache Struts 1.3.x Forward Compatibility
Overview
NES for Apache Struts 1.3.x Forward Compatibility targets Jakarta EE 9 (Servlet 5.0) and Java 11. It also runs on newer servlet containers and newer JDKs. This page records the combinations that have been verified by running the full Struts example application suite against each one, and the configuration each container family requires.
Verified combinations
Each cell was exercised by deploying the eight Struts example applications and requesting a page from each, plus a multipart/form-data upload. The Java 21 and Java 25 cells were also exercised with a small application that combines a Tiles layout, a DispatchAction, Validator rules, a Spring 6 root context and JPA where the server provides it.
| Application server | Servlet | Jakarta EE | Java 11 | Java 17 | Java 21 | Java 25 |
|---|---|---|---|---|---|---|
| Apache Tomcat 10.1 | 6.0 | 10 | Yes | Yes | Yes | Yes |
| Apache Tomcat 11.0 | 6.1 | 11 | — | Yes | Yes | Yes |
| Eclipse Jetty 12 | 6.0 | 10 | — | Yes | Yes | Yes (note 1) |
| WildFly 30 | 6.0 | 10 | Yes | Yes | Yes | No (note 2) |
| WildFly 40 | 6.1 | 11 | — | Yes | Yes | Yes |
| GlassFish 8 | 6.1 | 11 | — | — | Yes | Yes |
| Red Hat JBoss EAP 8.1 | 6.0 | 10 | — | Yes | Yes | No (note 3) |
A dash means the application server itself does not support that JDK, not that Struts fails there:
- Tomcat 11, Jetty 12 and WildFly 40 require Java 17 or later.
- GlassFish 8 requires Java 21.
- Red Hat lists Java 17 and 21 for JBoss EAP 8.1, not Java 11.
Notes:
- The Jetty 12 documentation gives Java 17 as the minimum and publishes no support policy for later JDKs. The Jetty project does build and test Jetty 12 on Java 25 in its continuous integration and fixes Java 25 issues as they are reported.
- WildFly 30 does not start on Java 25. Its module loader fails before any application is deployed with
UnsupportedOperationException: Setting a system-wide Policy object is not supported. WildFly 30.0.1.Final is the last 30.x release, so upgrade WildFly to run on Java 25. - Red Hat does not support JBoss EAP 8.1 on Java 25; EAP 8.1 is supported on Java 17 and 21, and Java 25 is listed for EAP 8.2. Struts deployed and passed the same checks on EAP 8.1 with Java 25 in our testing, but because the server is unsupported there, neither is this combination. Run EAP 8.1 on Java 21, or move to an EAP release that Red Hat supports on Java 25.
Tested versions: Tomcat 10.1.59, Tomcat 11.0.25, Jetty 12.0.39, WildFly 30.0.1.Final, WildFly 40.0.1.Final, GlassFish 8.0.4 and JBoss EAP 8.1 Update 8, on Eclipse Temurin builds of each JDK, with 1.3.10-struts-1.4.5.
The core framework — struts-core, struts-taglib, struts-tiles and struts-el — works on every combination marked Yes. The struts-faces module is subject to the limitation described below.
Running on Java 25
On Java 25, we recommend running Struts only on an application server whose maintainer supports Java 25.
Struts itself ran on Java 25 on every server we tested that starts on it. Whether a combination is supported, though, is decided by the server's maintainer, and HeroDevs cannot support a server on a JDK its own maintainer does not:
- Tomcat 10.1 and 11.0 support any stable Java release at or above their minimum, per Apache Tomcat Versions.
- WildFly 40 is recommended on Java 25 by the WildFly project.
- Jetty 12 publishes Java 17 as its minimum and no policy for later JDKs, but is built and tested on Java 25 by the Jetty project.
- GlassFish 8 runs on JDK 21 to JDK 25.
- JBoss EAP 8.1 is not supported by Red Hat on Java 25. Run it on Java 21, or move to an EAP release that Red Hat supports on Java 25.
- WildFly 30 does not run on Java 25.
If you start the server with the Java Security Manager enabled, remove that setting before moving to Java 24 or later. The Security Manager was permanently disabled in Java 24, and EAP 8.1 refuses to start with it on Java 25: The security manager is not supported in Java 25.
Jakarta EE application servers
Full Jakarta EE servers such as WildFly and GlassFish supply their own Jakarta Faces and CDI implementations, which changes what your application has to provide.
Add a CDI bean archive marker
On a Jakarta EE server, Jakarta Faces 4 initializes for every deployed web module and refuses to start unless the module is a CDI bean archive. Without this, deployment fails with IllegalStateException: CDI is not available, even for an application that uses no Faces and no CDI at all.
Add an empty bean archive marker to each web application:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
https://jakarta.ee/xml/ns/jakartaee/beans_3_0.xsd"
version="3.0"
bean-discovery-mode="annotated">
</beans>
This is required on GlassFish 8 for all web applications. On WildFly it is required only for applications that use Jakarta Faces.
Do not bundle a CDI implementation
If your web application bundles weld-servlet-shaded so that CDI is available on a plain servlet container, remove it before deploying to a Jakarta EE server. Its ServletContainerInitializer collides with the CDI implementation the server already provides, and deployment fails with:
Error invoking ServletContainerInitializer org.jboss.weld.environment.servlet.EnhancedListener
Package every tag library class you reference
GlassFish instantiates every tag class in every TLD on the classpath at deployment time, where Tomcat and Jetty load a tag class only when a page actually uses it. A tag library whose implementation classes are missing therefore deploys fine on Tomcat and fails to start on GlassFish.
The common case is struts-el, which ships struts-tiles-el.tld but declares struts-tiles as an optional dependency. If you use struts-el, add struts-tiles explicitly:
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts-tiles</artifactId>
<version>1.3.10-struts-1.4.5</version>
</dependency>
Otherwise deployment fails with NoClassDefFoundError: org/apache/struts/tiles/taglib/InsertTag.
Jakarta Faces support
struts-faces requires Jakarta Faces 3.x. It does not work on Jakarta Faces 4.
The struts-faces tag library is built on the Jakarta Faces JSP tag API — UIComponentELTag and UIComponentClassicTagBase. That API was deprecated in Faces 3.0 and removed in Faces 4.0, which supports Facelets views only. As a result:
- Supported: servlet containers where you supply Jakarta Faces yourself and can pin a 3.x implementation, such as Tomcat 10.1 and Jetty 12.
- Not supported: Jakarta EE 10 and 11 application servers, which ship Faces 4 and use it in preference to any implementation bundled in your application. On WildFly 30 and later and on GlassFish 8, Faces views resolve as Facelets and requests fail with
FacesException: /<view>.xhtml Not Found in ExternalContext as a Resource. - Not supported: Apache Tomcat 11. Jakarta Pages 4.0 does not run the Faces 3.x JSP view path correctly; pages render an empty response body.
Applications that use struts-faces should stay on a Jakarta EE 9 or 10 servlet container with Faces 3.x. Migrating the views from JSP to Facelets is required before moving to a Faces 4 environment.
Request character encoding
Apache Tomcat sets a default request character encoding in its conf/web.xml:
<request-character-encoding>UTF-8</request-character-encoding>
Most other containers, including Jetty and WildFly's Undertow, leave the request encoding unset when the client does not send one. Code that assumes ServletRequest.getCharacterEncoding() returns a value will behave differently on those containers.
Note
On 1.3.10-struts-1.4.4 and earlier, a multipart/form-data POST that does not declare a charset fails on containers that do not default the request encoding, with IllegalArgumentException: Null charset name. This is fixed in 1.3.10-struts-1.4.5. If you cannot upgrade, set the request encoding explicitly — for example with a servlet filter that calls ServletRequest.setCharacterEncoding — when deploying to Jetty, WildFly or GlassFish.
Scripting support
struts-scripting uses Apache BSF to run script actions. If you use it with Groovy, the Groovy version matters on newer JDKs.
Groovy 1.x calls setAccessible on JDK-internal members. JEP 396 made that a hard failure in Java 16, so on Java 17 and later the engine fails to load and the request fails with:
org.apache.bsf.BSFException: unable to load language: groovy
Use Groovy 3 with its BSF engine, which needs no --add-opens flags on Java 11, 17, 21 or 25:
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
<version>3.0.25</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-bsf</artifactId>
<version>3.0.25</version>
</dependency>
Groovy 3 is the newest line that ships a BSF engine; groovy-bsf was discontinued after Groovy 4.0.0-alpha-2.