eclipse-ee4j/mojarra

ID of composite component gets initialized early without parent IDs when it's referenced in f:ajax execute attribute

Closed this issue · 1 comments

Hurz commented

Accessing the clientId of a composite component can be initialized early in its lifecycle when referencing it in a f:ajax execute. This early initialization will prevent the component to being aware of its parents and can therefore cause duplicate ID errors.

To Reproduce

I've attached a sample application DemoDuplicateComponentBug.zip. Here is the code of the involved components of the sample application:

index.xhtml

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:b="http://xmlns.jcp.org/jsf/composite/base-components"
      xmlns:h="http://xmlns.jcp.org/jsf/html">

<body>

  <h:form id="contentForm">
    <b:outerComponent id="firstInstanceOfOuterComponent" />
    <b:outerComponent id="secondInstanceOfOuterComponent" />
  </h:form>

</body>
</html>

outerComponent.xhtml

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:b="http://xmlns.jcp.org/jsf/composite/base-components"
      xmlns:composite="http://xmlns.jcp.org/jsf/composite">

<composite:interface>
</composite:interface>

<composite:implementation>

        <b:middleComponent id="middleComponentInOuterComponent"/>

</composite:implementation>
</html>

middleComponent.xhtml

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://xmlns.jcp.org/jsf/core"
      xmlns:b="http://xmlns.jcp.org/jsf/composite/base-components"
      xmlns:composite="http://xmlns.jcp.org/jsf/composite">

<composite:interface>
</composite:interface>

<composite:implementation>
    <b:innerComponent>
      <!--
       this will fail as long as the clientId is referenced in the execute attribute.
       Any other references to the clientId (e.g. in the render tag) works.
      -->
      <f:ajax execute="#{cc.clientId}" event="change"/>
      <!-- This works and will not cause a duplicate ID error:
      <f:ajax render="#{cc.clientId}" event="change"/>
      -->
    </b:innerComponent>
</composite:implementation>
</html>

innerComponent.xhtml

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:composite="http://xmlns.jcp.org/jsf/composite"
>

<composite:interface>
  <composite:clientBehavior name="change"
                            event="change"
                            targets="input"/>
</composite:interface>

<composite:implementation>
      <h:selectOneMenu id="input"/>
</composite:implementation>
</html>

Running this on the newest Wildfly 31.0.1.Final and opening http://localhost:8080/web-application/ will result in a duplicate component ID error of "middleComponentInOuterComponent". Referencing the cc.clientId in any other way will not cause this error. Here is the Stacktrace (sorry for the german error output):

jakarta.servlet.ServletException: Komponenten-ID middleComponentInOuterComponent wurde bereits in der Ansicht gefunden.
	at jakarta.faces.impl@4.0.5//jakarta.faces.webapp.FacesServlet.executeLifecyle(FacesServlet.java:709)
	at jakarta.faces.impl@4.0.5//jakarta.faces.webapp.FacesServlet.service(FacesServlet.java:449)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
	at org.wildfly.security.elytron-web.undertow-server@4.0.0.Final//org.wildfly.elytron.web.undertow.server.ElytronRunAsHandler.lambda$handleRequest$1(ElytronRunAsHandler.java:68)
	at org.wildfly.security.elytron-base@2.2.3.Final//org.wildfly.security.auth.server.FlexibleIdentityAssociation.runAsFunctionEx(FlexibleIdentityAssociation.java:103)
	at org.wildfly.security.elytron-base@2.2.3.Final//org.wildfly.security.auth.server.Scoped.runAsFunctionEx(Scoped.java:161)
	at org.wildfly.security.elytron-base@2.2.3.Final//org.wildfly.security.auth.server.Scoped.runAs(Scoped.java:73)
	at org.wildfly.security.elytron-web.undertow-server@4.0.0.Final//org.wildfly.elytron.web.undertow.server.ElytronRunAsHandler.handleRequest(ElytronRunAsHandler.java:67)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:117)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
	at io.undertow.core@2.3.12.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.core@2.3.12.Final//io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
	at io.undertow.core@2.3.12.Final//io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
	at org.wildfly.security.elytron-web.undertow-server-servlet@4.0.0.Final//org.wildfly.elytron.web.undertow.server.servlet.CleanUpHandler.handleRequest(CleanUpHandler.java:38)
	at io.undertow.core@2.3.12.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at org.wildfly.extension.undertow@31.0.1.Final//org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:44)
	at io.undertow.core@2.3.12.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at org.wildfly.extension.undertow@31.0.1.Final//org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:51)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.SendErrorPageHandler.handleRequest(SendErrorPageHandler.java:52)
	at io.undertow.core@2.3.12.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:276)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:132)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
	at org.wildfly.extension.undertow@31.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1413)
	at org.wildfly.extension.undertow@31.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1413)
	at org.wildfly.extension.undertow@31.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1413)
	at org.wildfly.extension.undertow@31.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1413)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:256)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:101)
	at io.undertow.core@2.3.12.Final//io.undertow.server.Connectors.executeRootHandler(Connectors.java:393)
	at io.undertow.core@2.3.12.Final//io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:859)
	at org.jboss.threads@2.4.0.Final//org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
	at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1990)
	at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
	at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1348)
	at org.jboss.xnio@3.8.13.Final//org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1282)
	at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.IllegalStateException: Komponenten-ID middleComponentInOuterComponent wurde bereits in der Ansicht gefunden.
	at jakarta.faces.impl@4.0.5//com.sun.faces.util.Util.checkIdUniqueness(Util.java:1197)
	at jakarta.faces.impl@4.0.5//com.sun.faces.util.Util.checkIdUniqueness(Util.java:1186)
	at jakarta.faces.impl@4.0.5//com.sun.faces.util.Util.checkIdUniqueness(Util.java:1186)
	at jakarta.faces.impl@4.0.5//com.sun.faces.util.Util.checkIdUniqueness(Util.java:1186)
	at jakarta.faces.impl@4.0.5//com.sun.faces.application.view.FaceletPartialStateManagementStrategy.saveView(FaceletPartialStateManagementStrategy.java:434)
	at jakarta.faces.impl@4.0.5//com.sun.faces.application.view.WriteBehindStateWriter.getState(WriteBehindStateWriter.java:290)
	at jakarta.faces.impl@4.0.5//com.sun.faces.application.view.WriteBehindStateWriter.flushToWriter(WriteBehindStateWriter.java:188)
	at jakarta.faces.impl@4.0.5//com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:463)
	at jakarta.faces.impl@4.0.5//com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:163)
	at jakarta.faces.impl@4.0.5//jakarta.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:125)
	at jakarta.faces.impl@4.0.5//com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:93)
	at jakarta.faces.impl@4.0.5//com.sun.faces.lifecycle.Phase.doPhase(Phase.java:72)
	at jakarta.faces.impl@4.0.5//com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:150)
	at jakarta.faces.impl@4.0.5//jakarta.faces.webapp.FacesServlet.executeLifecyle(FacesServlet.java:692)
	... 43 more

Expected behavior

Expected behavior is the rendering of two components with the IDs contentForm:firstInstanceOfOuterComponent:middleComponentInOuterComponent:j_idt2:input and contentForm:firstInstanceOfOuterComponent:middleComponentInOuterComponent:j_idt5:input or similar chained IDs.

Environment:

  • Error validated with Wildfly Version 26.0.1.Final to 31.0.1.Final (Mojarra JSF 2.3.17.SP01 to Mojarra Jakarta Faces 4.0.5)
  • Worked with Wildfly 25.0.1.Final with Mojarra JSF 2.3.14.SP04

To modify the attached reproducer for Wildfly versions before 27 simply replace the jakarta with javax of the Faces Servlet in the web.xml.

OK, this is regression of jakartaee/faces#1567

Work around for now, use execute="@this" instead of execute="#{cc.clientId}". Removing execute attribute should also work as that should default to @this nonetheless.