dev@javaserverfaces.java.net

Re: issue 1826

From: Ed Burns <ed.burns_at_sun.com>
Date: Mon, 11 Oct 2010 08:32:08 -0700

>>>>> On Mon, 11 Oct 2010 07:15:04 -0700, Ed Burns <ed.burns_at_sun.com> said:

EB> Forwarding to dev_at_javaserverfaces.
>>>>> On Sat, 9 Oct 2010 23:37:07 -0700, Sheetal Vartak <sheetal.vartak_at_oracle.com> said:

SV> Now in the case where a component is dynamically added (subscribed
SV> to PreRenderViewEvent), things work just fine. Ed, your devtest that
SV> you added for 1757 does a dynamic add. Hence you have'nt seen this
SV> exception. It can be reproduced with Richard's acid test. He is
SV> removing a component from getChildren() and adding it
SV> back. Basically trying to toggle the order of the children in a
SV> form:

SV> UIComponent component = getChildren().remove( 0 );
SV> getChildren().add( component );

SV> What's happening is that the stateObj in this case for the UIOutput
SV> component is an instance of
SV> com.sun.faces.application.view.StateHolderSaver and there is no code
SV> to handle this situation during restoreState(). There is a check to
SV> see if the stateObj is an instance of
SV> javax.faces.component.StateHolderSaver, but there is no relation
SV> between the 2 except for the fact that the classes have identical
SV> code in them. Why is javax.faces.component.StateHolderSaver not a
SV> public class and why do we have another class
SV> (com.sun.faces.application.view.StateHolderSaver) doing the same
SV> thing ?

You have hit upon a problem in the Java programming language that is
solved by Project Jigsaw. Without Jigsaw, the only way to share a class
among modules is to make it public. StateHolderSaver is an
implementation specific class, but there is no way to have one
implementation of that class be accessible in both jsf-api.jar and
jsf-impl.jar. Our solution is to have two package private classes with
the same code: com.sun.faces.application.view.StateHolderSaver and
javax.faces.component.StateHolderSaver.

I think the right thing to do is to fix issue [Mojarra-924-SingleJar]
[1]. If we did this, then code in jsf-api could access com.sun.faces
classes directly. Then, we could do away with having multiple copies of
the same code in different packages. Note that StateHolderSaver is not
the only case where we resort to this terrible hack.

SV> I see that code was introduced in
SV> StateManagementStrategyImpl.saveComponentState() as follows :

SV> if (stateContext.componentAddedDynamically(c)) {
SV> stateObj = new StateHolderSaver(ctx, c); //This is com.sun.faces.application.view.StateHolderSaver
SV> // ensure it's in the addList.
SV> Map<String, ComponentStruct> dynamicAdds = stateContext.getDynamicAdds();
SV> assert(null != dynamicAdds);
SV> String clientId = c.getClientId(ctx);
SV> if (!dynamicAdds.containsKey(clientId)) {
SV> ComponentStruct toAdd = new ComponentStruct();
SV> toAdd.absorbComponent(ctx, c);
SV> dynamicAdds.put(clientId, toAdd);
SV> }
SV> } else {... }

SV> But there is no code to restore state if the stateObj is of type
SV> com.sun.faces.application.view.StateHolderSaver.

Please correct me if I'm wrong, but it looks like that code is on line
312 of StateManagementStrategyImpl.java.

Ed

[1] https://javaserverfaces.dev.java.net/issues/show_bug.cgi?id=924

-- 
| ed.burns_at_sun.com | office: +1 407 458 0017
| homepage:               | http://ridingthecrest.com/