Jakarta EE Servers: GlassFish, WildFly, Payara, Open Liberty and TomEE
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the section bibliography. |
This page is written against Jakarta Faces 4.1 (API jakarta.faces-api 4.1.2, part of Jakarta EE 11), Java 17 or later, and the
server releases current on 2026-10-08: Eclipse GlassFish 8.0.5, WildFly 41.0.1.Final, Payara 7.2026.9, Open Liberty 26.0.0.10
and Apache TomEE 10.2.0. Every server was downloaded from Maven Central, started with the same small Bookshelf WAR and queried
for the Faces implementation it actually used (the RuntimeInfoBean below). All five were run on JDK 21. Claims that were not run are marked as such. Apache Tomcat is not a Jakarta EE server and has
no bundled Faces implementation; running Faces on it is the subject of a separate page (Tomcat and Weld).
An application server already contains a Faces implementation, a CDI container, Servlet, Expression Language and (on most) Bean
Validation. A Faces application written for a server therefore ships no Faces JARs: the WAR holds the views, the classes and the
descriptors, and compiles against the APIs with provided scope. That makes the WAR small, but it also means the Faces
implementation, and its version, is chosen by the server and not by your pom.xml. This page shows which one you get, how to
deploy, and what is different between the five products.
One WAR for Every Server
The WAR used on all five servers is the Bookshelf catalogue in its smallest useful form: a Book record, an
application-scoped BookService, a request-scoped CatalogueBean and two Facelets views that use the shared layout template.
The packages follow the conventions of this section (org.example.bookshelf.model, .service and .web, resource bundle
variable msg, template /WEB-INF/templates/layout.xhtml).
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>bookshelf</artifactId>
<version>1.0.0</version>
<packaging>war</packaging>
<properties>
<maven.compiler.release>17</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
<dependencies>
<!-- APIs only: the server supplies Faces, CDI, Servlet and EL at run time -->
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-web-api</artifactId>
<version>11.0.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>bookshelf</finalName>
</build>
</project>
The Web Profile API JAR contains the Faces, CDI, Servlet and Expression Language APIs, so one provided dependency is enough
(see the Maven WAR section of Project Setup for the alternative of declaring
jakarta.faces-api alone). Packaging the API JAR in WEB-INF/lib instead would put a second copy of jakarta.faces.* next to
the server’s own and is the classic cause of class-loading errors on every server below.
<?xml version="1.0" encoding="UTF-8"?>
<web-app 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/web-app_6_0.xsd"
version="6.0">
<servlet>
<servlet-name>facesServlet</servlet-name>
<servlet-class>jakarta.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>facesServlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<context-param>
<param-name>jakarta.faces.PROJECT_STAGE</param-name>
<param-value>Production</param-value>
</context-param>
<welcome-file-list>
<welcome-file>catalogue.xhtml</welcome-file>
</welcome-file-list>
</web-app>
<?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_4_0.xsd"
version="4.0" bean-discovery-mode="annotated"/>
The descriptors are written at Servlet 6.0, beans.xml 4.0 and faces-config.xml 4.0 on purpose: the same WAR has to deploy
on TomEE 10.2.0, which is a Jakarta EE 10 server (see Apache TomEE 10.2), as well as on the four Jakarta EE 11 servers, and
nothing in it needs Faces 4.1. If you only target EE 11 servers you can move the descriptors to the 6.1 and 4.1 schemas. The
PROJECT_STAGE context parameter is set to Production here; see
Project Stages for what each stage changes. The Facelets
views are the catalogue and a diagnostic page:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="jakarta.faces.html"
xmlns:f="jakarta.faces.core"
xmlns:ui="jakarta.faces.facelets">
<ui:composition template="/WEB-INF/templates/layout.xhtml">
<ui:define name="title">#{msg['catalogue.title']}</ui:define>
<ui:define name="content">
<h:dataTable value="#{catalogueBean.books}" var="book">
<h:column><f:facet name="header">#{msg['catalogue.isbn']}</f:facet>#{book.isbn}</h:column>
<h:column><f:facet name="header">#{msg['catalogue.titleColumn']}</f:facet>#{book.title}</h:column>
<h:column><f:facet name="header">#{msg['catalogue.author']}</f:facet>#{book.author}</h:column>
<h:column><f:facet name="header">#{msg['catalogue.year']}</f:facet>#{book.year}</h:column>
</h:dataTable>
<p><h:link outcome="runtime" value="Runtime info"/></p>
</ui:define>
</ui:composition>
</html>
Source: Jakarta EE Tutorial: Facelets
The diagnostic page prints which implementation answered. It uses only public Java and Faces API calls, so it works unchanged on every server and is the quickest way to confirm what a deployment really runs.
package org.example.bookshelf.web;
import jakarta.enterprise.context.RequestScoped;
import jakarta.faces.context.FacesContext;
import jakarta.inject.Named;
/** Reports which Faces implementation and API the server supplied. */
@Named
@RequestScoped
public class RuntimeInfoBean {
public String getImplementation() {
Class<?> impl = FacesContext.getCurrentInstance().getExternalContext().getClass();
Package p = impl.getPackage();
var src = impl.getProtectionDomain().getCodeSource();
return impl.getName() + " / " + p.getImplementationTitle() + " " + p.getImplementationVersion()
+ " / " + (src == null ? "unknown" : src.getLocation());
}
public String getApi() {
Package p = FacesContext.class.getPackage();
return p.getSpecificationTitle() + " " + p.getSpecificationVersion()
+ " (API jar " + p.getImplementationVersion() + ")";
}
public String getCdi() {
return jakarta.enterprise.inject.spi.CDI.current().getBeanManager().getClass().getName();
}
}
runtime.xhtml shows the three properties with h:outputText. Never expose such a page in production: it names the
implementation and its file system location, which helps an attacker and helps nobody else. Remove it, or restrict it with a
security constraint (see the security page), before a real deployment.
Which Implementation Each Server Bundles
This table is what the diagnostic page printed, plus the module versions read from each distribution, on 2026-10-08. The Faces implementation is not always the newest release: servers freeze it per server release.
| Server (release) | Jakarta EE | Faces implementation (observed) | CDI container | Notes |
|---|---|---|---|---|
GlassFish 8.0.5 |
11 |
Eclipse Mojarra 4.1.17 ( |
Weld 6.0.4.Final |
Hibernate Validator in |
WildFly 41.0.1.Final |
11 |
Eclipse Mojarra 4.1.13 ( |
Weld 6.0.4.Final ( |
|
Payara 7.2026.9 |
11 |
Mojarra 4.1.14.payara-p1 (Payara’s build of Mojarra) |
Weld 6.0.4.Final |
Same GlassFish-derived module layout |
Open Liberty 26.0.0.10 |
11 ( |
Apache MyFaces 4.1.1 repackaged by Liberty ( |
Weld ( |
Features are opt-in, see Open Liberty 26 (faces-4.1) |
Apache TomEE 10.2.0 (Web Profile) |
10 |
Apache MyFaces 4.0.3 ( |
Apache OpenWebBeans 4.0.3 |
Faces 4.0 only; Bean Validation |
Source: Jakarta EE Compatible Products
Two practical consequences follow. First, the same page may behave differently on Mojarra and on MyFaces; the differences are collected in Mojarra versus MyFaces and in the "Mojarra vs MyFaces" part of each page of this section, so test on the server you ship on. Second, the Faces version is also fixed: on TomEE 10.2.0 you get Faces 4.0, so Faces 4.1 additions (see what Faces 4.1 added) are not available there even though the WAR compiles against the 4.1 API. The Jakarta EE site lists which products are certified compatible with which platform and profile; the certification list is what makes "runs on Jakarta EE 11" a claim you can check, and it is where a server that has just released (like the WildFly 42 beta that exists today) is listed once it is certified.
Eclipse GlassFish 8
GlassFish 8.0.5 is the Jakarta EE 11 compatible implementation and the home of Mojarra, so it is the reference for "what the
specification does". The distribution is a ZIP that unpacks to a glassfish8 directory; everything is driven by the
asadmin command.
export JAVA_HOME=/path/to/jdk-21
GF=glassfish8
# a throw-away development domain without an admin password
$GF/bin/asadmin create-domain --nopassword=true --instanceport 8080 --adminport 4848 bookdomain
$GF/bin/asadmin start-domain bookdomain
$GF/bin/asadmin deploy --contextroot bookshelf target/bookshelf.war
curl -s http://localhost:8080/bookshelf/catalogue.xhtml | grep 'Clean Code'
$GF/bin/asadmin undeploy bookshelf
$GF/bin/asadmin stop-domain bookdomain
Observed on 8.0.5: the deployment printed "Application deployed with name bookshelf", the catalogue rendered, and the diagnostic page reported
com.sun.faces.context.ExternalContextImpl from Mojarra 4.1.17, API jar 4.1.17 (the same JAR, modules/jakarta.faces.jar) and
org.jboss.weld.bean.builtin.BeanManagerProxy. Configuration notes:
-
Domains. A GlassFish installation holds any number of domains, each with its own
config/domain.xml, ports and applications.--nopassword=truecreates an admin user without a password, which is acceptable for a throw-away local domain and nothing else; for a shared or production domain create it with a password and keep the admin listener off public networks. -
Ports. The domain creation flags move only the HTTP and admin ports. The other listeners (HTTPS, IIOP, JMS, JMX) have defaults in
domain.xmlthat clash when two domains run on one machine; edit them or create the domain with--portbase. -
Context root.
--contextrootondeployor aglassfish-web.xmlwith acontext-rootelement sets it; without either, the application name (the WAR name) is used. -
Class loading. The Faces JAR is a module of the server (an OSGi bundle), visible to every application. Applications are isolated from each other but see the server’s Mojarra.
-
Java. The run used JDK 21.
WildFly 41
WildFly assembles the server from modules and configures subsystems in standalone.xml. Faces is handled by the jsf
subsystem; Mojarra 4.1.13 lives in the module jakarta.faces.impl, with the API in jakarta.faces.api and the CDI
integration in org.jboss.as.jsf-injection. Faces is added to a deployment’s class path only when the deployment uses Faces
(for example, when it declares the FacesServlet).
export JAVA_HOME=/path/to/jdk-21
WF=wildfly-41.0.1.Final
$WF/bin/standalone.sh &
cp target/bookshelf.war $WF/standalone/deployments/
# the scanner writes bookshelf.war.deployed when it succeeds (bookshelf.war.failed otherwise)
curl -s http://localhost:8080/bookshelf/runtime.xhtml
$WF/bin/jboss-cli.sh --connect --commands=':shutdown'
Observed: deployment took a few seconds and created bookshelf.war.deployed; the diagnostic page reported Mojarra 4.1.13 from
modules/system/layers/base/jakarta/faces/impl/main/jakarta.faces-4.1.13.jar and Weld’s BeanManagerProxy. The context root
is the WAR file name (/bookshelf). The management interface listened on 127.0.0.1 only, which is the safe default; keep it
that way and do not add a remote binding without credentials. Useful details:
-
Ports. Standalone mode opens HTTP (8080), HTTPS (8443) and the management ports. They are system-property controlled (
-Djboss.http.port=...,-Djboss.management.http.port=...), which is how parallel servers are started on one machine. -
Which implementations are installed. The CLI command
/subsystem=jsf:list-active-jsf-implsreturned["main"](the bundled Mojarra), and/subsystem=jsf:read-resourceshoweddefault-jsf-impl-slot => "main". -
Maven. The WildFly Maven plugin can deploy from the build; it was not run for this page.
Payara 7
Payara Server is derived from GlassFish and keeps its layout (glassfish/domains, asadmin), so GlassFish know-how
transfers. Payara 7.2026.9 reported Mojarra 4.1.14.payara-p1 and Weld 6.0.4.Final, so it is one Mojarra patch release behind
GlassFish 8.0.5 and carries Payara’s own build identifier.
export JAVA_HOME=/path/to/jdk-21
PAYARA=payara7
$PAYARA/bin/asadmin create-domain --nopassword=true --instanceport 8080 --adminport 4848 bookdomain
$PAYARA/bin/asadmin start-domain bookdomain
$PAYARA/bin/asadmin deploy --contextroot bookshelf target/bookshelf.war
curl -s http://localhost:8080/bookshelf/runtime.xhtml
$PAYARA/bin/asadmin stop-domain bookdomain
Source: Payara Server documentation
Observed: identical commands to GlassFish worked. Two differences matter for operations. Payara ships a Hazelcast-based
clustering runtime configured in domain.xml (hazelcast-runtime-configuration, with its own ports) that GlassFish does
not have; the cluster aspects of Faces are covered in the session replication part of the deployment and clustering page and in
the cluster part of the state-saving page. And the Payara version
number is a release train (7.2026.9 is a 2026 release), so "Payara 7" says little about the Faces patch
level; always check the actual JAR as shown above.
Open Liberty 26 (faces-4.1)
Open Liberty is the odd one out in three ways: it is configured by an XML file listing features, it bundles MyFaces and not
Mojarra, and nothing is available until a feature is enabled. A server is a directory under usr/servers with a
server.xml.
<?xml version="1.0" encoding="UTF-8"?>
<server description="Bookshelf on Open Liberty">
<featureManager>
<feature>faces-4.1</feature>
<feature>cdi-4.1</feature>
</featureManager>
<httpEndpoint id="defaultHttpEndpoint" host="*" httpPort="9080" httpsPort="9443"/>
<webApplication id="bookshelf" location="bookshelf.war" contextRoot="/bookshelf"/>
</server>
export JAVA_HOME=/path/to/jdk-21
WLP=wlp
$WLP/bin/server create bookshelf
# write usr/servers/bookshelf/server.xml as above, then:
mkdir -p $WLP/usr/servers/bookshelf/apps
cp target/bookshelf.war $WLP/usr/servers/bookshelf/apps/
$WLP/bin/server start bookshelf
curl -s http://localhost:9080/bookshelf/runtime.xhtml
$WLP/bin/server stop bookshelf
Source: Open Liberty: httpEndpoint
Observed with 26.0.0.10: the server reported the installed features cdi-4.1, expressionLanguage-6.0, faces-4.1 and
servlet-6.1; the diagnostic page reported org.apache.myfaces.context.servlet.ServletExternalContextImpl from Liberty’s
io.openliberty.org.apache.myfaces.4.1 JAR with implementation version 4.1.1, the API from
dev/api/spec/io.openliberty.jakarta.faces.4.1_*.jar, and Weld’s BeanManagerImpl. Notes:
-
Version lag. The bundled MyFaces is 4.1.1, behind MyFaces Core 4.1.4. Fixes released after 4.1.1 reach Liberty only with a Liberty release.
-
Features. The Jakarta Faces 4.1 feature enables CDI, Expression Language and Servlet; the
webProfile-11.0feature enablesfaces-4.1for you. The documentation lists Java 17, 21, 25 and 27 as supported for it. A feature you do not list is absent: if a view uses Bean Validation or WebSocket push, add the matching feature (this page’s run did not use them). -
Mojarra in the WAR. With the
faces-4.1feature the server’s MyFaces is on the class path, so a WAR that carries Mojarra conflicts. In the run, a WAR holdingjakarta.faces-4.1.17.jarfailed at startup with a WeldDefinitionExceptioncaused byNoClassDefFoundError: jakarta/websocket/CloseReason$CloseCodewhile loading a Mojarra push class (thewebsocket-2.2feature was not enabled). The supported way to bring your own implementation is the next feature. -
facesContainer-4.1. This feature contains only the container integration for Faces; it provides no API and no implementation, so the implementation must be packaged in the WAR. It enablescdi-4.1,expressionLanguage-6.0,jndi-1.0,servlet-6.1andwebsocket-2.2. Replacingfaces-4.1withfacesContainer-4.1in theserver.xmlabove, and deploying a WAR that packages Mojarra 4.1.17, started cleanly and the diagnostic page reported Mojarra 4.1.17 loaded from the WAR’sWEB-INF/lib(the JAR was downloaded withfeatureUtility installFeature facesContainer-4.1; the zip used here did not contain it).
Apache TomEE 10.2
TomEE is Apache Tomcat plus the Jakarta EE Web Profile implementations from Apache: MyFaces for Faces, OpenWebBeans for CDI,
Bean Validation from Apache BVal. TomEE 10.2.0 is a Jakarta EE 10 server on Tomcat 10.1 (the 404 page printed "Apache Tomcat
(TomEE)/10.1.57 (10.2.0)"). Its distribution contained myfaces-api-4.0.3.jar, myfaces-impl-4.0.3.jar,
openwebbeans-impl-4.0.3.jar and openwebbeans-jsf-4.0.3.jar in lib/. It is therefore a Faces 4.0 server; the
Jakarta EE 11 release, TomEE 11, was a milestone (11.0.0-M1) on Maven Central at the time of writing.
export JAVA_HOME=/path/to/jdk-21
TOMEE=apache-tomee-webprofile-10.2.0
chmod +x $TOMEE/bin/*.sh # the ZIP did not preserve the executable bit
cp target/bookshelf.war $TOMEE/webapps/
$TOMEE/bin/catalina.sh run & # or startup.sh to detach
curl -s http://localhost:8080/bookshelf/runtime.xhtml
$TOMEE/bin/catalina.sh stop
Source: Apache TomEE 10.0 documentation
Observed: the WAR deployed unchanged and the diagnostic page reported
org.apache.myfaces.context.servlet.ServletExternalContextImpl, Apache MyFaces Core 4.0 Impl 4.0.3, and OpenWebBeans'
InjectableBeanManager. Configuration is Tomcat’s: ports are in conf/server.xml (HTTP connector 8080, shutdown 8005),
the context root is the WAR name, and the webapps directory is the deployment directory. Because the CDI container is OpenWebBeans and not Weld, Weld-specific API
(for example org.jboss.weld.*) must not be used in code meant for TomEE,.
Replacing MyFaces with Mojarra on TomEE by packaging jakarta.faces-4.1.17.jar in the WAR failed at deployment in the run
with an OpenWebBeans AmbiguousResolutionException for the bean name application: the server’s MyFaces CDI producer and
the bean from the WAR’s copy of Faces collided. No configuration that makes a bundled Mojarra work on this server was found, so for Faces 4.1 wait for TomEE 11.
Replacing the Bundled Implementation
Sometimes a project needs a different implementation or a newer patch release than the one the server carries (a fix in a later Mojarra, or MyFaces for consistency with another environment). The outcome varies by server and was tested for each:
| Server | Result in the run |
|---|---|
GlassFish 8.0.5 |
Packaging MyFaces 4.1.4 (API and implementation) in |
Payara 7.2026.9 |
The same MyFaces WAR failed the same way ( |
WildFly 41.0.1 |
Worked. A WAR with MyFaces 4.1.4 in |
Open Liberty 26.0.0.10 |
Works with the |
TomEE 10.2.0 |
Mojarra 4.1.17 packaged in the WAR failed at deployment ( |
Source: WildFly Administration Guide: Jakarta Faces Subsystem and Open Liberty: Jakarta Faces 4.1 Container
The lesson is that the "bring your own implementation" capability is a feature of the server, not of Faces. Where a server has no supported switch, the answer is to use the bundled implementation and to follow its release schedule, or to move to a server (or to Tomcat plus Weld, see Tomcat and Weld) where you control the implementation.
<context-param>
<param-name>org.jboss.jbossfaces.JSF_CONFIG_NAME</param-name>
<param-value>myfaces-4.1.4</param-value>
</context-param>
Source: WildFly Administration Guide: Configuring a Jakarta Faces app to use a non-default implementation
The slot name above follows the documentation’s <name>-<version> convention (its example uses myfaces-4.0.0); the
actual slot depends on how the implementation was installed, and this snippet was not run.
Configuration Differences at a Glance
| GlassFish 8 | WildFly 41 | Payara 7 | Open Liberty 26 | TomEE 10.2 | |
|---|---|---|---|---|---|
Deploy |
|
copy to |
|
copy to |
copy to |
Context root |
|
WAR name |
|
|
WAR name |
Server config |
|
|
|
|
Tomcat |
Faces / CDI |
Mojarra 4.1.17 / Weld |
Mojarra 4.1.13 / Weld |
Mojarra 4.1.14.payara-p1 / Weld |
MyFaces 4.1.1 / Weld |
MyFaces 4.0.3 / OpenWebBeans |
Faces version |
4.1 |
4.1 |
4.1 |
4.1 |
4.0 |
What does not differ is the part you control: the WAR, the Facelets, the CDI beans and the descriptors above ran unchanged on all five servers (the catalogue rendered the three books on each). A few behaviours do depend on the server and must be tested: the exact text of the default error pages (see error pages in the exception-handling page), whether CDI scopes beyond the standard ones are available, how client-side state is encrypted in a cluster (MyFaces needs an explicit secret on every node; see client-state keys), and how long a server keeps view state (Mojarra and MyFaces use different defaults, see state saving and stateless views).
Component Libraries and Servers
PrimeFaces and OmniFaces are packaged in the WAR and work with both implementations; the JAR versions required are in
PrimeFaces getting started and
OmniFaces. Two server-specific points apply: OmniFaces 5 needs Faces 4.1, so it does not run on
TomEE 10.2.0 (Faces 4.0, use an OmniFaces 4.x line there), and a library that ships its own CDI extension can trigger the
duplicate bean problems shown in Replacing the Bundled Implementation if it also carries a Faces implementation. Never package a Faces implementation as a
transitive dependency of a library; mark it provided or exclude it.
Mojarra vs MyFaces on Servers
-
GlassFish, WildFly and Payara run Mojarra; Open Liberty and TomEE run MyFaces. The implementation is a property of the server choice, so a team that develops on one family and ships on the other meets the behavioural differences in Mojarra versus MyFaces for the first time in production.
-
The diagnostic page is a more reliable way to see which implementation runs than reading logs.
-
The "replace the implementation" experiments above show that the two implementations register CDI producers under the same EL names (
requestScope,initParam,application), so they cannot coexist in one CDI container.
What Changed
-
Faces 4.0 / Jakarta EE 10. The namespace is
jakarta.*andjavax.facesis gone; themanaged-beanmachinery was removed in favour of CDI (see Backing Beans and CDI). Servers in this release line include GlassFish 7, Payara 6 and TomEE 10. -
Faces 4.1 / Jakarta EE 11. Java 17 minimum; the servers in this page’s first four rows implement it (see the version matrix). TomEE 11 is a milestone only.
-
Faces 5.0 / Jakarta EE 12 (upcoming). Milestones exist (
jakarta.faces-api:5.0.0-M9); no server in this page implements it, so nothing here describes 5.0 behaviour. -
Server packaging. Open Liberty offers a container-only
facesContainer-x.yfeature for each Faces version from 2.2 to 4.1, and WildFly’sjsfsubsystem allows several implementations to be installed side by side (any implementation at spec level 4.0 or higher).
Where the Books Are Outdated
-
The JSF 1.x and 2.x books describe deployment on the Sun Java System Application Server, JBoss AS 4 to 7, WebLogic and Tomcat. Those products and their
javax.facesJARs,sun-web.xmlandjboss-web.xmlconventions belong to a different generation. Today the names are GlassFish, WildFly, Payara, Open Liberty and TomEE, and the descriptors areglassfish-web.xml,jboss-web.xmlandserver.xmlfeatures. -
Several books assume you copy a Faces implementation JAR into the WAR for every server and declare it in
web.xml. On a Jakarta EE server this is the cause of the failures shown above; the implementation is provided, and only a few servers allow replacing it. -
The older books show the application server as a place for managed beans declared in
faces-config.xml; on the servers on this page, beans are CDI beans discovered by the container. -
Ant, hand-assembled directory deployments and "hot deploy by copying files" appear in the older books. The same idea is still possible (copying a WAR to
deployments,appsorwebapps), but the build is Maven. -
The books predate containers and cloud deployments. Running the same WAR in Docker images of WildFly, Payara or Open Liberty is the current practice; see Dockerfile fundamentals, and the Docker part of the deployment and clustering page for the Faces side.
Pitfalls
-
Packaging the Faces API or implementation in the WAR on a server that bundles one. Result: class-loading errors or the CDI ambiguity shown in Replacing the Bundled Implementation. Keep the API
provided, and add an implementation only where the server documents it. -
Assuming the same Faces version everywhere. TomEE 10.2.0 is Faces 4.0, WildFly 41 carries Mojarra 4.1.13 while GlassFish 8.0.5 carries 4.1.17, and Open Liberty carries MyFaces 4.1.1. Read the version from the running server.
-
Creating domains with an empty admin password and forgetting it.
--nopassword=trueis for local, throw-away domains. A GlassFish or Payara admin console without a password on a reachable port is a remote administration hole. -
Leaving the diagnostic or development pages deployed. Use
Productionas the project stage and remove pages that print implementation details. -
Port conflicts. A second GlassFish, Payara or WildFly on the same host needs changed ports for every listener, not only HTTP.
-
Features absent in Open Liberty. The application fails at startup with a missing class when a feature (WebSocket, validation, JNDI) is not listed in
server.xml. -
Weld-only code on TomEE. TomEE uses OpenWebBeans.
Related Pages
The Tomcat and Weld page covers the "no application server" alternative where you choose the implementation
yourself; the Spring Boot with JoinFaces and Quarkus pages cover running Faces inside other runtimes; the
Deployment and Clustering page covers packaging, the Production stage, Docker images and session replication on these servers; the
Persistence and Services page covers data sources and transactions that a full server provides, and the
Testing page covers Arquillian against them. The Best Practices checklist lists the server-related rules, and
Migrating to Jakarta Faces covers moving an application from an older server. See also
Project Setup and Versions and Implementations.