javaee / mojarra

PLEASE NOTE: This project has moved to Eclipse Foundation and will be archived under the JavaEE GitHub Organization. After Feb. 1, 2021, the new location will be github.com/javaee/mojarra. Mojarra - Oracle's implementation of the JavaServer Faces specification
https://github.com/eclipse-ee4j/mojarra
Other
164 stars 58 forks source link

Problems with c:if and composite components #3512

Closed javaserverfaces closed 9 years ago

javaserverfaces commented 10 years ago

When our servers were updated from JSF Mojarra 2.1.19 to 2.1.28, we started noticing crashes in many pages of our web application. We had to rollback the update and stay with 2.1.19.

A real example of the case is a webpage where we have dynamic collapsibles, each of which contains dynamic tabsets, each of which contains dynamic fields of different kinds with search boxes, calendars, ajax events, all of this managed by a data dictionary which defines form groups, forms, and fields. We use a lot of c:forEach, c:if, composite components, and facelets includes.

Thankfully, after some efforts, I managed to narrow down the case make it as simple as I could.

If you create a small web application with the code bellow, and run it, you click on the "Tab 1" link, the application switches to tab 1, then you click on "Tab 0" to return to tab 0, then there is an exception.

Please note that if I remove the f:ajax onchange events on both String FIelds, it works without crashing. Also, if I replace the String field composite components with normal h:InputText components, it also works without crashing (with the f:ajax events).

Here is a list of the Mojarra versions on which I tested the case : 2.1.19 = ok 2.1.21 = ok 2.1.22 = crash 2.1.23 = crash 2.1.24 = crash 2.1.25 = crash 2.1.26 = crash 2.1.27 = crash 2.1.28 = crash 2.1.29 = crash

Here is the stack trace : SEVERE [javax.enterprise.resource.webcontainer.jsf.context] java.lang.IndexOutOfBoundsException: Index: 1, Size: 1 at java.util.ArrayList.rangeCheck(Unknown Source) at java.util.ArrayList.get(Unknown Source) at javax.faces.component.UIComponentBase.restoreBehaviors(UIComponentBase.java:2177) at javax.faces.component.UIComponentBase.restoreBehaviorsState(UIComponentBase.java:2153) at javax.faces.component.UIComponentBase.restoreState(UIComponentBase.java:1573) at javax.faces.component.UIOutput.restoreState(UIOutput.java:272) at javax.faces.component.UIInput.restoreState(UIInput.java:1411) at com.sun.faces.application.view.FaceletPartialStateManagementStrategy$2.visit(FaceletPartialStateManagementStrategy.java:380) at com.sun.faces.component.visit.FullVisitContext.invokeVisitCallback(FullVisitContext.java:151) at javax.faces.component.UIComponent.visitTree(UIComponent.java:1652) at javax.faces.component.UIComponent.visitTree(UIComponent.java:1663) at javax.faces.component.UIComponent.visitTree(UIComponent.java:1663) at javax.faces.component.UINamingContainer.visitTree(UINamingContainer.java:174) at javax.faces.component.UIComponent.visitTree(UIComponent.java:1663) at javax.faces.component.UIComponent.visitTree(UIComponent.java:1663) at javax.faces.component.UIForm.visitTree(UIForm.java:371) at javax.faces.component.UIComponent.visitTree(UIComponent.java:1663) at javax.faces.component.UIComponent.visitTree(UIComponent.java:1663) at com.sun.faces.application.view.FaceletPartialStateManagementStrategy.restoreView(FaceletPartialStateManagementStrategy.java:367) at com.sun.faces.application.StateManagerImpl.restoreView(StateManagerImpl.java:138) at com.sun.faces.application.view.ViewHandlingStrategy.restoreView(ViewHandlingStrategy.java:123) at com.sun.faces.application.view.FaceletViewHandlingStrategy.restoreView(FaceletViewHandlingStrategy.java:577) at com.sun.faces.application.view.MultiViewHandler.restoreView(MultiViewHandler.java:142) at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:192) at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:116) at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118) at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:295) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230) at org.apache.catalina.core.StandardContextValve.__invoke(StandardContextValve.java:149) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java) at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:169) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:145) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:97) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:102) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:336) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:856) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:653) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:920) at java.lang.Thread.run(Unknown Source)


The view (Test.xhtml):

<?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:fields="http://java.sun.com/jsf/composite/fields">

Tab 0 : Tab 1 : ------------------------------------------------------- The backing bean (com.test.TestBean.java) ------------------------------------------------------- package com.test; import javax.faces.bean.ManagedBean; import javax.faces.bean.ViewScoped; import javax.faces.event.AjaxBehaviorEvent; @ManagedBean(name = "TestBean") @ViewScoped public class TestBean { private Boolean tab0Expanded = true; private Boolean tab1Expanded = false; private String field0 = "Tab 0 value"; private String field1 = "Tab 1 value"; public void tab0Click(AjaxBehaviorEvent event) { tab0Expanded = true; tab1Expanded = false; } public void tab1Click(AjaxBehaviorEvent event) { tab1Expanded = true; tab0Expanded = false; } public String getField0() { return field0; } public void setField0(String field0) { this.field0 = field0; } public String getField1() { return field1; } public void setField1(String field1) { this.field1 = field1; } public Boolean getTab0Expanded() { return tab0Expanded; } public Boolean getTab1Expanded() { return tab1Expanded; } } ------------------------------------------ The composite component (resources/fields/StringField.xhtml) ------------------------------------------ -------------------- faces-config.xml -------------------- ---------- web.xml ---------- Faces Servlet javax.faces.webapp.FacesServlet 1 Faces Servlet *.xhtml I really hope you can help us with that, thanks in advance. #### Environment Redhat Enterprise Linux 6.6 JBoss EAP 6.3.1 Mojarra 2.1.22 to 2.1.29 #### Affected Versions [2.1.22, 2.1.29]
javaserverfaces commented 10 years ago

Reported by yylabelle01

javaserverfaces commented 10 years ago

@manfredriem said: Can you please send the entire reproducer to issues@javaserverfaces.java.net? Thanks!

javaserverfaces commented 10 years ago

yylabelle01 said: Web application war file sent to issues@javaserverfaces.java.net.

javaserverfaces commented 10 years ago

@manfredriem said: Attached reproducer. Thank you!

javaserverfaces commented 9 years ago

-michael- said: @yylabelle01: As a workaround you can fix your example by using '#

{cc.id}

_input' as ID of your inputText in StringField.xhtml instead of just 'input'. Maybe that can also be applied in your more complex real life scenario.

javaserverfaces commented 9 years ago

yylabelle01 said: Hi Michael, your workaround works fine, even with our real life case, thanks for the information.

This modification has allowed us to make progress in our tests, we are now encountering many "duplicate ID" strange errors in our more complex views, when switching tabs in a tabset for example. We have been able to fix many of these cases by using c:if instead of the rendered attribute, and some of them by replacing composite components by basic <h: elements.

I don't know if those issues are related to this case or not or if it's worth investigating.

Thanks.

javaserverfaces commented 9 years ago

@manfredriem said: Please use f:subview as a wrapper around your c:if sections as c:if itself is not a naming container, so if you use it without establishing a naming context you will see the behavior you experience.

Note that according to the JSF specification a component needs to have a unique id, but c:if by itself cannot guarantee that so you have to make sure it does so by putting it in a naming container.

I realize that this is inconvenient because you are upgrading an existing application that worked before, but unfortunately it relied on incorrect behavior.

Thanks!

javaserverfaces commented 9 years ago

-michael- said: Hey yylabelle01,

I consider the duplicate ID issue also as an bug and opened a ticket:

3549 returns wrong components when using dynamic includes") (previously #3547 returns wrong components when using dynamic includes")).

In that example you don't see duplicate ID error, but the mix up of components in the tree. The duplicate IDs are caused by mixed up UniqueIdVendor components that are generating non unique ids. But that symptom is harder to reproduce in a simple example.

Brgds Michael

javaserverfaces commented 9 years ago

yylabelle01 said: We will implement those changes in our next development cycle.

Thank your guys for your help.

javaserverfaces commented 10 years ago

File: testJsf2.war Attached By: @manfredriem

javaserverfaces commented 7 years ago

This issue was imported from java.net JIRA JAVASERVERFACES-3508

javaserverfaces commented 9 years ago

Marked as works as designed on Tuesday, November 25th 2014, 9:28:12 am