diff --git a/jsf/subsystem/pom.xml b/jsf/subsystem/pom.xml
index bf8fce622b63..c5b75427ab82 100644
--- a/jsf/subsystem/pom.xml
+++ b/jsf/subsystem/pom.xml
@@ -67,6 +67,11 @@
jakarta.enterprise.cdi-api
+
+ jakarta.servlet
+ jakarta.servlet-api
+
+
jakarta.validation
jakarta.validation-api
diff --git a/jsf/subsystem/src/main/java/org/jboss/as/jsf/deployment/JSFMetadataProcessor.java b/jsf/subsystem/src/main/java/org/jboss/as/jsf/deployment/JSFMetadataProcessor.java
index 5c4d925a999a..6fd7a15d93be 100644
--- a/jsf/subsystem/src/main/java/org/jboss/as/jsf/deployment/JSFMetadataProcessor.java
+++ b/jsf/subsystem/src/main/java/org/jboss/as/jsf/deployment/JSFMetadataProcessor.java
@@ -10,6 +10,7 @@
import jakarta.faces.application.ViewHandler;
import org.jboss.as.jsf.logging.JSFLogger;
+import org.jboss.as.jsf.subsystem.JSFResourceDefinition;
import org.jboss.as.server.deployment.DeploymentPhaseContext;
import org.jboss.as.server.deployment.DeploymentUnit;
import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
@@ -18,8 +19,11 @@
import org.jboss.metadata.javaee.spec.ParamValueMetaData;
import org.jboss.metadata.web.jboss.JBossServletMetaData;
import org.jboss.metadata.web.jboss.JBossWebMetaData;
+import org.jboss.metadata.web.spec.ListenerMetaData;
import org.jboss.metadata.web.spec.MultipartConfigMetaData;
+import com.sun.faces.config.ConfigureListener;
+
/**
* @author Stuart Douglas
*/
@@ -66,11 +70,12 @@ public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitPro
if(JsfVersionMarker.isJsfDisabled(deploymentUnit)) {
return;
}
- if(metaData == null || metaData.getMergedJBossWebMetaData() == null || metaData.getMergedJBossWebMetaData().getServlets() == null) {
+ JBossWebMetaData webMetaData = (metaData != null) ? metaData.getMergedJBossWebMetaData() : null;
+ if (webMetaData == null || webMetaData.getServlets() == null) {
return;
}
JBossServletMetaData jsf = null;
- for(JBossServletMetaData servlet : metaData.getMergedJBossWebMetaData().getServlets()) {
+ for(JBossServletMetaData servlet : webMetaData.getServlets()) {
if(JAVAX_FACES_WEBAPP_FACES_SERVLET.equals(servlet.getServletClass())) {
jsf = servlet;
}
@@ -81,22 +86,34 @@ public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitPro
}
if (disallowDoctypeDecl != null) {
// Add the disallowDoctypeDecl context param if it's not already present
- setContextParameterIfAbsent(metaData.getMergedJBossWebMetaData(), DISALLOW_DOCTYPE_DECL, disallowDoctypeDecl.toString());
+ setContextParameterIfAbsent(webMetaData, DISALLOW_DOCTYPE_DECL, disallowDoctypeDecl.toString());
}
- // Auto-disable lazy bean validation for distributable web application.
- // This can otherwise cause missing @PreDestroy events.
- if (metaData.getMergedJBossWebMetaData().getDistributable() != null) {
+ if (webMetaData.getDistributable() != null) {
+ // Auto-disable lazy bean validation for distributable web application.
+ // This can otherwise cause missing @PreDestroy events.
String disabled = Boolean.toString(false);
- if (!setContextParameterIfAbsent(metaData.getMergedJBossWebMetaData(), LAZY_BEAN_VALIDATION_PARAM, disabled).equals(disabled)) {
+ if (!setContextParameterIfAbsent(webMetaData, LAZY_BEAN_VALIDATION_PARAM, disabled).equals(disabled)) {
JSFLogger.ROOT_LOGGER.lazyBeanValidationEnabled();
}
+
+ String version = JsfVersionMarker.getVersion(deploymentUnit);
+ // Disable counter-productive "distributable" logic in Mojarra implementation
+ if (version.equals(JsfVersionMarker.JSF_4_0) && JSFModuleIdFactory.getInstance().getImplModId(version).getSlot().equals(JSFResourceDefinition.DEFAULT_SLOT)) {
+ ListenerMetaData mojarraListenerMetaData = new ListenerMetaData();
+ mojarraListenerMetaData.setListenerClass(ConfigureListener.class.getName());
+ ListenerMetaData workaroundListenerMetaData = new ListenerMetaData();
+ workaroundListenerMetaData.setListenerClass(NonDistributableServletContextListener.class.getName());
+
+ webMetaData.getListeners().add(mojarraListenerMetaData);
+ // Ensure workaround listener runs after Mojarra's bootstrap listener
+ webMetaData.getListeners().add(workaroundListenerMetaData);
+ }
}
// Set a default buffer size as 1024 is too small
- final JBossWebMetaData webMetaData = metaData.getMergedJBossWebMetaData();
// First check the legacy facelets.BUFFER_SIZE property which is required for backwards compatibility
if (!hasContextParam(webMetaData, "facelets.BUFFER_SIZE")) {
// The legacy parameter has not been set, set a default buffer if the current parameter name has not been set.
- setContextParameterIfAbsent(metaData.getMergedJBossWebMetaData(), ViewHandler.FACELETS_BUFFER_SIZE_PARAM_NAME, Integer.toString(defaultBufferSize));
+ setContextParameterIfAbsent(webMetaData, ViewHandler.FACELETS_BUFFER_SIZE_PARAM_NAME, Integer.toString(defaultBufferSize));
}
}
diff --git a/jsf/subsystem/src/main/java/org/jboss/as/jsf/deployment/NonDistributableServletContextListener.java b/jsf/subsystem/src/main/java/org/jboss/as/jsf/deployment/NonDistributableServletContextListener.java
new file mode 100644
index 000000000000..cb83372e17d2
--- /dev/null
+++ b/jsf/subsystem/src/main/java/org/jboss/as/jsf/deployment/NonDistributableServletContextListener.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package org.jboss.as.jsf.deployment;
+
+import jakarta.faces.context.FacesContext;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletContextEvent;
+import jakarta.servlet.ServletContextListener;
+
+import com.sun.faces.config.InitFacesContext;
+import com.sun.faces.config.WebConfiguration;
+
+/**
+ * Workaround for counter-productive "distributable" logic in Mojarra.
+ * This setting is used to trigger redundant calls to HttpSession.setAttribute(...) for mutated attributes.
+ */
+public class NonDistributableServletContextListener implements ServletContextListener {
+
+ @Override
+ public void contextInitialized(ServletContextEvent event) {
+ ServletContext context = event.getServletContext();
+ FacesContext facesContext = new InitFacesContext(context);
+ try {
+ WebConfiguration.getInstance(context).setOptionEnabled(WebConfiguration.BooleanWebContextInitParameter.EnableDistributable, false);
+ context.setAttribute(WebConfiguration.BooleanWebContextInitParameter.EnableDistributable.getQualifiedName(), Boolean.FALSE);
+ } finally {
+ facesContext.release();
+ }
+ }
+}