You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@myfaces.apache.org by "Michael Dietrich (Created) (JIRA)" <de...@myfaces.apache.org> on 2011/11/08 08:38:51 UTC

[jira] [Created] (MYFACES-3389) Duplicate Id error when model of forEach is changed

Duplicate Id error when model of forEach is changed
---------------------------------------------------

                 Key: MYFACES-3389
                 URL: https://issues.apache.org/jira/browse/MYFACES-3389
             Project: MyFaces Core
          Issue Type: Bug
    Affects Versions: 2.1.2
            Reporter: Michael Dietrich


We have a use case, where the model (i.e. items) of a forEach is changed in the Invoke Application phase, in a way that rows are added or deleted in the middle of the model. 
During the buildView(...) in the Render Response phase, the forEach Tag Handler recognizes, that the model has changed, and for example that now one more row is available, but it does not recognize, that this row was not added as last row. So the forEach Tag Handler logic starts to create additional components for the additional row, but it creates these components for entries at the end of the model. The issue is, that there already exist components for the last row in the UIViewRoot and these componts already have the same Ids than the newly created ones. Thus we end up with a Duplicate Id Exception

The attached file might help you, to recreate the issue with a simple example.

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators: https://issues.apache.org/jira/secure/ContactAdministrators!default.jspa
For more information on JIRA, see: http://www.atlassian.com/software/jira

        

[jira] [Commented] (MYFACES-3389) Duplicate Id error when model of forEach is changed

Posted by "Leonardo Uribe (Commented) (JIRA)" <de...@myfaces.apache.org>.
    [ https://issues.apache.org/jira/browse/MYFACES-3389?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13146687#comment-13146687 ] 

Leonardo Uribe commented on MYFACES-3389:
-----------------------------------------

Unfortunately by its original design, c:forEach does not allow that type of
manipulation, and there is no way we can fix it without change how it works.

c:forEach is a "build view time" tag. In other words, is a tag that when
is processed (the view is created or refreshed), it changes the view
adding or removing components. But to work in a reliable way, this tag 
requires the values that iterate be stable, or in other words, they should
not change over the lifetime of the page. If they change, things like the
state get lost or mixed could happen.

In this case, facelets has another internal id used to check if two components
are the same. In myfaces is stored under the key:

org.apache.myfaces.view.facelets.MARK_ID 

So, when the model is changed making disappear and appear the second row, this
internal id gets "confused". It is something hard to explain, but in few words
the generated ids looks like this:

j_id83974898_48897493
j_id83974898_48897493_1
j_id83974898_48897493_2

when is removed the second row

j_id83974898_48897493
j_id83974898_48897493_1

but it should be:

j_id83974898_48897493
j_id83974898_48897493_2

So, on the next request, j_id83974898_48897493_1, but the state has is as
j_id83974898_48897493_2, and finally the state get lost. So, with or without
PSS c:forEach will not going to work correctly if the rule about the stability
of the model is not preserved. 

I tried to set this param:

  <context-param>
    <param-name>org.apache.myfaces.REFRESH_TRANSIENT_BUILD_ON_PSS_PRESERVE_STATE</param-name>
    <param-value>true</param-value>
  </context-param>

And the example works. Partial state saving (PSS) algorithm impose some rules 
over the view that must be preserved. See MYFACES-3329 for details. In 
c:forEach case, "it is not possible" to save the iteration values to use it later
on restore view phase and preserve PSS conditions by backward compatibility
with previous use cases (enforce iteration values to be Serializable). Note
I say "it is not possible", but I'm not really sure, because c:forEach in 
facelets is not a 1:1 copy of jsp c:forEach.

I tried this too:

  <c:forEach items="#{forEachBean.elementList}" var="uipropgroupelem" varStatus="el">
    <f:subview>
      <h:inputText id="iT_#{uipropgroupelem.elementName}" value="#{uipropgroupelem.elementValue}" /><br />
    </f:subview>
  </c:forEach>

Apparently it works, but looking on the generated ids, you can see how the
second and the third row gets mixed. 

Is there any other alternative? Look t:dataList

<t:dataList value="#{itemsBean.items}" var="item" rowStatePreserved="true">

It has a property called "rowKey" with this description:

"... Used to assign a value expression that identify in a unique way a row. 
This value will be used later instead of rowIndex as a key to be appended 
to the container client id using getDerivedSubClientId() method. ..."

It few words it allow to have components with full state per row and bind in
some way the component state with the model, so an addition/removal will
be handled correctly. But this will only works with PSS enabled and if
the component is not added dynamically to the tree using 
<ui:include src="#{...}"/>, because it relies on markInitialState() call to
setup the initial state of the row. See this link for more information:

http://lu4242.blogspot.com/2011/06/jsf-component-state-per-row-for.html

Thinking more about it, I think it is possible to use PostAddToViewEvent
to setup that "initial state", in case markInitialState() cannot do it.

Considering all previous argument, my opinion is we should close this issue
as invalid.

                
> Duplicate Id error when model of forEach is changed
> ---------------------------------------------------
>
>                 Key: MYFACES-3389
>                 URL: https://issues.apache.org/jira/browse/MYFACES-3389
>             Project: MyFaces Core
>          Issue Type: Bug
>    Affects Versions: 2.1.2
>            Reporter: Michael Dietrich
>         Attachments: MyFaces212ForEachTest.war
>
>
> We have a use case, where the model (i.e. items) of a forEach is changed in the Invoke Application phase, in a way that rows are added or deleted in the middle of the model. 
> During the buildView(...) in the Render Response phase, the forEach Tag Handler recognizes, that the model has changed, and for example that now one more row is available, but it does not recognize, that this row was not added as last row. So the forEach Tag Handler logic starts to create additional components for the additional row, but it creates these components for entries at the end of the model. The issue is, that there already exist components for the last row in the UIViewRoot and these componts already have the same Ids than the newly created ones. Thus we end up with a Duplicate Id Exception
> The attached file might help you, to recreate the issue with a simple example.

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators: https://issues.apache.org/jira/secure/ContactAdministrators!default.jspa
For more information on JIRA, see: http://www.atlassian.com/software/jira