Using JSF

Upgrading Faces to Jakarta

Liferay DXP 2025.Q3+

Liferay Faces now uses the jakarta.* namespace to align with Jakarta EE 9 APIs. Migrating an existing Liferay Faces (JSF) portlet from the legacy javax.* namespace requires updating dependency coordinates, XML namespaces, and Java imports.

Because the migration uses a transformed build of JSF 2.3, the underlying JSF semantics are unchanged. Behavioral changes to your application are minimal.

Important

Before changing Faces dependencies, bring your Liferay Workspace and target platform up to a Jakarta-based release. See Update Workspace in the general Jakarta upgrade guide — set the Workspace Gradle plugin to 14.0.0 or later and liferay.workspace.target.platform.version=2025.q3.0 or later.

Step 1: Install the Jakarta Runtime (Thin WAR Only)

If your project uses a Thin WAR packaging model (where runtime dependencies are provided by the Liferay server rather than bundled in the WAR), you must deploy the new Jakarta-namespaced runtime JARs to your Liferay instance before deploying your migrated portlets.

Copy the following JARs into the ${liferay.home}/osgi/modules/ folder. Wait for all bundles to reach the STARTED state in the server log before proceeding.

RoleRequired JAR
Portlet Bridge APIcom.liferay.faces.bridge.api-7.0.0.jar
Portlet Bridge Implcom.liferay.faces.bridge.impl-7.0.0.jar
Bridge Extensionscom.liferay.faces.bridge.ext-9.0.0.jar
Shared Utilitiescom.liferay.faces.util-5.0.0.jar
Liferay Portal Tagscom.liferay.faces.portal-7.0.0.jar
Alloy Tags (if used)com.liferay.faces.alloy-5.0.0.jar
JSF 2.3 Impljakarta.faces-2.3.21.LIFERAY-PATCHED-4.JAKARTA-LIFERAY-PATCHED-1.jar
PrimeFaces (if used)org.primefaces-15.0.6.LIFERAY-PATCHED-3.JAKARTA-LIFERAY-PATCHED-1.jar
Note

If you deploy a Thin WAR before these bundles are active, the WAR fails to start and throws ClassNotFoundException: jakarta.faces.webapp.FacesServlet.

Step 2: Update Project Dependencies

Update your project’s build file (e.g., pom.xml or build.gradle) to use the new Jakarta-namespaced dependency versions.

If you are using a Thin WAR, set the scope of these dependencies to provided. If you are using a Thick WAR (bundling the runtime), set the scope to compile or runtime, with the exception of jakarta.portlet-api and jakarta.servlet-api, which must always remain provided.

Key dependency coordinates:

DependencyVersion
com.liferay.faces:com.liferay.faces.bridge.api7.0.0
com.liferay.faces:com.liferay.faces.bridge.impl7.0.0
com.liferay.faces:com.liferay.faces.bridge.ext9.0.0
com.liferay.faces:com.liferay.faces.util5.0.0
com.liferay.faces:com.liferay.faces.portal7.0.0
com.liferay.faces:com.liferay.faces.alloy5.0.0
com.liferay:jakarta.faces2.3.21.LIFERAY-PATCHED-4.JAKARTA-LIFERAY-PATCHED-1
com.liferay:org.primefaces15.0.6.LIFERAY-PATCHED-3.JAKARTA-LIFERAY-PATCHED-1
com.liferay.jakarta.portlet:com.liferay.jakarta.portlet-api4.0.0
jakarta.servlet:jakarta.servlet-api5.0.0

Step 3: Automate the Namespace Migration

Do not manually edit your Java imports and XML files. Use a batch migration tool such as the Jakarta Upgrade Tool (blade gw upgradeJakarta), Eclipse Transformer, or OpenRewrite.

The Jakarta Upgrade Tool rewrites javax.* references — including javax.faces.*, javax.portlet.*, javax.inject.*, and javax.enterprise.* — to jakarta.* across Java sources, JSPs, XML descriptors, bnd.bnd, and build.gradle files. It also remaps the Liferay Faces, jakarta.faces, and PrimeFaces Gradle/BND coordinates to their Jakarta-namespaced replacements.

Note

Facelet .xhtml templates are not in the Jakarta Upgrade Tool’s per-extension handler list as of Liferay DXP 2026.Q1. Inspect each.xhtmlforxmlnsattributes that still referencehttp://java.sun.com/jsforhttp://xmlns.jcp.org/jsfand EL expressions that referencejavax.*; update them manually, or run a complementary tool (such as Eclipse Transformer) over your view templates.

Warning

Standard Java SE packages (such as javax.sql.* and javax.crypto.*) are not part of Jakarta EE and must not be renamed. The Jakarta Upgrade Tool excludes these by design. If you use a different tool, confirm it excludes them or revert manually.

Step 4: Update XML Descriptors

Confirm each descriptor in your WEB-INF folder is correct:

  1. In web.xml, the namespace must be https://jakarta.ee/xml/ns/jakartaee (version 5.0+) and the <servlet-class> must point to the Jakarta FacesServlet:

    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>jakarta.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
  2. In portlet.xml, the namespace must use the Jakarta Portlet 4.0 schema and the <portlet-class> must point to the Jakarta package:

    <portlet-class>jakarta.portlet.faces.GenericFacesPortlet</portlet-class>
    <init-param>
        <name>jakarta.portlet.faces.defaultViewId.view</name>
        <value>/WEB-INF/views/view.xhtml</value>
    </init-param>
    
  3. In liferay-plugin-package.properties, confirm the -cdiannotations: instruction is present:

    -cdiannotations:
    

    This prevents Liferay’s WAB Generator from scanning CDI annotations, which lets the bundled CDI implementation (Weld) discover beans for the JSF portlet.

Step 5: Deploy and Validate

Compile and deploy your updated WAR to your Liferay instance, then validate the migration:

  1. Check the Liferay logs to confirm the WAR starts without bundle-wiring errors.

  2. Navigate to the portlet and test view rendering, file uploads, and inter-portlet events.

  3. Execute an Ajax interaction and confirm it routes correctly without returning a 403 error.

  4. If you bundle PrimeFaces, test the components you use to confirm compatibility with the LIFERAY-PATCHED Jakarta build.

For more on Liferay Faces artifact versioning, see Liferay Faces Version Scheme.

Troubleshooting

  • Injected dependencies fail to wire: Ensure beans.xml is present in your WEB-INF folder, -cdiannotations: is present in liferay-plugin-package.properties, and that no scope annotations still reference the old javax.* packages.
  • Bundle-wiring errors in staging or production: Verify that the Thin WAR runtime JARs in your remote osgi/modules folder exactly match the versions your WAR expects. Align the server runtime before deploying the migrated WAR.