[
https://issues.jboss.org/browse/JBSEAM-4919?page=com.atlassian.jira.plugi...
]
Brian Leathem commented on JBSEAM-4919:
---------------------------------------
Setting a breakpoint at the code where the exception occurs:
{code:title="AttachedObjectListHolder#Line 162"}
} else {
// assume 1:1 relation between existing attachedObjects and state
for (int i = 0, len = attachedObjects.length; i < len; i++) {
T l = this.attachedObjects.get(i);
if (l instanceof StateHolder) {
((StateHolder) l).restoreState(context, attachedObjects[i]);
}
}
}
{code}
which is in the _restoreState_ method of the _AttachedObjectListHolder_ and is invoked by
the _restoreState_ method of the _UIInput_ component.
The problem comes about, as we are violating the assumption noted in the comment of the
above code. Namely _attachedObjects_ is of length 2, and _this.attachedObjects_ is of
length 1. To understand why, it is important to realize the _attachedObjects_ is the
stored state of the _UIInput_ component, and refers to two validators (_BeanValildator_
and _EqualityValidator_) where as _this.attachedObjects_ refers to the list of validators
currently attached to the _UIInput_ component (and consists of only a _BeanValildator_).
This discrepancy arises because the _EqualityValidator_ is added to the _UIInput_ list of
validators in the encode method of _EqualityValidatorRendererBase_, whereas the
_restoreState_ method is called much earlier in the lifecycle than the encode method.
The curious part here is why it works on the first submit. The answer is that we follow a
different path through the _AttachedObjectListHolder_ _saveState_ method on initial page
request, vs. the first page submit - based on the value of the _AttachedObjectListHolder_
_initialState_ property. See the code below:
{code:title="AttachedObjectListHolder#Line 110"}
if (initialState) {
Object[] attachedObjects = new Object[this.attachedObjects.size()];
boolean stateWritten = false;
for (int i = 0, len = attachedObjects.length; i < len; i++) {
T attachedObject = this.attachedObjects.get(i);
if (attachedObject instanceof StateHolder) {
StateHolder sh = (StateHolder) attachedObject;
if (!sh.isTransient()) {
attachedObjects[i] = sh.saveState(context);
}
if (attachedObjects[i] != null) {
stateWritten = true;
}
}
}
return ((stateWritten) ? attachedObjects : null);
} else {
Object[] attachedObjects = new Object[this.attachedObjects.size()];
for (int i = 0, len = attachedObjects.length; i < len; i++) {
attachedObjects[i] = UIComponentBase.saveAttachedState(context,
this.attachedObjects.get(i));
}
return (attachedObjects);
}
{code}
During the initial request, _initialState_ is _false_, and the validator state is saved by
delegating to the _UIComponentBase.saveAttachedState_ method using _StateHolderSaver_
objects. After the first request, the _initialState_ is true, and we invoke the saveState
method on the _EqualityValidator_ directly. This then affects the path we take through
the _restoreState_ method, where the error is ultimately thrown:
{code:title="AttachedObjectListHolder#Line 148"}
if (attachedObjects.length > 0 && attachedObjects[0] instanceof
StateHolderSaver) {
// overwrite the existing attachedObjects with those included
// in the full state.
if (this.attachedObjects != null) {
this.attachedObjects.clear();
} else {
this.attachedObjects = new ArrayList<T>(2);
}
for (int i = 0, len = attachedObjects.length; i < len; i++) {
T restored = (T) ((StateHolderSaver) attachedObjects[i]).restore(context);
if (restored != null) {
this.attachedObjects.add(restored);
}
}
} else {
// assume 1:1 relation between existing attachedObjects and state
for (int i = 0, len = attachedObjects.length; i < len; i++) {
T l = this.attachedObjects.get(i);
if (l instanceof StateHolder) {
((StateHolder) l).restoreState(context, attachedObjects[i]);
}
}
}
{code}
In the first pass through the _restoreState_ method, where our state is stored in
_StateHolderSaver_ objects by the _UIComponentBase_ delegation, we "overwrite the
existing attachedObjects with those included in the full state" (from the embedded
comment). Whereas the 2nd time through, the validator saved its state itself and we go
through the 2nd path, where the exception is thrown - since we haven't yet registered
the _EqualityValidator_ with the _UIInput_ component.
Having discovered this, I thought I could work around the problem by having the
_EqualityValidator_ save/restore state methods also delegate to _UIComponentBase_ for
state saving, as in:
{code:title="Attempt at delegating state saving to UIComponentBase"}
public void restoreState(FacesContext context, Object stateHolder) {
if (stateHolder != null) {
Object state = UIComponentBase.restoreAttachedState(context, stateHolder);
Object[] fields = (Object[]) state;
forId = (String) fields[0];
message = (String) fields[1];
messageId = (String) fields[2];
operator = ValidOperation.valueOf((String) fields[3]);
}
}
public Object saveState(FacesContext context) {
Object[] state = new Object[4];
state[0] = forId;
state[1] = message;
state[2] = messageId;
state[3] = operator.toString();
Object stateHolder = UIComponentBase.saveAttachedState(context, state);
return stateHolder;
}
{code}
But this did not resolve the problem, as the _BeanValidator_ is in the 0th position of the
list, and since it does not perform a similar delegation in it's save/restore state
methods, we still follow the same paths through the above code.
*TL;DR:*
A proper fix to this issue will involve finding a different means of registering the
_EqualityValidator_ with the _UIInput_ component. This should be done at the time the
component tree is built, rather than we the component tree is encoded.
seam-ui example java.lang.IndexOutOfBoundsException in restoreState
-------------------------------------------------------------------
Key: JBSEAM-4919
URL:
https://issues.jboss.org/browse/JBSEAM-4919
Project: Seam 2
Issue Type: Bug
Components: Core
Affects Versions: 2.3.0.BETA1
Environment: AS 7.1.0.Final, AS 7.1.1.Final
Reporter: Marek Schmidt
Assignee: Marek Novotny
Priority: Blocker
Labels: jsf2, jsf21, ui
Fix For: 2.3.0.BETA2
In the seam-ui example, a debug page is shown
{noformat}
Exception during request processing:
Caused by javax.servlet.ServletException with message: "Index: 1, Size: 1"
javax.faces.webapp.FacesServlet.service(FacesServlet.java:606)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248)
org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83)
org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:60)
org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
org.jboss.seam.web.IdentityFilter.doFilter(IdentityFilter.java:40)
org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:90)
org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64)
org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45)
org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
org.jboss.seam.web.HotDeployFilter.doFilter(HotDeployFilter.java:53)
org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248)
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275)
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50)
org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153)
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877)
org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671)
org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930)
java.lang.Thread.run(Thread.java:662)
Caused by java.lang.IndexOutOfBoundsException with message: "Index: 1, Size:
1"
java.util.ArrayList.RangeCheck(ArrayList.java:547)
java.util.ArrayList.get(ArrayList.java:322)
javax.faces.component.AttachedObjectListHolder.restoreState(AttachedObjectListHolder.java:165)
javax.faces.component.UIInput.restoreState(UIInput.java:1411)
com.sun.faces.application.view.StateManagementStrategyImpl$2.visit(StateManagementStrategyImpl.java:264)
com.sun.faces.component.visit.FullVisitContext.invokeVisitCallback(FullVisitContext.java:151)
javax.faces.component.UIComponent.visitTree(UIComponent.java:1612)
javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
javax.faces.component.UIForm.visitTree(UIForm.java:371)
javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
com.sun.faces.application.view.StateManagementStrategyImpl.restoreView(StateManagementStrategyImpl.java:251)
com.sun.faces.application.StateManagerImpl.restoreView(StateManagerImpl.java:188)
org.jboss.seam.jsf.SeamStateManager.restoreView(SeamStateManager.java:76)
com.sun.faces.application.view.ViewHandlingStrategy.restoreView(ViewHandlingStrategy.java:123)
com.sun.faces.application.view.FaceletViewHandlingStrategy.restoreView(FaceletViewHandlingStrategy.java:453)
com.sun.faces.application.view.MultiViewHandler.restoreView(MultiViewHandler.java:142)
org.jboss.seam.jsf.SeamViewHandler.restoreView(SeamViewHandler.java:94)
com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:192)
com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:116)
com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248)
org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83)
org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:60)
org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
org.jboss.seam.web.IdentityFilter.doFilter(IdentityFilter.java:40)
org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:90)
org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64)
org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45)
org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
org.jboss.seam.web.HotDeployFilter.doFilter(HotDeployFilter.java:53)
org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248)
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275)
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50)
org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153)
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877)
org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671)
org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930)
java.lang.Thread.run(Thread.java:662)
{noformat}
--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators:
https://issues.jboss.org/secure/ContactAdministrators!default.jspa
For more information on JIRA, see:
http://www.atlassian.com/software/jira