eclipse-ee4j / mojarra

Mojarra, a Jakarta Faces implementation
Other
158 stars 107 forks source link

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

Closed Hurz closed 3 months ago

Hurz commented 3 months ago

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:

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

BalusC commented 3 months ago

OK, this is regression of https://github.com/jakartaee/faces/issues/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.