[ 
https://issues.apache.org/jira/browse/MYFACES-3983?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14936090#comment-14936090
 ] 

Leonardo Uribe commented on MYFACES-3983:
-----------------------------------------

After some time, I have found a simple solution that will solve the problem. 
I'll attach the relevant code below (inside ComponentTagHandlerDelegate)

{code:java}

    protected UIComponent createComponent(FaceletContext ctx)
    {
        if (_componentBuilderHandlerDelegate != null)
        {
            // the call to Application.createComponent(FacesContext, Resource)
            // is delegated because we don't have here the required Resource 
instance
            return _componentBuilderHandlerDelegate.createComponent(ctx);
        }
        UIComponent c = null;
        FacesContext faces = ctx.getFacesContext();
        Application app = faces.getApplication();
        if (_delegate.getBinding() != null)
        {
            ValueExpression ve = _delegate.getBinding().getValueExpression(ctx, 
Object.class);
            if (PhaseId.RESTORE_VIEW.equals(faces.getCurrentPhaseId()))
            {
                if (!ve.isReadOnly(faces.getELContext()))
                {
                    try
                    {
                        // force reset it is an easy and cheap way to allow 
"binding" attribute to work on 
                        // view scope beans or flow scope beans (using a 
transient variable)
                        ve.setValue(faces.getELContext(), null);
                    }
                    catch (Exception e)
                    {
                        // ignore
                    }
                }
            }

{code}

I have realized that there is not a single case where a component instance 
attached to a binding attribute can be reused between views. The reason is it 
is supposed that facelet algorithm is the one responsible to trigger the 
component creation. So, when ComponentTagHandlerDelegate.createComponent(...) 
is called and this happens on restore view phase, it is a fact that:

- The component is being created.
- It should not be any UIComponent instance on the bean.

So, if these two conditions are valid and the ValueExpression instance is not 
read only, it is safe to just call ve.setValue(elContext,null) and force a 
reset over the EL expression. Then, the call to 
application.createComponent(...) will call the getter method, create the 
component instance, and if necessary call again ve.setValue(...) but it will 
pass the created component.

What will happen later is since we are on restore view phase, and partial state 
saving (PSS) algorithm is enabled the view will be restored from the state, 
filling the missing components and then when PostRestoreStateEvent is called 
and UIComponent.processEvent(...) is called, ve.setValue(...) will be called 
again, so at the end all "binding" EL expressions will be set correctly, but we 
will not have extra component instances from beans.

The call for ve.setValue(elContext,null) will be useless for request scope 
beans, but the gain will be huge, because it will be possible to use "binding" 
attribute for view scope and flow scope beans just doing something like this:

{code:java}

    private transient HtmlDataTable dataTable;

    public HtmlDataTable getDataTable() {
        return dataTable;
    }

    public void setDataTable(HtmlDataTable dataTable) {
        this.dataTable = dataTable;
    }

{code}

It will work too in cases where the component is created on the getter.

> ViewScopeBinding does not work, results in an exception when using a datatable
> ------------------------------------------------------------------------------
>
>                 Key: MYFACES-3983
>                 URL: https://issues.apache.org/jira/browse/MYFACES-3983
>             Project: MyFaces Core
>          Issue Type: Bug
>          Components: JSR-344
>    Affects Versions: 2.2.7
>            Reporter: Anup
>            Priority: Minor
>         Attachments: ViewScopeTest.war
>
>
> Install the ViewScopeTest which was created from the following stack over 
> flow posting: 
> http://stackoverflow.com/questions/2797231/why-does-postconstruct-callback-fire-every-time-even-though-bean-is-viewscoped
> Drive a request to /ViewScopeTest/ViewScopeBinding.jsf 
> and click on one of the buttons.
> The following error occurs:
>  Exception thrown by application class 
> 'javax.faces.webapp.FacesServlet.service:230' 
>   javax.servlet.ServletException: 
>  at javax.faces.webapp.FacesServlet.service(FacesServlet.java:230)
> at 
> com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1285)
> at [internal classes]
>  
> Caused by: java.lang.NullPointerException: 
>  at 
> org.apache.myfaces.view.facelets.compiler.CheckDuplicateIdFaceletUtils.createAndQueueException(CheckDuplicateIdFaceletUtils.java:139)
> ... 1 more
> This works fine on server with Mojarra 



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to