Configuration and Project Stages
|
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), Eclipse Mojarra 4.1.17 and
Apache MyFaces Core 4.1.4, with Java 17 or later. Faces 4.0 (Jakarta EE 10, Java 11 or later) has the same configuration
model; the differences are collected in What Changed and nothing here was run on 4.0. The examples were compiled and deployed in a
scratch Bookshelf WAR on Apache Tomcat 11.0.26 with Weld 6.0.4.Final, once with Mojarra and once with MyFaces, and driven with
curl: every status code, HTML fragment, log line and "what happened" statement below comes from those runs (checked on
2026-10-08). A parameter described without such a statement is described from the specification, the API documentation or the
Mojarra and MyFaces parameter references only, and the page says so. Faces 5.0 is still a milestone release (5.0.0-M9 on
2026-09-18) and nothing here describes it as current behaviour.
The page is the reference for how a Faces application is configured and how that configuration behaves. The
Project Setup page shows how to put a first web.xml and faces-config.xml into a
project; this page goes through every standard context parameter, the ProjectStage and its real effects, the
faces-config.xml document, the relation between annotations and XML, the loading and ordering of several configuration
files, and the parameters that only Mojarra or only MyFaces understand. Faces is configured from a handful of places, and
most configuration mistakes come from not knowing which of them wins.
Where Faces Reads Its Configuration
Five mechanisms feed the configuration of a Faces application. They are independent and they overlap on purpose, so that a library can configure itself, an application can override the library, and an operations team can change a setting without rebuilding the WAR.
| Source | What it configures | Who writes it |
|---|---|---|
Context parameters ( |
Behaviour switches: project stage, Facelets, state saving, validation, mapping. Names start with |
The application, or a library through its |
JNDI environment entry |
The project stage only. |
The operations team, in the server or in the descriptor |
|
Objects and registrations: locales, resource bundles, navigation rules, converters, validators, components, renderers, phase listeners, factories, flows, protected views, ordering. |
The application and every library that ships a |
Annotations ( |
The same registrations as the XML, written next to the class. |
The application and libraries |
Code: |
Registrations computed at startup. |
Frameworks and integrations |
Source: Jakarta Faces 4.1 specification, 11.3.2 Application Startup Behavior and Jakarta EE Tutorial: Application Configuration Resource File
The sequence at startup is the same on both implementations. The container merges the descriptors, Faces decides whether it
has anything to do, collects the configuration resources, sorts them, combines the annotation metadata with them, and publishes
PostConstructApplicationEvent when it is finished. All of this happens before the first request is processed, which is why
configuration errors are deployment errors, not request errors.
Source: Jakarta Faces 4.1 specification, 11.3.2 Application Startup Behavior and Jakarta Faces 4.1 API: FacesServlet
Two details of the diagram deserve a sentence. The FacesServlet is mapped for you when you do not map it yourself and one of
these is true: WEB-INF/faces-config.xml exists, a META-INF/faces-config.xml or *.faces-config.xml file exists in a JAR,
jakarta.faces.CONFIG_FILES is declared, or the container initializer found a class with a Faces annotation (the API documentation
of FacesServlet lists the annotations); the section on Extensionless Mapping and the FacesServlet Mappings shows what that automatic mapping covers. And
the Mojarra reference adds a case for applications with no web.xml and no faces-config.xml at all (a Spring Boot
application that registers everything programmatically): com.sun.faces.forceLoadConfiguration starts the configuration
even though none of the usual triggers is present.
Startup and Shutdown
Startup ends with an event and shutdown starts with one. At startup the specification (11.3.2) has the runtime publish
PostConstructApplicationEvent immediately after all configuration resources have been processed, flows and resource library
contracts included; the events page lists it as an
application system event. A parsing error in a configuration resource is fatal to
startup and the container does not make the application available. At shutdown (11.3.4) the runtime must make sure that
FacesContext.getCurrentInstance() returns successfully while the application is going down (the API documentation of
FacesContext says that getApplication() is valid during startup and shutdown), then publish PreDestroyApplicationEvent,
and finally call FactoryFinder.releaseFactories(). So PreDestroyApplicationEvent is the hook for releasing what an
application-wide extension holds (a thread pool, a cache, a connection), and by the time the factories are released nothing of
Faces may be used any more.
package org.example.bookshelf.config;
import jakarta.faces.context.FacesContext;
import jakarta.faces.event.AbortProcessingException;
import jakarta.faces.event.SystemEvent;
import jakarta.faces.event.SystemEventListener;
import java.util.logging.Logger;
/** Runs when the web application stops: close what the application opened at startup. */
public class ShutdownHook implements SystemEventListener {
private static final Logger LOG = Logger.getLogger(ShutdownHook.class.getName());
@Override
public void processEvent(SystemEvent event) throws AbortProcessingException {
FacesContext ctx = FacesContext.getCurrentInstance();
String line = "shutdown: FacesContext present = " + (ctx != null)
+ ", project stage = " + (ctx == null ? "?" : ctx.getApplication().getProjectStage());
LOG.info(line);
System.err.println(line);
// close the catalogue cache, stop the import scheduler ...
}
@Override
public boolean isListenerForSource(Object source) {
return true;
}
}
<application>
<system-event-listener>
<system-event-listener-class>org.example.bookshelf.config.ShutdownHook</system-event-listener-class>
<system-event-class>jakarta.faces.event.PreDestroyApplicationEvent</system-event-class>
<source-class>jakarta.faces.application.Application</source-class>
</system-event-listener>
</application>
Source: Jakarta Faces 4.1 specification, 11.3.4 Application Shutdown Behavior and Jakarta Faces 4.1 API: PreDestroyApplicationEvent
Run on Mojarra 4.1.17 and MyFaces 4.1.4 on Tomcat 11.0.26 (the embedded Tomcat was stopped with SIGTERM, with a hook that stops the
context): both implementations published the event, and in the listener FacesContext.getCurrentInstance() was not null and
getProjectStage() answered Production. In the first run the java.util.logging line of the listener did not appear in the log at all (the cause was not investigated), so the listener also writes to
System.err, which did appear; if a shutdown message is missing in your logs, check the logging configuration before suspecting the event. Treat the
FacesContext of such a listener as a way to reach the Application, not as a request: the specification only promises the context and the application object.
Context Parameters
A context parameter is a name and a string value that the servlet container exposes through the ServletContext. Faces
reads them once, at startup, so changing one needs a redeploy or restart. (The Facelets refresh period is no exception: it
sets how often the view files are checked, and is itself read at startup.)
Setting a Parameter
There are three places, and they combine under the rules of the Servlet specification, not of Faces.
<?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_1.xsd"
version="6.1">
<context-param>
<param-name>jakarta.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<context-param>
<param-name>jakarta.faces.FACELETS_REFRESH_PERIOD</param-name>
<param-value>1</param-value>
</context-param>
<context-param>
<param-name>jakarta.faces.FACELETS_SKIP_COMMENTS</param-name>
<param-value>true</param-value>
</context-param>
<servlet>
<servlet-name>facesServlet</servlet-name>
<servlet-class>jakarta.faces.webapp.FacesServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>facesServlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
</web-app>
Source: Jakarta EE Tutorial: Configuring Project Stage and Jakarta Faces 4.1 specification, 11.1.3 Application Configuration Parameters
A JAR can contribute parameters of its own through a META-INF/web-fragment.xml. A library that needs a Faces parameter to
work (a tag library registered through jakarta.faces.FACELETS_LIBRARIES, for example) ships it that way, so the
application does not have to copy it:
<?xml version="1.0" encoding="UTF-8"?>
<web-fragment 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-fragment_6_1.xsd"
version="6.1">
<name>bookshelfDefaults</name>
<context-param>
<param-name>jakarta.faces.FACELETS_SKIP_COMMENTS</param-name>
<param-value>true</param-value>
</context-param>
</web-fragment>
Source: Jakarta Faces 4.1 API: FacesServlet (the API documentation of FacesServlet names web.xml and web-fragment.xml as the places where Faces looks)
In the scratch run a fragment that set jakarta.faces.PROJECT_STAGE to Development was honoured by both
implementations when web.xml set nothing, and lost to web.xml when web.xml set Production; a second parameter of the same fragment that
web.xml did not mention still applied. That is the Servlet rule (the main descriptor overrides a fragment), so a library’s defaults
can be overridden by the application and never the other way round.
The third place is the container itself. Tomcat’s context.xml can define an environment entry, and the project stage
(and only the project stage) is read from JNDI before the context parameter is consulted; the section on How the Stage Is Determined shows
it. Servers other than Tomcat have their own way to define the same JNDI name.
How Values Are Read
The values are strings and each parameter has its own rule. The specification states the rules of the boolean ones the same
way for most of them: the runtime calls toLowerCase().equals("true") on the string, so true, TRUE and True enable
the parameter, and anything else (yes, 1, on) leaves it off. jakarta.faces.STATE_SAVING_METHOD is compared
ignoring case, jakarta.faces.PROJECT_STAGE is not: it has to be the exact name of a constant. The lists are separated by
different characters depending on the parameter (semicolon for the Facelets libraries, decorators and view mappings, comma for
CONFIG_FILES and FULL_STATE_SAVING_VIEW_IDS, a space for RESOURCE_EXCLUDES and FACELETS_SUFFIX); the tables below
say which. A mistyped parameter name is not an error: it is simply never read, and the application runs with the default. In the scratch run
jakarta.faces.PROJECT_STAG, a made-up com.sun.faces.numberOfLogicalViewz and the old javax.faces.PROJECT_STAGE were all
ignored on both implementations, without a log line, while the correct jakarta.faces.PROJECT_STAGE next to them set Development. Both
implementations can print what they read, which is the quickest way to find a typo (the sections on Mojarra Parameters and
MyFaces Parameters show how).
The Standard Parameters
The specification requires every implementation to support the parameters of its section 11.1.3, and a few more are defined only in the API documentation. The next tables list all of them, grouped by purpose, with the default, the release that introduced them and what they do. "Tested" in the last column means that the behaviour was run in the scratch application and is described under the table or in the section named there.
| Parameter | Default | Since | Effect | Tested |
|---|---|---|---|---|
|
|
2.0 |
Where the application is in its lifecycle: |
yes |
|
none |
1.0 |
Comma-separated, context-relative paths of additional configuration files. |
yes |
|
|
1.0 |
Identifier of the |
no |
|
|
4.0 |
Maps the |
yes |
|
|
2.3 |
Switches off the automatic |
yes |
|
|
2.3 |
Exceptions thrown by phase listeners installed on the |
no |
Source: Jakarta Faces 4.1 specification, 11.1.3 Application Configuration Parameters, Jakarta Faces 4.1 API: FacesServlet and Mojarra 4.1 context parameters
| Parameter | Default | Since | Effect | Tested |
|---|---|---|---|---|
|
|
2.0 |
Seconds between two checks whether a view file changed. |
yes |
|
|
2.0 |
XML comments of the Facelets source are not delivered to the client. |
yes |
|
|
2.0 |
Response buffer size, in bytes, while the view renders. |
no |
|
|
2.0 |
Space-separated list of the extensions under which view files may be stored; the first physical file found wins. |
yes |
|
none |
2.0 |
Semicolon-separated extensions ( |
yes |
|
none |
2.0 |
Semicolon-separated, web-root-relative paths (each starting with |
yes (earlier page) |
|
none |
2.0 |
Semicolon-separated class names of |
yes |
|
|
1.1 |
Deprecated for removal since 4.0 because Jakarta Pages views are gone; use |
no |
Source: Jakarta Faces 4.1 API: ViewHandler and Jakarta Faces 4.1 specification, 11.1.3 Application Configuration Parameters
| Parameter | Default | Since | Effect | Tested |
|---|---|---|---|---|
|
|
1.0 |
|
yes |
|
|
2.2 |
With server state saving, guarantees that the stored state is serializable, so that a |
no |
|
|
2.0 |
Saves only the difference from the initial state. Deprecated since 4.1 (full state saving will go away). |
no |
|
none |
2.0 |
Comma-separated view ids that use full state saving. Deprecated since 4.1. |
no |
| Parameter | Default | Since | Effect | Tested |
|---|---|---|---|---|
|
|
2.0 |
The default time zone of |
yes |
|
|
2.2 |
A |
yes |
|
|
2.0 |
An empty submitted string becomes |
yes (earlier page) |
|
|
2.0 |
Validators also run on empty values; |
yes (earlier page) |
|
|
2.0 |
Do not add the Jakarta Validation validator to every input. Covered on the Bean Validation page. |
no |
|
|
2.3 |
Without it |
yes (earlier page) |
Source: Jakarta Faces 4.1 specification, 11.1.3 Application Configuration Parameters and Mojarra 4.1 context parameters
| Parameter | Default | Since | Effect | Tested |
|---|---|---|---|---|
|
|
2.0 |
The character between the segments of a client id; only its first character is used. |
yes |
|
|
2.0 |
Extensions the resource handler never serves; a configured value replaces the default entirely. |
no |
|
|
2.2 |
Web-root-relative directory of the resources; must not start with |
no |
|
|
2.2 |
Web-root-relative directory of the resource library contracts. Covered on the resource library contracts page. |
no |
|
|
2.2 |
Enables the |
yes (earlier page) |
|
|
4.0 |
How many client windows the session remembers. Covered on the multi-window page and the Scopes page. |
yes (earlier page) |
|
|
2.3 |
Registers the WebSocket endpoint behind |
yes (earlier page) |
|
|
2.3 |
Port of the WebSocket endpoint when it differs from the HTTP port. |
no |
Source: Jakarta Faces 4.1 specification, 11.1.3 Application Configuration Parameters and Mojarra 4.1 context parameters
Three rows need a comment on the source of the default. jakarta.faces.validator.DISABLE_DEFAULT_BEAN_VALIDATOR is
false in the Mojarra reference; the MyFaces reference table lists true in its default column, which contradicts the
specification wording (the validator is added unless the parameter is true) and was not checked at run time, so the table above
gives the Mojarra value. The defaults of RESOURCE_EXCLUDES and SEPARATOR_CHAR come from the specification text and
the Mojarra reference. And NUMBER_OF_CLIENT_WINDOWS is absent from the specification’s list in chapter 11, yet both implementations
document it and the Scopes page observed it working on both.
Facelets Parameters in Practice
The refresh period and the comment switch are demonstrated on the Project Setup page, where the combination with the project stage is tabulated. The other Facelets parameters change how a view id is mapped to a file or what the compiler does, and they have traps.
FACELETS_SUFFIX
A request for /books.xhtml becomes the view id /books.xhtml, and the Facelets compiler reads the physical file
books.xhtml. jakarta.faces.FACELETS_SUFFIX changes the file suffix that is looked for: it is a space-separated list of
extensions, each starting with a dot; the first physical file that matches one of them becomes the file behind the view id. A project that keeps its views in .facelet files while the URLs stay .xhtml configures it like this:
<context-param>
<param-name>jakarta.faces.FACELETS_SUFFIX</param-name>
<param-value>.facelet .xhtml</param-value>
</context-param>
The Bookshelf scratch application had suffix.facelet and index.xhtml in its web root, the FacesServlet mapped to
*.xhtml only, and the two implementations answered like this:
| Parameter value | Request | Mojarra 4.1.17 | MyFaces 4.1.4 |
|---|---|---|---|
|
|
200 |
200 |
|
|
404 |
500 |
|
|
200 |
404 |
|
|
200 |
200 |
Two lessons follow. First, a list of suffixes is not portable: with both .facelet and .xhtml in the list, Mojarra
found suffix.facelet for the request /suffix.xhtml and MyFaces answered 404 (it did not substitute the suffix
because the request already ended with one of the listed ones), while with the single value .facelet both implementations
served the page. The single value is the safe choice, and it means every view file must use it.
Second, and worse: the file suffix.facelet was answered with status 200 and its raw Facelets source on a direct request, in
every variant, because the container serves a file nobody maps as static content. The source of a page, with its EL
expressions, bean names and comments, was readable by anyone. A suffix other than .xhtml therefore needs a constraint that
blocks direct access:
<security-constraint>
<web-resource-collection>
<web-resource-name>Facelets sources</web-resource-name>
<url-pattern>*.facelet</url-pattern>
</web-resource-collection>
<auth-constraint/>
</security-constraint>
With this constraint the direct request answered 403 on both implementations, and the view requested as /index.xhtml
still rendered. (The constraint has an empty auth-constraint, which in the Servlet specification means no role may access the
resource.) Views under WEB-INF need no constraint, because the container never serves that directory; that is the reason
templates are kept in WEB-INF/templates in the Bookshelf layout.
FACELETS_VIEW_MAPPINGS
jakarta.faces.FACELETS_VIEW_MAPPINGS declares that some resources are Facelets views whatever their extension.
Each entry of the semicolon-separated list is a file extension written as *.xhtml or a prefix starting with a slash
and ending in *, as in /user/*. A legacy application with views called *.html that maps the FacesServlet to
*.html too would write:
<context-param>
<param-name>jakarta.faces.FACELETS_VIEW_MAPPINGS</param-name>
<param-value>*.html</param-value>
</context-param>
<servlet-mapping>
<servlet-name>facesServlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
In the scratch run a file legacy.html with Facelets content was served by MyFaces with this parameter alone (status 200,
the EL expression evaluated) and answered 404 on Mojarra. Adding jakarta.faces.FACELETS_SUFFIX with the value .html made both implementations serve it, with or without
the view mappings parameter. So FACELETS_SUFFIX is the parameter that decides which file is read; FACELETS_VIEW_MAPPINGS
decides which view ids count as Facelets, and Mojarra needs the first even when the second is set.
FACELETS_DECORATORS
A TagDecorator sees each tag while a view is compiled and may replace it. The classes are named in the semicolon-separated
parameter, need a public no-argument constructor, and are created when the first request for a Facelets view reaches the
ViewHandler. A decorator that only observes returns null:
package org.example.bookshelf.config;
import jakarta.faces.view.facelets.Tag;
import jakarta.faces.view.facelets.TagDecorator;
import java.util.logging.Logger;
public class CompileLogDecorator implements TagDecorator {
private static final Logger LOG = Logger.getLogger(CompileLogDecorator.class.getName());
public CompileLogDecorator() {
LOG.info("decorator created");
}
@Override
public Tag decorate(Tag tag) {
if ("commandButton".equals(tag.getLocalName())) {
LOG.info("compiling " + tag.getQName() + " at " + tag.getLocation());
}
return null;
}
}
<context-param>
<param-name>jakarta.faces.FACELETS_DECORATORS</param-name>
<param-value>org.example.bookshelf.config.CompileLogDecorator</param-value>
</context-param>
On the first request for index.xhtml both implementations logged decorator created once and then
compiling h:commandButton at /index.xhtml @6,90 (Mojarra) or ... at /index.xhtml at line 6 and column 90 (MyFaces). Because the compiled
view is cached, the decorator runs again only when the refresh period causes a recompilation. A decorator that returns a different
Tag rewrites the view before it is built; the tag libraries and templates documented elsewhere in this section are the usual
way to change markup, and a decorator is the tool for a rewrite that has to touch every view.
Conversion and Validation Parameters
Six parameters change what happens in the Process Validations phase (see
the lifecycle page). Two are covered by earlier pages
(INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL and VALIDATE_EMPTY_FIELDS on the Validators
page, the Bean Validation parameters on the Bean Validation page); the other two have run-time
consequences worth demonstrating.
The time zone of f:convertDateTime
f:convertDateTime formats with GMT unless a timeZone attribute is given, a surprise for every application not running in
London. jakarta.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE switches the default to the JVM’s zone:
<context-param>
<param-name>jakarta.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE</param-name>
<param-value>true</param-value>
</context-param>
<h:outputText value="#{dateBean.published}">
<f:convertDateTime pattern="yyyy-MM-dd HH:mm z"/>
</h:outputText>
package org.example.bookshelf.web;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Named;
import java.time.Instant;
import java.util.Date;
@Named
@RequestScoped
public class DateBean {
public Date getPublished() { return Date.from(Instant.parse("2026-07-01T12:00:00Z")); }
}
For a date of 2026-07-01 at 12:00 UTC and a JVM started with -Duser.timezone=Europe/Madrid, the page printed
2026-07-01 12:00 GMT without the parameter and 2026-07-01 14:00 CEST with it, on both implementations. The converter is
applied on output in the Render Response phase and on input in Process Validations, so a value typed in a form is parsed in the
same zone it was displayed in. Prefer an explicit timeZone attribute when the zone is part of the
business rule rather than of the server.
Required fields that are missing from the request
required="true" is checked when the input is decoded and validated, and only for the parameters that are present in the request.
A request that leaves the parameter out entirely is not an empty submission: the component has nothing submitted and, by default,
is not validated. A browser always sends the field of a text input, even empty, so the problem is invisible in the browser and
shows up in a scripted or malicious request.
<h:form id="f">
<h:inputText id="title" value="#{reqBean.title}" required="true"/>
<h:message for="title"/>
<h:inputText id="note" value="#{reqBean.note}"/>
<h:commandButton id="b" value="save" action="#{reqBean.save}"/>
</h:form>
package org.example.bookshelf.web;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Named;
@Named
@RequestScoped
public class ReqBean {
private String title;
private String note;
private String last = "none";
public String getTitle() { return title; }
public void setTitle(String t) { this.title = t; }
public String getNote() { return note; }
public void setNote(String n) { this.note = n; }
public String save() { last = "saved title=[" + title + "] note=[" + note + "]"; return null; }
public String getLast() { return last; }
}
A POST that carried f:b and f:note but not f:title called the action with title=null on both implementations, and no message
was added; a POST with f:title= (present but empty) produced "Validation Error: Value is required." With the parameter
jakarta.faces.ALWAYS_PERFORM_VALIDATION_WHEN_REQUIRED_IS_TRUE set to true the first request was rejected as well, with the same message,
and the action did not run.
<context-param>
<param-name>jakarta.faces.ALWAYS_PERFORM_VALIDATION_WHEN_REQUIRED_IS_TRUE</param-name>
<param-value>true</param-value>
</context-param>
Treat the parameter as a hardening setting for any application where an action depends on a required value: the server must not rely on the browser to send the fields. It costs one validation call per required input and changes no markup.
The Client Id Separator
jakarta.faces.SEPARATOR_CHAR changes the character between the segments of a client id (f:title becomes f_title). Only
the first character of the value is used. It exists for style sheets and scripts that cannot cope with the colon, and it has
a price: every id with that character in it, every search expression and every piece of JavaScript written with the old
character stops working. In the scratch run a form f with the input in and the button b rendered the ids f_in and f_b on both
implementations, and the view state field j_id1_jakarta.faces.ViewState_0 (Mojarra) and j_id__v_0_jakarta.faces.ViewState_1 (MyFaces). The
Search Expressions page lists the places that must stay in step: the update
and render attributes, @form:id style absolute expressions, and CSS selectors that escape the colon.
<context-param>
<param-name>jakarta.faces.SEPARATOR_CHAR</param-name>
<param-value>_</param-value>
</context-param>
State Saving Parameters
jakarta.faces.STATE_SAVING_METHOD decides where the view state lives, and it is the most visible parameter in the page source.
The state saving page covers the mechanism, the limits of the server variant, the protection of the client
variant and the Mojarra and MyFaces parameters around it; here only the configuration is shown.
<context-param>
<param-name>jakarta.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
The hidden field jakarta.faces.ViewState of a trivial page held 40 characters on Mojarra and 32 on MyFaces with the default
server method (an identifier of a state kept in the session), and 704 and 128 characters respectively with client (the state
itself, protected by the implementation). The size grows with the component tree on every response and every
postback, and the state leaves the server, so it must be protected: both implementations encrypt it and attach a message authentication code by default, and the
parameters that turn that off (com.sun.faces.disableClientStateEncryption, org.apache.myfaces.USE_ENCRYPTION) must never
be set in production.
Parameters in the Specification Text That Do Nothing
Two parameters are listed in chapter 11 of the specification and in the MyFaces reference table, yet no trace of them was found in the
code that is delivered. jakarta.faces.HONOR_CURRENT_COMPONENT_ATTRIBUTES and jakarta.faces.FACELETS_RESOURCE_RESOLVER do not
appear as strings in the jakarta.faces-api 4.1.2 JAR, in jakarta.faces 4.1.17 (Mojarra) or in the myfaces-api and
myfaces-impl 4.1.4 JARs. The second also names a ResourceResolver class that is not part of the 4.1 API any more (it
was removed in Faces 4.0). Do not configure them; if a book or an old answer suggests it, the resource handling and extending Faces
pages describe the current extension points.
Project Stages
A project stage tells the runtime where the application is in its life: being written, being tested by machines, being
tested by people, or running for real. It is the Faces equivalent of the RAILS_ENV of Ruby on Rails, as the API
documentation puts it, and it is the one setting that both the specification and the implementations use to trade diagnostics against speed and
safety. The constants of jakarta.faces.application.ProjectStage are:
| Constant | Meant for |
|---|---|
|
Programmers working on the application. Diagnostics are on, caches check for changes and error pages explain what went wrong. |
|
Automated tests of single classes, run by the build. |
|
Automated or manual tests of the deployed application as a whole. |
|
The default. Fast and quiet: nothing that explains the internals to the client. |
The specification gives the stages no behaviour beyond a handful of points listed in What the Stage Changes. What each implementation does
with them is its own business, and the scratch measurements below show that UnitTest and SystemTest mean almost nothing in
practice: the practical choice is between Development and everything else.
How the Stage Is Determined
Application.getProjectStage() computes the stage the first time it is called and keeps it. The algorithm in the API documentation
looks for a JNDI environment entry first and for the context parameter second, and falls back to Production when the value cannot be used.
The JNDI name is the constant ProjectStage.PROJECT_STAGE_JNDI_NAME, which holds java:comp/env/faces/ProjectStage (not
jakarta.faces.PROJECT_STAGE, which is the name of the context parameter). Two ways to define it were run on Tomcat with the
JNDI naming enabled, each time with the context parameter set to Production, and in each case both implementations
reported Development: the JNDI entry won. In web.xml:
<env-entry>
<env-entry-name>faces/ProjectStage</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>Development</env-entry-value>
</env-entry>
and in the Tomcat META-INF/context.xml of the application, which is the variant an operations team controls without touching the WAR:
<Context>
<Environment name="faces/ProjectStage" value="Development" type="java.lang.String" override="false"/>
</Context>
Source: Jakarta Faces 4.1 API: ProjectStage, PROJECT_STAGE_JNDI_NAME and Apache Tomcat 11: Environment Entries
A value that is not exactly one of the four names is not an error. Mojarra logged INFO: Unable to discern ProjectStage for value Staging.
and MyFaces WARNING: Wrong value in context init parameter 'jakarta.faces.PROJECT_STAGE' (='Staging'), using default value 'Production';
both then ran as Production. The lower-case development was refused in the same way, because the value goes through ProjectStage.valueOf(). The
Jakarta EE Tutorial says custom stages can be added; that cannot work with a Java enum, and in both implementations a custom
name means Production plus a log line. The mistake to avoid is a
typo in the one value that should enable diagnostics (or, worse, a typo that is meant to disable them): the application starts
without complaint and runs in Production.
Setting the Stage per Environment
The stage must follow the environment, not the source tree. Three arrangements work; the first is the simplest, the second is the safest against a mistake in the build, the third is the one for containers that offer a JNDI configuration.
A Maven property filtered into web.xml. The default is Production, so that a build without a profile is a safe one, and a
dev profile selects Development and a one-second refresh period:
<context-param>
<param-name>jakarta.faces.PROJECT_STAGE</param-name>
<param-value>${faces.project.stage}</param-value>
</context-param>
<context-param>
<param-name>jakarta.faces.FACELETS_REFRESH_PERIOD</param-name>
<param-value>${faces.refresh.period}</param-value>
</context-param>
<properties>
<faces.project.stage>Production</faces.project.stage>
<faces.refresh.period>-1</faces.refresh.period>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webResources>
<webResource>
<directory>src/main/webapp</directory>
<includes>
<include>WEB-INF/web.xml</include>
</includes>
<filtering>true</filtering>
</webResource>
</webResources>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>dev</id>
<properties>
<faces.project.stage>Development</faces.project.stage>
<faces.refresh.period>1</faces.refresh.period>
</properties>
</profile>
</profiles>
With these files mvn package wrote Production and -1 into the packaged WEB-INF/web.xml, and mvn package -Pdev wrote
Development and 1. The war plugin filters only the resources listed, which keeps stray ${...} expressions in other files untouched.
The JNDI entry in the server. The context.xml and env-entry above move the decision out of the WAR: one artifact is
deployed to every environment and the stage comes from the server. Because the JNDI value wins over the context parameter, it can
override a Development left in web.xml, which makes it the safer of the two for a production server.
A web-fragment.xml in a library. A fragment can set the stage too (it applied in the scratch run), but a library that picks
Development for the application it is bundled in is a trap; keep the stage out of libraries.
Reading the Stage
The stage can be read from three places, and a page may adapt to it, within the limits of ui:debug and the Stage.
package org.example.bookshelf.web;
import jakarta.enterprise.context.RequestScoped;
import jakarta.faces.application.ProjectStage;
import jakarta.faces.context.FacesContext;
import jakarta.inject.Inject;
import jakarta.inject.Named;
@Named
@RequestScoped
public class StageInfo {
@Inject
private FacesContext facesContext;
public ProjectStage getStage() {
return facesContext.getApplication().getProjectStage();
}
public boolean isDevelopment() {
return getStage() == ProjectStage.Development;
}
public boolean isProduction() {
return getStage() == ProjectStage.Production;
}
}
<ui:debug hotkey="d" rendered="#{stageInfo.development}"/>
<p>stage=#{stageInfo.stage}</p>
The page printed stage=Development dev=true prod=false, stage=UnitTest dev=false prod=false and
stage=Production dev=false prod=true under the three settings, on both implementations, and the debug script was
rendered only in the first. The same test can be written without a bean as
#{facesContext.application.projectStage eq 'Development'}: EL coerces the string to the enum, and the page behaved
identically. In JavaScript faces.getProjectStage() returns the stage as a string without a request (see the
Ajax page), which the Faces scripts themselves use to decide whether to show an alert.
What the Stage Changes
The specification names a short list of stage-dependent behaviour, and the implementations add their own. The first table is the specification’s; the second is what the two implementations did in the scratch run, with the same views and the same requests under each stage.
| Where | Rule |
|---|---|
|
|
Navigation case not found for a call node of a Faces Flow |
A message explaining that there was no match is rendered when the stage is not |
Ajax errors |
In |
Composite component interface metadata |
|
Invalid composite library name |
An informative message is placed in the page in |
Error information for Facelets error pages |
In |
Resource metadata |
An implementation may cache the resolved resources when the stage is |
Source: Jakarta Faces 4.1 specification, FACELETS_REFRESH_PERIOD in 11.1.3 and Jakarta Faces 4.1 specification, faces.getProjectStage and the Ajax error handling in the JavaScript chapter
Beyond that list each implementation decides. Every row of the next table was produced by one request to the same view under
Development, UnitTest, SystemTest, Production, no setting, Staging and development (the last three behaved as Production).
| Situation | Mojarra 4.1.17 | MyFaces 4.1.4 |
|---|---|---|
|
Text plus the sentence "This link is disabled because a navigation case could not be matched." in |
Only the text, in every stage. |
An exception thrown while the view renders (a bean getter) |
|
|
|
|
Nothing rendered, no message and no log line, in every stage. |
A |
|
|
Two components with the same id |
The view fails with status 500 in every stage; the log says |
The view fails in every stage with a |
|
The script and the debug output are produced in every stage (see ui:debug and the Stage). |
The same. |
Implementation switches tied to the stage |
Not applicable. |
|
Three things stand out. Mojarra gives UnitTest and SystemTest the "not production" behaviour in the link row only, MyFaces never
distinguishes the three non-production stages, and a build that uses the two test stages to get development diagnostics will not
get them. Second, the error information of the Development page is exactly what an attacker wants (class names, source lines, bean
variables), so the stage is a security setting as much as a convenience; the same is true of MyFaces' ERROR_HANDLING, which switched the
error page on in Production when set to true in the scratch run (the page title was the exception message, status 500, 11 KB).
Third, a Production rendering failure is not pretty by default: Mojarra hands the exception to the container and MyFaces
sends what it has already rendered. The exception handling page shows how to configure an <error-page>
and the ExceptionHandler so that a failure ends in a deliberate page.
ui:debug and the Stage
The documentation of ui:debug says the tag works only when the stage is Development. In the scratch run that was not
the case. A page with <ui:debug hotkey="d"/> rendered the keyboard script in Development and in Production on both
implementations, and the URL that the script opens (/bookshelf/debug.xhtml?facelets.ui.DebugOutput=..., with the generated number
copied from the page) answered 200 with a page that listed the component tree, the request parameters and the scoped variables:
10 KB on Mojarra and 8 KB on MyFaces in Production. The request needs the session of the user who rendered the page, so it is
not an anonymous leak, but anyone who can use the page can read bean state with it. Guard the tag explicitly:
<ui:debug hotkey="d" rendered="#{stageInfo.development}"/>
With this guard the script was absent from the Production and UnitTest pages and present in Development, on both implementations. Put the tag in
the one template that all views use, as the tag documentation suggests, so that the guard exists once.
Source: Jakarta Faces 4.1 VDL: ui:debug
faces-config.xml
faces-config.xml is the application configuration resource: an XML document in the Jakarta EE namespace that registers objects
with the Application and the factories, and that carries the settings that have no annotation. The same format is used by the
WEB-INF/faces-config.xml of the application, by the META-INF/faces-config.xml of every library and by the extra files
named in jakarta.faces.CONFIG_FILES.
The Document
A Faces 4.1 document starts with this declaration, which the specification requires:
<?xml version="1.0" encoding="UTF-8"?>
<faces-config 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-facesconfig_4_1.xsd"
version="4.1">
<!-- name, ordering, application, factory, lifecycle, ... in any order -->
</faces-config>
Source: Jakarta Faces 4.1 specification, 11.3.5 Application Configuration Resource Format and web-facesconfig_4_1.xsd
The schema of 4.1 defines the root as a choice of its children, repeated, so the elements can appear in any order and the ordering of
the schema never causes a validation error. The root has three attributes: version (4.1), id, and
metadata-complete, which stops annotation scanning when it is true in WEB-INF/faces-config.xml (see Annotations or XML). The
Project Setup page shows the namespaces and version numbers of all the earlier
releases; a document that names an older schema is still read by 4.1 runtimes, but only a 4.1 document can use the elements added since.
A <managed-bean> element in a 4.1 document does not validate against the schema, and both runtimes ignored it silently in the
scratch run: the managed bean facility is gone, and CDI replaces it (the
Backing Beans and CDI page).
The Elements
The next table is the complete list of the children of the root in the 4.1 schema, and of the children of application and factory,
with the annotation or other mechanism that replaces them where there is one.
| Element | Purpose | Annotation or alternative |
|---|---|---|
|
The name other files use in |
none |
|
Relative ordering of a library’s file, or the absolute order chosen by the application. |
none |
|
Application-wide settings and replacements; the children are in the next table. |
none |
|
Replaces or decorates a factory; the children are in the table after the next. |
none |
|
Holds |
|
|
Rule-based navigation: |
implicit navigation needs no configuration |
|
Registers a |
|
|
Registers a converter by |
|
|
Registers a validator by |
|
|
Registers a client behavior by |
|
|
Registers a render kit and its renderers, by component family and renderer type. |
|
|
A flow described in XML. |
a CDI producer annotated with |
|
|
none |
|
A design-time promise that an object will exist; the schema says it has no effect on the runtime. |
none |
|
Vendor extension point. |
none |
Source: web-facesconfig_4_1.xsd and Jakarta Faces 4.1 specification, 11.3.6 Configuration Impact on Jakarta Faces Runtime
| Element | Purpose |
|---|---|
|
|
|
|
|
A bundle whose keys replace the standard Faces messages. |
|
|
|
Replace or decorate the default implementation: the class must have a public constructor taking the previous implementation if it wants to wrap it (the decorator pattern of 11.3.7). |
|
The search expression extension points of 2.3. |
|
The render kit used when a view does not choose one. |
|
|
|
Maps view ids to contracts; the resource library contracts page. |
|
Vendor extension point. |
Source: Jakarta Faces 4.1 specification, 11.3.6 Configuration Impact on Jakarta Faces Runtime and Jakarta Faces 4.1 specification, 11.3.7 Delegating Implementation Support
| Element | Factory of |
|---|---|
|
the |
|
the |
|
the |
|
the |
|
the cache of compiled views |
|
the |
|
the |
|
the |
|
the delegates behind Facelets tag handlers |
|
the |
|
the |
|
the |
|
the |
|
the |
|
the |
Source: web-facesconfig_4_1.xsd and Jakarta Faces 4.1 specification, 11.3.7 Delegating Implementation Support
A factory is replaced by naming a class that extends the factory type and has a constructor taking the factory it wraps; Faces passes the previous one, and the new class delegates to it. The extending Faces page works through the factories that an application needs.
A Complete Configuration for Bookshelf
The next file configures the Bookshelf with the elements that have no annotation: the locales and the message bundle, a system event listener, a phase listener, a navigation rule, a converter, protected views and a name. The two classes it names follow it.
<?xml version="1.0" encoding="UTF-8"?>
<faces-config 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-facesconfig_4_1.xsd"
version="4.1">
<name>bookshelf</name>
<application>
<locale-config>
<default-locale>en</default-locale>
<supported-locale>es</supported-locale>
</locale-config>
<resource-bundle>
<base-name>org.example.bookshelf.messages</base-name>
<var>msg</var>
</resource-bundle>
<system-event-listener>
<system-event-listener-class>org.example.bookshelf.config.StageBanner</system-event-listener-class>
<system-event-class>jakarta.faces.event.PostConstructApplicationEvent</system-event-class>
<source-class>jakarta.faces.application.Application</source-class>
</system-event-listener>
</application>
<lifecycle>
<phase-listener>org.example.bookshelf.config.RenderTimer</phase-listener>
</lifecycle>
<navigation-rule>
<from-view-id>/index.xhtml</from-view-id>
<navigation-case>
<from-outcome>details</from-outcome>
<to-view-id>/other.xhtml</to-view-id>
<redirect/>
</navigation-case>
</navigation-rule>
<converter>
<converter-id>bookshelf.demo</converter-id>
<converter-class>org.example.bookshelf.convert.XmlConverter</converter-class>
</converter>
<protected-views>
<url-pattern>/admin/*</url-pattern>
</protected-views>
</faces-config>
package org.example.bookshelf.config;
import jakarta.faces.event.PhaseEvent;
import jakarta.faces.event.PhaseId;
import jakarta.faces.event.PhaseListener;
import java.util.logging.Logger;
/** Registered from faces-config.xml: logs how long the Render Response phase took. */
public class RenderTimer implements PhaseListener {
private static final Logger LOG = Logger.getLogger(RenderTimer.class.getName());
private static final String START = RenderTimer.class.getName() + ".start";
@Override
public PhaseId getPhaseId() {
return PhaseId.RENDER_RESPONSE;
}
@Override
public void beforePhase(PhaseEvent event) {
event.getFacesContext().getAttributes().put(START, System.nanoTime());
}
@Override
public void afterPhase(PhaseEvent event) {
Long start = (Long) event.getFacesContext().getAttributes().get(START);
if (start != null) {
LOG.info("render " + event.getFacesContext().getViewRoot().getViewId() + " took "
+ (System.nanoTime() - start) / 1_000_000 + " ms");
}
}
}
package org.example.bookshelf.config;
import jakarta.faces.application.Application;
import jakarta.faces.event.AbortProcessingException;
import jakarta.faces.event.PostConstructApplicationEvent;
import jakarta.faces.event.SystemEvent;
import jakarta.faces.event.SystemEventListener;
import java.util.logging.Logger;
/** Registered from faces-config.xml: logs the project stage once, when configuration processing is done. */
public class StageBanner implements SystemEventListener {
private static final Logger LOG = Logger.getLogger(StageBanner.class.getName());
@Override
public void processEvent(SystemEvent event) throws AbortProcessingException {
Application app = ((PostConstructApplicationEvent) event).getApplication();
LOG.info("Bookshelf started in project stage " + app.getProjectStage());
}
@Override
public boolean isListenerForSource(Object source) {
return source instanceof Application;
}
}
The bundle behind resource-bundle is two files, org/example/bookshelf/messages.properties (catalogue.title=Catalogue, book.saved=Book saved)
and messages_es.properties (catalogue.title=Catalogo, book.saved=Libro guardado). A view uses it as #{msg['catalogue.title']}.
The file started on both implementations with the validation parameters switched on (com.sun.faces.validateXml,
com.sun.faces.verifyObjects for Mojarra; org.apache.myfaces.VALIDATE_XML and org.apache.myfaces.VALIDATE for MyFaces). The log
showed Bookshelf started in project stage Production once, produced by the system event listener when the configuration was
finished, and render /index.xhtml took 43 ms (Mojarra) for the first request and ... took 2 ms for the second, produced by the phase
listener. A request with Accept-Language: es printed Catalogo / Libro guardado, one with en printed Catalogue / Book saved, and one
with fr, which is not a supported locale, fell back to the default Catalogue / Book saved, on both runtimes.
Checking the File
Both implementations can validate configuration files against the schema, and by their references neither does by default (the
specification requires the check only of implementations that are part of a Jakarta EE server). With a bogus element added to a 4.1 document, MyFaces with
org.apache.myfaces.VALIDATE_XML set to true logged SEVERE: cvc-complex-type.2.4.a: Invalid content was found starting with
element '{"https://jakarta.ee/xml/ns/jakartaee":bogus-element}' and kept running; Mojarra with com.sun.faces.validateXml set to
true logged nothing and started. So the switch reported the error on MyFaces and not on Mojarra in this run, which makes it a poor safety net. An
editor that knows the xsi:schemaLocation (every IDE does) and a build step that runs xmllint --schema are better tools:
curl -sO https://jakarta.ee/xml/ns/jakartaee/web-facesconfig_4_1.xsd
xmllint --noout --schema web-facesconfig_4_1.xsd src/main/webapp/WEB-INF/faces-config.xml
Annotations or XML
Every registration that has an annotation can be written either way, and the specification fixes the winner when the two disagree: an entry in an application configuration resource takes precedence over an annotation. The annotated classes are found by scanning, and the scan can be restricted or switched off.
What Is Scanned
The specification (11.4.1) says that all classes in WEB-INF/classes are scanned, that the classes of a JAR in WEB-INF/lib are scanned
only if the JAR contains a META-INF/faces-config.xml (or a file ending in .faces-config.xml, even empty), and that a
metadata-complete="true" in WEB-INF/faces-config.xml turns the scan off for everything except the implementation’s own classes. The
containers' initializer is told which annotations to look for (the list is in the API documentation of FacesServlet); that is also what
triggers the automatic mapping of the servlet. A library that wants its annotated classes found therefore ships a
META-INF/faces-config.xml, even an empty one. Mojarra scanned a library JAR without it in the scratch runs of earlier pages and MyFaces did not,
so the file is what makes the library portable.
Two parameters restrict the scan and shorten the startup of an application with a large class path:
<!-- Mojarra: package names for WEB-INF/classes, or jar:name:packages -->
<context-param>
<param-name>com.sun.faces.annotationScanPackages</param-name>
<param-value>org.example.bookshelf.convert org.example.bookshelf.web</param-value>
</context-param>
<!-- MyFaces: comma separated packages -->
<context-param>
<param-name>org.apache.myfaces.annotation.SCAN_PACKAGES</param-name>
<param-value>org.example.bookshelf.convert,org.example.bookshelf.web</param-value>
</context-param>
In the scratch run, restricting the scan to org.example.bookshelf.config (a package without the @FacesConverter class) made the page
that uses the converter fail with status 500 on both implementations, and restricting it to the package that contains the converter
made the page work. The mistake it invites is silent: a class in a package that is not listed is never registered, and the first
error is at the first use of the id.
Annotation and XML for the Same Id
The Bookshelf scratch application registers the converter id bookshelf.demo with an annotation:
package org.example.bookshelf.convert;
import jakarta.faces.component.UIComponent;
import jakarta.faces.context.FacesContext;
import jakarta.faces.convert.Converter;
import jakarta.faces.convert.FacesConverter;
@FacesConverter("bookshelf.demo")
public class AnnotatedConverter implements Converter<String> {
@Override public String getAsObject(FacesContext c, UIComponent u, String v) { return "annotation:" + v; }
@Override public String getAsString(FacesContext c, UIComponent u, String v) { return "annotation:" + v; }
}
and, in some runs, with a class that only an XML entry names:
package org.example.bookshelf.convert;
import jakarta.faces.component.UIComponent;
import jakarta.faces.context.FacesContext;
import jakarta.faces.convert.Converter;
public class XmlConverter implements Converter<String> {
@Override public String getAsObject(FacesContext c, UIComponent u, String v) { return "xml:" + v; }
@Override public String getAsString(FacesContext c, UIComponent u, String v) { return "xml:" + v; }
}
<converter>
<converter-id>bookshelf.demo</converter-id>
<converter-class>org.example.bookshelf.convert.XmlConverter</converter-class>
</converter>
A view printed <h:outputText value="x" converter="bookshelf.demo"/> under each arrangement, with the same result on Mojarra and on MyFaces:
| Arrangement | Output |
|---|---|
the annotation only, no |
|
the annotation and an XML entry for the same id in |
|
the annotation and an XML entry in a library’s |
the library’s class (XML wins) |
a library’s XML entry and an XML entry in |
the application’s class ( |
two libraries with the entry, one ordered after the other |
the class of the library ordered last |
|
status 500: Mojarra |
The rule is the one the specification gives: a registration that comes later replaces an earlier one with the same id, XML entries
are applied over the annotations, and the application’s own file is the last of the XML. An application can therefore change a
library’s behaviour without editing the library, by registering the same id in its own faces-config.xml.
Replacing a Standard Converter
The same replacement works on the identifiers that Faces itself registers, as long as the new class is a subclass of the standard one.
The standard integer converter has the id jakarta.faces.Integer; a subclass that accepts an underscore as a digit separator and an XML entry that replaces it:
package org.example.bookshelf.convert;
import jakarta.faces.component.UIComponent;
import jakarta.faces.context.FacesContext;
import jakarta.faces.convert.IntegerConverter;
/** Replacement for the standard converter id jakarta.faces.Integer: accepts a thousands separator. */
public class UnderscoreIntegerConverter extends IntegerConverter {
@Override
public Object getAsObject(FacesContext c, UIComponent u, String v) {
return super.getAsObject(c, u, v == null ? null : v.replace("_", ""));
}
}
<converter>
<converter-id>jakarta.faces.Integer</converter-id>
<converter-class>org.example.bookshelf.convert.UnderscoreIntegerConverter</converter-class>
</converter>
package org.example.bookshelf.web;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Named;
@Named
@RequestScoped
public class NumBean {
private Integer qty;
public Integer getQty() { return qty; }
public void setQty(Integer q) { this.qty = q; }
}
A form with <h:inputText value="#{numBean.qty}" converter="jakarta.faces.Integer"/> bound to this bean received 1_000. Without the entry both runtimes
reported "must be a number consisting of one or more digits." and kept the form; with it the bean got 1000 and the page printed
qty=1000. The id has to be used explicitly: the replacement applies to the converter that is looked up by id, which is
what converter="jakarta.faces.Integer" does. Use this technique sparingly: it changes every use of the id in the application, in
every library, and a reader of the view sees nothing unusual.
Which to Use
Prefer the annotation where one exists: the registration sits next to the class and cannot drift from it. Use XML when the registration must
be changeable without recompiling (a library default the application overrides), when the same class is registered under two ids,
when the item has no annotation (locales, bundles, navigation rules, phase listeners, factories, protected-views, ordering), or when
the annotation scan is too expensive and metadata-complete="true" is set so that everything is listed explicitly. A project can mix the
two freely; the rule above settles every conflict.
Several Configuration Files
An application is rarely a single file. Every JAR on the class path may bring its own faces-config.xml, the application has its
own, and a large application may split its configuration into parts. This section covers how the files are found, in which
order they are read, and what happens when they disagree.
Where the Files Are Found
The discovery rules are fixed by the specification (11.3.2) and were checked, one location at a time, with a phase listener registered
by each file and a page that printed the list of the registered phase listeners (Lifecycle.getPhaseListeners()).
| Location | Found automatically? | Observed |
|---|---|---|
|
yes |
read on Mojarra and MyFaces |
|
yes |
read on both |
|
yes |
read on both |
|
yes, and read last |
read on both, its listener last in the list |
|
no |
ignored by both until it is listed in |
a service file |
yes |
its class contributes a document on both; see Configuration from Code: ApplicationConfigurationPopulator |
Source: Jakarta Faces 4.1 specification, 11.3.2 Application Startup Behavior and Jakarta EE Tutorial: Application Configuration Resource File
The tutorial adds a sentence on the class path: files are found in the JARs of WEB-INF/lib and in parent class loaders.
Beware that the tutorial names the parameter jakarta.faces.application.CONFIG_FILES in that section: the name defined by the
specification and the API (FacesServlet.CONFIG_FILES_ATTR) is jakarta.faces.CONFIG_FILES.
The CONFIG_FILES Parameter
jakarta.faces.CONFIG_FILES lists additional files, as comma-separated paths relative to the web application root. It is meant for
an application whose configuration is split by team or by module and kept in WEB-INF:
<context-param>
<param-name>jakarta.faces.CONFIG_FILES</param-name>
<param-value>/WEB-INF/navigation.faces-config.xml,/WEB-INF/converters.faces-config.xml</param-value>
</context-param>
The specification says that when this parameter exists the search for META-INF files is skipped, and the API documentation of
FacesServlet says the listed files are "in addition to" /WEB-INF/faces-config.xml. The scratch application had two library JARs with a
META-INF/faces-config.xml (lib-a, lib-b with a b.faces-config.xml), a file in WEB-INF/classes/META-INF, the WEB-INF/faces-config.xml and
WEB-INF/other.faces-config.xml, each registering one phase listener. The lists of registered listeners were:
| Parameter | Mojarra 4.1.17 | MyFaces 4.1.4 |
|---|---|---|
not set |
|
|
|
|
|
|
|
|
(A and B are the JARs, K the file in WEB-INF/classes/META-INF, O the listed file and my the WEB-INF/faces-config.xml.) Three
facts follow. Neither implementation skipped the META-INF search when the parameter was set, so the sentence in the
specification does not describe what the two implementations do. Listing /WEB-INF/faces-config.xml is harmless: the file was loaded once,
at the end, as the specification requires. And the position of the listed file differs: Mojarra read it after the META-INF files and
MyFaces before them, so a configuration that depends on the order of the extra files must name them in ordering elements (see
Ordering of Configuration Files) rather than rely on the list.
Configuration from Code: ApplicationConfigurationPopulator
Before the documents are parsed, Faces asks every ApplicationConfigurationPopulator found with the ServiceLoader to fill an
empty faces-config document. The result is processed like a file, so a framework can compute its configuration (from a classpath scan, from
Spring properties, from annotations of its own) instead of shipping an XML file. The class below adds the render timer of the previous section with the same
elements the XML file would have contained:
package org.example.bookshelf.config;
import jakarta.faces.application.ApplicationConfigurationPopulator;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/** Adds configuration in code: the same elements a faces-config.xml would contain. */
public class AuditConfigPopulator extends ApplicationConfigurationPopulator {
private static final String NS = "https://jakarta.ee/xml/ns/jakartaee";
@Override
public void populateApplicationConfiguration(Document toPopulate) {
Element root = toPopulate.getDocumentElement();
Element lifecycle = toPopulate.createElementNS(NS, "lifecycle");
Element listener = toPopulate.createElementNS(NS, "phase-listener");
listener.setTextContent("org.example.bookshelf.config.RenderTimer");
lifecycle.appendChild(listener);
root.appendChild(lifecycle);
}
}
org.example.bookshelf.config.AuditConfigPopulator
With the service file in WEB-INF/classes/META-INF/services and no faces-config.xml listing the listener, both implementations registered
RenderTimer and logged the render times. The specification text of 11.3.2 calls the service
jakarta.faces.ApplicationConfigurationResourceDocumentPopulator; no such class exists in the 4.1 API, whose class is
jakarta.faces.application.ApplicationConfigurationPopulator, and the service file must carry that name. Mojarra’s own runtime
configuration is contributed by a subclass of it (com.sun.faces.config.configpopulator.MojarraRuntimePopulator). Application code rarely needs
this, because a faces-config.xml does the same in a form the next programmer can read; the extending Faces page
lists the other extension points for integrations.
Ordering of Configuration Files
When two files register something that can only have one value, or something that wraps what was registered before, the order in which they are read decides the result. The classpath order is not a contract: it depends on the container and the build. The specification therefore defines how files declare their order. The rules (11.3.8) are borrowed from the Servlet specification’s ordering of web fragments.
The Rules
-
A file may have a top-level
<name>. Only named files take part in ordering. -
A library file may have an
<ordering>with at most one<before>and one<after>; each contains the names of other files and may contain<others/>, the set of all other files. -
<before><others/></before>moves the file to the beginning of the list,<after><others/></after>to the end; several files that say so are in unspecified order among themselves. -
The application’s own
WEB-INF/faces-config.xmlis always read last, and it alone may contain an<absolute-ordering>: a list of<name>elements, optionally with one<others/>, that fixes the order of all the library files. A library file not named and without<others/>in an absolute ordering is ignored (its configuration is not read at all). -
An
<ordering>inWEB-INF/faces-config.xmlor an<absolute-ordering>in a library is ignored, with a log message. -
A cycle is an error that must fail the deployment, and so must two files with the same name.
<!-- library A -->
<faces-config ...>
<name>A</name>
<ordering><after><name>B</name></after></ordering>
<lifecycle><phase-listener>lib.PL_A</phase-listener></lifecycle>
</faces-config>
<!-- library B: no ordering -->
<faces-config ...>
<name>B</name>
<lifecycle><phase-listener>lib.PL_B</phase-listener></lifecycle>
</faces-config>
<!-- library C -->
<faces-config ...>
<name>C</name>
<ordering><before><others/></before></ordering>
<lifecycle><phase-listener>lib.PL_C</phase-listener></lifecycle>
</faces-config>
<!-- WEB-INF/faces-config.xml: name "my", no ordering -->
The specification derives the order C, B, A, my. The scratch application built these four files plus an unnamed library D, and
printed the list of phase listeners:
What the Two Implementations Do
Each case below was a separate deployment with the libraries named, the WEB-INF/faces-config.xml shown and one phase listener per file;
the cell is the order of the registered phase listeners.
| Case | Mojarra 4.1.17 | MyFaces 4.1.4 |
|---|---|---|
The specification’s example (A after B, C before others, D unnamed) |
|
|
|
|
|
Absolute ordering |
|
|
Absolute ordering |
startup fails: |
|
Absolute ordering |
startup fails: |
|
No ordering in any file (libraries |
|
|
|
ignored: |
ignored, no message in the log |
Two libraries both named |
deployed; |
deployed; |
A after B and B after A |
startup fails: |
|
Four results deserve attention.
-
Where the specification leaves a choice, the implementations choose differently. The unnamed library D landed between B and A on Mojarra and before B on MyFaces, and with no ordering at all the unordered libraries were read in the alphabetical order of their file names in both runs; that order came from the container’s listing of
WEB-INF/liband must not be relied upon. -
Mojarra 4.1.17 cannot start with an absolute ordering that leaves out
<others/>when there are library files, whether it names all of them or not. The stack trace is anArrayIndexOutOfBoundsExceptionthat ends incom.sun.faces.config.manager.Documents.sortDocuments(Documents.java:217). Until that is fixed, write<others/>in every<absolute-ordering>(the case with<others/>worked), and use<before>/<after>rather than an absolute ordering when you can. -
Duplicate names did not fail the deployment on either implementation, although the specification requires it, so a clash is not detected for you: two libraries must not use the same
<name>. -
A cycle fails differently: Mojarra aborted the deployment (the application answered 404 afterwards), MyFaces logged a
SEVEREmessage and answered with status 500.
What Ordering Changes
Ordering decides two things. The first is the order of decoratable artifacts: a ViewHandler, NavigationHandler,
ActionListener, factory or other class named in <application> or <factory> wraps the one registered before it, so the file read
last is the outermost wrapper. The second is every registration that has an id: a later file replaces an earlier one, as the converter
table of Annotations or XML shows. For phase listeners, the order of the list is also the order of the calls: in both runs
beforePhase was called for the listeners in list order (C, B, D, A, my on Mojarra) and afterPhase in reverse order (my, A, D, B, C), so the first
listener registered is the outermost one. The Events and Listeners page describes how listeners registered in faces-config.xml relate to those of a view.
Mojarra Parameters
Mojarra reads about fifty parameters of its own, all in the com.sun.faces. namespace, and documents each in the file
CONTEXT-PARAMS.md of its 4.1 branch, which a test keeps in step with the code. The table lists all of them, grouped as in that file, with the default and what they do. A parameter that
Mojarra does not know is ignored without a message, and MyFaces ignores the com.sun.faces. names in the same way (it reads the names of the next
section), so a shared web.xml can carry both sets. Run Mojarra with com.sun.faces.displayConfiguration set to true and
every parameter it reads is logged at startup; the scratch run printed lines such as
INFO: JSF1021: [/bookshelf] Configuration option 'com.sun.faces.validateXml' - DISABLED and
INFO: JSF1018: [/bookshelf] Configuration option 'jakarta.faces.STATE_SAVING_METHOD' set to 'client'.
| Parameter | Default | Effect |
|---|---|---|
|
none |
Restricts the annotation scan to the listed packages (and |
|
|
Logs every parameter value at |
|
|
Starts the configuration even when no |
|
|
Parses the configuration files and scans annotations on a thread pool; also gates a watcher of the configuration files that runs in |
|
none |
Regular expression that recognises the same library packaged twice, so its |
|
|
Validates configuration files against the schema. In the scratch run it logged nothing for an invalid file. |
|
|
Checks at startup that every class named in the configuration exists and has a public no-argument constructor. Logs |
|
none |
Class name of the |
|
|
Sends an |
|
none |
Comma-separated exception classes the default |
|
|
Removes |
Source: Mojarra 4.1 context parameters
| Parameter | Default | Effect |
|---|---|---|
|
|
|
|
|
Re-applies the Facelets page to the restored tree before rendering: a second build of the view on every postback (since 4.0.19). A migration crutch for views that change outside Faces. |
|
|
Remembers what |
|
|
Generated component ids follow the position of the tag in the page, which keeps them stable across views that include the same page. |
|
|
Server state saving: how many initially requested views the session remembers. Together with the next parameter it sizes the session. |
|
|
Server state saving: how many postback states are kept per logical view. |
|
|
GZIP-compresses the serialized view state (client state, or server state when |
|
none |
Minutes a client-side state stays valid; a later restore throws |
|
|
Buffer size, in bytes, used while writing client state. |
|
none |
|
|
|
Deserializes the client state right after writing it, to surface serialization problems. Doubles the cost. |
|
|
Renders the |
|
|
Renders |
|
|
Writes the hidden state field before |
|
|
Answers with |
|
|
Whether non-ASCII characters are escaped into entities; |
|
|
Wraps inline script in a comment for browsers that do not know |
|
|
Renders children of |
Source: Mojarra 4.1 context parameters
| Parameter | Default | Effect |
|---|---|---|
|
|
Caches the last-modified time of a resource instead of reading the file on every request. |
|
none |
Comma-separated MIME types ( |
|
|
Milliseconds a client may cache a resource (seven days). |
|
|
Fails the view when a composite component names a resource library that does not exist. |
|
|
Buffer size, in bytes, used while streaming a resource. |
|
|
Minutes between two checks whether a cached resource changed; |
|
|
Registers a |
|
|
Re-sets session attributes after every change so a clustered container replicates them. |
|
|
Returns a no-op |
|
|
Writes the flash cookie on every response. |
|
|
View scope maps kept in the session; the least recently used is destroyed beyond that. The Scopes page observed it. |
|
|
Size of the application-wide flash store (since 4.0.7). The misspelled |
|
|
Flash creations between two sweeps of expired entries. |
|
|
Milliseconds after which an idle WebSocket session is closed; |
|
none |
Maximum concurrent WebSocket sessions per channel; unbounded by default (since 4.0.21). |
|
|
Space-separated HTTP methods the |
|
|
Completes the response in Restore View for |
|
|
Random identifiers for server-side state instead of a counter. |
|
|
Turns off encryption and the tamper evidence of client state; a debugging aid, never for production. |
|
|
Per-response nonce on rendered scripts and the |
|
|
Allows attribute values that start with |
|
|
Rejects a Facelets source with a |
Source: Mojarra 4.1 context parameters
Two practical notes. The page of CONTEXT-PARAMS.md also says that a custom value is allowed for PROJECT_STAGE; as shown in
How the Stage Is Determined, in practice a name that is not a constant becomes Production. And parameters with a
com.sun.faces. name that you find in older articles (for example com.sun.faces.expressionFactory) are not in the 4.1 reference
and should be treated as inert.
MyFaces Parameters
MyFaces documents its parameters in the configuration section of its Core 4.1 page, in groups (common, validation, EL, render, view
handler, resources, state). They live in the org.apache.myfaces. namespace, apart from the standard ones the page repeats.
MyFaces prints its parameters with org.apache.myfaces.LOG_WEB_CONTEXT_PARAMS: the default is dev-only, which logs in Development and nowhere else; true
logs in every stage. The scratch run printed INFO: Init context parameter found 'jakarta.faces.PROJECT_STAGE' set to 'Production'
for a parameter that was set and INFO: No context init parameter 'org.apache.myfaces.MAC_SECRET' found. for one that was not. A placeholder value set for
org.apache.myfaces.SECRET was not printed in the log of that run, which is how it should be: do not put a real secret in a parameter
you also print.
In the table the prefix org.apache.myfaces. is left out (the reference writes it o.a.m.). The table lists the parameters that matter
in practice; the page of the reference has the rest.
| Parameter | Default | Effect |
|---|---|---|
|
|
Logs the parameters at startup: |
|
|
MyFaces writes its own error page for an unhandled exception. Run: switched on in |
|
|
The templates of the error page and of the |
|
|
Adds a listener that records submitted, local and converted values. |
|
off |
Schema validation of configuration and tag library files; and a consistency check of the configuration (the reference names managed beans and navigation rules). Run: the first logged a |
|
none |
Comma-separated exception classes the |
|
|
Wraps EL exceptions so the handler can report the location, expression and tag. |
|
|
Seconds between checks for changes of the web configuration. |
|
|
Skips the check for a |
|
|
Skips scanning JARs for |
|
none |
Class names of integration points for containers and frameworks. |
|
none |
Comma-separated packages scanned for annotations. Run: see Annotations or XML. |
|
|
Uses CDI’s discovery instead of MyFaces’s own scan. |
|
|
Loads the classes of components, converters, validators and behaviors when first used. |
|
|
Uses |
|
|
Tuning of the view pool. The pool needs |
|
|
Creates the session before rendering if there is none. |
|
|
Disables the flash scope and its cookie. |
|
|
Logs the resolvers consulted per request ( |
|
none, |
Limits of the |
| Parameter | Default | Effect |
|---|---|---|
|
|
Input fields are cleared when null or empty values are submitted. |
|
|
A |
|
|
|
|
|
|
|
|
Adds |
|
|
Enables the EL |
|
none |
Replace the expression factory, order the EL resolvers, or leave one out. The reference warns that this can break the resolvers the specification requires. |
|
|
Composite component |
|
|
Uses |
|
|
Sends the |
|
|
Renders the view state and hidden fields at the beginning of the form. |
|
|
Which build of |
|
|
Content type when the |
|
|
Client behavior scripts are passed as strings. |
|
|
Restore View answers 404 when the view id does not exist. |
|
|
|
|
|
Caches that avoid repeated look-ups of view ids. |
|
|
Caches for generated ids. |
|
|
Cache of "does this resource exist". |
|
|
Milliseconds in the |
|
|
Buffer while streaming a resource; cache of the last-modified time in |
|
|
Cache resources of JARs in a temporary directory; allow a slash in a library name. |
| Parameter | Default | Effect |
|---|---|---|
|
|
Latest views kept in the session with server state saving. Evicted state leads to |
|
|
Views kept for a sequence of POST or POST-redirect-GET navigations. |
|
|
Lets old views be purged after Post/Redirect/Get. |
|
none |
Maximum flash tokens in the session. |
|
|
Encrypts the view state (client saving). Never set to |
|
|
The cipher, its mode and padding, the initialization vector and the key (Base64). The reference gives no default for the key: a cluster
needs the same one on every node, supplied from the environment (see below). The documented default mode is |
|
|
The message authentication code of the state and its key. |
|
|
Compression before encryption in client state, and in the session. |
|
none |
Factory class for serializing the state. |
|
|
Minutes a client state stays valid. |
|
|
The random key added to the server view state token (and |
|
|
Renders the |
|
|
|
|
|
Whether the page is re-applied to a refreshed view and whether state is preserved for |
|
|
How duplicate ids are checked in |
The key parameters are the one place where a configuration file tempts a programmer into a security mistake. A key must be the same on every node of a cluster and must not sit in the version control system of the project. Supply it at build or deploy time from the environment, and build or deploy fails when it is missing:
<context-param>
<param-name>org.apache.myfaces.SECRET</param-name>
<param-value>${env.BOOKSHELF_VIEWSTATE_SECRET}</param-value>
</context-param>
With the war plugin filtering of the earlier section, a build with BOOKSHELF_VIEWSTATE_SECRET=placeholder-from-ci in its environment wrote that
value into the packaged descriptor, and a build without the variable left the text ${env.BOOKSHELF_VIEWSTATE_SECRET} in it unreplaced, which is why the
value must be checked after packaging (a deploy script that greps the descriptor for ${ is enough). The value shown is a placeholder; a real key is
generated with a secure random source and kept in the CI secret store or the server’s configuration. The state saving page explains the
format of the key and the cluster implications.
Extensionless Mapping and the FacesServlet Mappings
Which URLs reach the FacesServlet is configuration too. The Project Setup page covers the three mapping styles of web.xml
(extension, prefix and exact); this section covers the parts that depend on parameters: the mapping Faces adds when you declare none, the
Faces 4.0 extensionless mapping, and what each setting does to the URLs the application generates.
The Automatic Mapping
When the servlet is not mapped in web.xml or web-fragment.xml and Faces detects that the application uses it (the triggers of the
diagram at the start of this page), the implementation maps it to four patterns: /faces/*, *.jsf, *.faces and *.xhtml.
jakarta.faces.DISABLE_FACESSERVLET_TO_XHTML removes the last of them. A mapping that you declare yourself replaces all four.
AUTOMATIC_EXTENSIONLESS_MAPPING
With jakarta.faces.AUTOMATIC_EXTENSIONLESS_MAPPING set to true, the implementation scans the web application at startup and
adds a mapping for the extensionless variant of every view it finds (/index for /index.xhtml). Mojarra’s reference warns that
the scan walks the whole web root and registers a mapping per view, so the startup cost grows with the number of views.
<context-param>
<param-name>jakarta.faces.AUTOMATIC_EXTENSIONLESS_MAPPING</param-name>
<param-value>true</param-value>
</context-param>
The exact alternative, which the Jakarta EE Tutorial describes, lists the views yourself and costs nothing at startup:
<servlet-mapping>
<servlet-name>facesServlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
<url-pattern>/index</url-pattern>
<url-pattern>/other</url-pattern>
</servlet-mapping>
Five configurations of the scratch application were requested at six URLs. Mojarra and MyFaces gave the same status code in every cell; "raw" means that the response was the unprocessed source of the view.
| URL | No servlet declared, no parameter | Parameter true, no servlet declared |
Parameter true, *.xhtml declared |
Exact /index and /other added to *.xhtml |
DISABLE_FACESSERVLET_TO_XHTML, no servlet declared |
|---|---|---|---|---|---|
|
404 |
200 |
200 |
200 |
404 |
|
200 |
200 |
200 |
200 |
200, raw source |
|
200 |
200 |
404 |
404 |
200 |
|
200 |
200 |
404 |
404 |
200 |
|
200 |
200 |
404 |
404 |
200 |
|
404 |
200 |
200 |
200 |
404 |
Source: Jakarta Faces 4.1 API: FacesServlet and Jakarta EE Tutorial: Identifying the Servlet for Lifecycle Processing
The table has three consequences.
-
A declared mapping replaces the automatic ones. With
*.xhtmldeclared,/faces/index.xhtmland/index.jsfstop working, even though the extensionless parameter is on. That is usually what you want, and it explains a bookmarked old URL that suddenly answers 404 after someone adds a<servlet-mapping>. -
The extensionless parameter adds, it does not replace. The
.xhtmlURLs keep working, which is why a site migrating to clean URLs must redirect or canonicalise the old ones itself. -
DISABLE_FACESSERVLET_TO_XHTMLwithout a mapping of your own serves the views as text./index.xhtmlanswered 200 with the literalstage=#{configInfoBean.stage}of the source on both implementations, and/faces/index.xhtmlstill rendered: an attacker reads every view’s source, including the EL expressions and the structure of the application, by dropping the prefix. Use the parameter only together with an explicit mapping for each URL pattern that must work, and asecurity-constraintfor the rest, exactly as for prefix mapping.
URLs Generated by Faces
Faces builds the URLs of links, form actions and redirects from the mapping of the current request. With the extensionless parameter on, a page requested with its extension linked to the other pages with their extension, and a page requested extensionless linked to extensionless URLs:
| Request | h:link outcome="other" | Form action | Redirect from action="other?faces-redirect=true" |
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
not run |
|
|
not run |
not run |
The results are identical for Mojarra and MyFaces, and also hold for the configuration with exact mappings for /index and /other. The
rule has one consequence for links: the first URL of a visit decides the form of every later one, so a canonical form has to be
imposed on the first request (a redirect from the extension form to the clean form, or a link from outside that uses the clean
form). Another consequence is that the view id never changes: navigation outcomes, include-view-params, f:viewParam and the security
patterns are written with view ids, and the mapping is only a prefix or suffix applied when the URL is built. The
Navigation page and the View Parameters page show that in use.
Mojarra and MyFaces
The two implementations pass the same specification and agreed on most of what this page measured: the parameter semantics of the standard names, the requirement that XML beats annotations, the discovery locations, the mapping matrix, the generated URLs, the JNDI precedence of the stage and the silent handling of unknown names. They differ where the specification leaves a choice, and in a few places where it does not.
| Topic | Mojarra 4.1.17 | MyFaces 4.1.4 |
|---|---|---|
Parameter namespace and printing |
|
|
|
Behave as non-production for unresolved |
Behave as |
Failure while rendering |
|
|
A resource that does not exist |
|
Nothing rendered, nothing logged. |
|
The scan is not skipped; the listed file is read after the |
The scan is not skipped; the listed file is read before them. |
Libraries with no ordering |
Alphabetical by file name. In the specification’s example the unnamed library D landed between B and A. |
Alphabetical by file name. In the specification’s example the unnamed library D landed before B. |
|
Startup fails with |
Works; unlisted files are ignored, as specified. |
|
Ignored with the warning |
Ignored without a message. |
Two files with the same name |
Both deployed (the specification asks for a failed deployment). |
Both deployed. |
Cycle in the ordering |
Deployment aborted. |
|
XML validation switch |
|
|
|
A list works; the view mappings need the matching suffix. |
A list of |
Ajax error in |
|
No alert. |
The practical rule stays the one of the Project Setup page: keep the implementation parameters in a profile or a container-specific descriptor, and test configuration-dependent behaviour on the implementation that production uses.
What Changed
| Version | Change |
|---|---|
Faces 2.0 |
|
Faces 2.2 |
|
Faces 2.3 |
|
Faces 3.0 |
The |
Faces 4.0 |
|
Faces 4.1 |
The 4.1 schema and |
Faces 5.0 (upcoming) |
Still at |
Where the Books Are Outdated
The books consulted for this section describe Faces 1.0 to 2.2. The faces-config.xml reference of Burns and Schalk and the
configuration chapter of Dudney and colleagues are the ones that touch this page, and the configuration they teach has changed in these ways:
-
javax.faces.parameter names.* Every parameter of the books has ajakarta.faces.name since 3.0, and the old names are ignored without a message (verified:javax.faces.PROJECT_STAGEhad no effect on either implementation). -
<managed-bean>,<managed-property>and<referenced-bean>infaces-config.xml. The first two are gone from the schema and from the runtime, and a<managed-bean>element is ignored;<referenced-bean>remains in the schema only as a note for tools. Beans are CDI beans. -
The Pages-era configuration. JSP views,
DEFAULT_SUFFIXand aFacesServletmapped to*.jspor*.jsffor JSP pages belong to the past; the default mapping and suffix are.xhtmland the Pages suffix is deprecated for removal. -
DTD and old schemas. The Faces 1.0 and 1.1 DOCTYPE with
web-facesconfig_1_x.dtdand the schemas of 1.2 to 2.3 name namespaces that the 4.1 documents do not use; the Project Setup page tabulates them. -
The Facelets 1.x parameters. The standalone Facelets book configures the library through its own
facelets.*context parameters and acom.sun.faceletsview handler. Facelets is part of Faces since 2.0, and thejakarta.faces.FACELETS_*parameters of this page replace them. -
Implementation parameters. The Reference Implementation parameters of older books and articles come from Mojarra 1.x and 2.x. Check every name against
CONTEXT-PARAMS.md: a name that is not there (for examplecom.sun.faces.expressionFactory) is not a 4.1 parameter, and an unknown name is ignored without a message. -
Project stages and development mode. Standalone Facelets had a development setting of its own. The
ProjectStageof Faces 2.0 replaces it, and its effects are the ones of Project Stages, fewer than a reader may assume. -
Secrets in configuration. Nothing in Faces configuration needs a literal secret: take keys and passwords from the environment or the server, as shown for the MyFaces key, and keep placeholders in the files under version control.
Source: Jakarta EE Tutorial: Configuring Jakarta Faces Applications (the tutorial documents Jakarta EE 10; its managed-bean pages and the schema 3.0 shown in it are outdated for Faces 4.1)
Common Mistakes
-
Leaving
Developmentinweb.xmlof a release. The error page, the unhandled-message list and the refresh checks reach production. MakeProductionthe default of the build and selectDevelopmentwith a profile, or take the stage from JNDI. -
Believing
UnitTestandSystemTestdo something. On MyFaces they equalProduction; on Mojarra they differ in one rendering detail. -
Believing
ui:debugis switched off in production. It is not; guard it with the stage, once, in the master template. -
Enabling
ERROR_HANDLING(MyFaces) or the Development stage on a public server to find a problem. Stack traces, bean state and the component tree go to the client. -
Mistyping a parameter name. Nothing complains; print the parameters at startup and look.
-
Trusting
requiredfor server-side rules. A request that omits the field skips validation unlessALWAYS_PERFORM_VALIDATION_WHEN_REQUIRED_IS_TRUEis set; validate on the server whatever the browser sends. -
A view suffix other than
.xhtmlwithout a constraint. The raw Facelets source is served by the container. -
DISABLE_FACESSERVLET_TO_XHTMLwithout a mapping of your own. The.xhtmlviews are then served as plain text. -
Absolute ordering without
<others/>on Mojarra 4.1.17. The application does not start. -
Relying on classpath order. The order of unordered files is whatever the container lists; use
<ordering>. -
Relying on
CONFIG_FILESto replace theMETA-INFsearch. Neither implementation skipped it. -
Duplicate
<name>values. The deployment is not refused, and one of the files may be shadowed. -
Restricting the annotation scan too far. A converter in a package that is not listed fails at first use, not at startup.
-
Real secrets in
web.xmlorfaces-config.xml. Keys, passwords and database URLs belong in the environment or the server; the files in version control carry placeholders. -
Changing a descriptor and expecting a reload. Only the view files are re-read; every parameter is read at startup.
Related Pages
The Project Setup page introduces the descriptors and the hot-reload loop that this page extends. The
Scopes page measures NUMBER_OF_CLIENT_WINDOWS, CLIENT_WINDOW_MODE and the eviction parameters, the
lifecycle page explains where the stage-dependent behaviour of validation sits, and the
Navigation page covers the rules that go in faces-config.xml. The state saving,
resource handling, resource library contracts,
exception handling, extending Faces,
performance and security pages pick up the parameters that belong to them, and the
Tomcat and Weld, servers,
Spring Boot with JoinFaces and Quarkus pages show how the same
configuration is expressed where there is no web.xml.
References
-
Jakarta Faces 4.1 specification — chapter 11: 11.1.3 Application Configuration Parameters, 11.3 Application Configuration Resources (11.3.2 Startup, 11.3.5 Format, 11.3.6 Impact on the Runtime, 11.3.7 Delegating Implementation Support, 11.3.8 Ordering, 11.3.9 Example, plus 11.3.4 Shutdown) and 11.4 Annotations
-
Jakarta EE Tutorial: Configuring Jakarta Faces Applications (documents Jakarta EE 10)
-
Apache MyFaces Core 4.1: requirements, dependencies and configuration
-
Apache Maven WAR Plugin: Adding and Filtering External Web Resources