Bauke Scholtz created MYFACES-4776:
--------------------------------------

             Summary: Restoring a component value set to an unmodifiable List 
fails with "Could not restore StateHolder"
                 Key: MYFACES-4776
                 URL: https://issues.apache.org/jira/browse/MYFACES-4776
             Project: MyFaces Core
          Issue Type: Bug
    Affects Versions: 4.1.5
            Reporter: Bauke Scholtz


A {{List}} without a public zero-argument constructor, such as 
{{List.of(...)}}, which Java code sets as the value of a component, cannot be 
restored. The next postback fails with HTTP 500.

h3. Reproducer

{code:xml}
<h:form id="form">
    <h:dataTable id="table" var="item">
        <h:column><h:outputText value="#{item}" /></h:column>
    </h:dataTable>
    <h:commandButton id="set" value="Set" action="#{bean.setValue}" />
    <h:commandButton id="submit" value="Submit" />
</h:form>
{code}

{code:java}
@Named
@RequestScoped
public class Bean {

    public void setValue() {
        ((UIData) 
FacesContext.getCurrentInstance().getViewRoot().findComponent("form:table")).setValue(List.of("b",
 "a", "b"));
    }
}
{code}

# Click Set. The table shows the rows {{b}}, {{a}} and {{b}}.
# Click Submit.

h3. Expected

The table shows the same rows.

h3. Actual

HTTP 500:

{noformat}
java.lang.IllegalStateException: Error restoring component: form:table
    at 
org.apache.myfaces.view.facelets.PartialStateManagementStrategy.restoreStateFromMap(PartialStateManagementStrategy.java:892)
    ...
Caused by: java.lang.RuntimeException: Could not restore StateHolder of type 
java.util.ImmutableCollections$ListN (missing no-args constructor?)
    at 
jakarta.faces.component.UIComponentBase.restoreAttachedState(UIComponentBase.java:1821)
    at 
jakarta.faces.component._DeltaStateHelper.restoreState(_DeltaStateHelper.java:729)
    at 
jakarta.faces.component.UIComponentBase.restoreState(UIComponentBase.java:2064)
    at jakarta.faces.component.UIData.restoreState(UIData.java:1206)
Caused by: java.lang.InstantiationException: 
java.util.ImmutableCollections$ListN
Caused by: java.lang.NoSuchMethodException: 
java.util.ImmutableCollections$ListN.<init>()
{noformat}

Reproduced on MyFaces 4.1.5-SNAPSHOT on Tomcat 11, with server side state 
saving. With {{new ArrayList<>(List.of("b", "a", "b"))}} it works.

h3. Cause

{{UIComponentBase.saveAttachedState()}} saves every {{Collection}} other than 
an {{ArrayList}} together with its class:

{code:java}
return new _AttachedCollectionStateWrapper(attachedObject.getClass(), lst);
{code}

{{UIComponentBase.restoreAttachedState()}} then creates a new instance of that 
class:

{code:java}
restoredList = (Collection) clazz.newInstance();
{code}

That needs a public zero-argument constructor, which the unmodifiable 
collections of the JDK do not have. They cannot be filled through {{add()}} 
either.

h3. Spec

The javadoc of {{UIComponentBase.saveAttachedState()}}:

{quote}
This method supports saving attached objects of the following type: 
{{Object}}s, {{null}} values, and {{Collection}}s of these objects. If any 
contained objects are not {{Collection}}s and do not implement {{StateHolder}}, 
they must have zero-argument public constructors.
{quote}

The javadoc of {{UIComponentBase.restoreAttachedState()}}:

{quote}
This method supports restoring all attached objects types supported by 
{{saveAttachedState}}.
{quote}

A {{Collection}} is supported, and the zero-argument constructor is required 
only of the objects it contains, not of the collection itself.

h3. Proposed fix

In {{restoreAttachedState()}}, when the saved collection class has no 
accessible zero-argument constructor, fall back to a collection of the same 
kind: an {{ArrayList}} for a {{List}}, a {{LinkedHashSet}} for a {{Set}}, and 
an {{ArrayList}} otherwise.

TCK: {{Issue6125IT.testUnmodifiableValueSetWholeIsRestored}} of the Jakarta 
Faces 5.0 TCK 
([jakartaee/faces#2267|https://github.com/jakartaee/faces/pull/2267]).

🤖 Generated with Claude Opus 5.5



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to