myfaces-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Leonardo Uribe <lu4...@gmail.com>
Subject Re: [core] implicit object 'component' in rendered expression (myfaces and spec bug)
Date Wed, 25 May 2011 17:36:02 GMT
Hi

I have seen that. The problem is in spec javadoc, the behavior for
UIComponent.process*
and encode* is clear about the ordering.

In theory, pushComponentToEL should be called before any call to
isRendered, but after
isTransient. Look on MyFaces UIComponentBase.processRestoreState. It has this

    public void processRestoreState(FacesContext context, Object state)
    {
        if (context == null)
        {
            throw new NullPointerException("context");
        }

        Object[] stateValues = (Object[]) state;

        try
        {
            // Call
UIComponent.pushComponentToEL(javax.faces.context.FacesContext,
javax.faces.component.UIComponent)
            pushComponentToEL(context, this);

            // Call the restoreState() method of this component.
            restoreState(context, stateValues[0]);

The spec javadoc says the opposite, restoreState should be called "before"
pushComponentToEL but in practice that breaks UIComponent.EventListenerWrapper.
I reported the bug long time ago, but it wasn't fixed (I don't know why).

This case is similar. This should be fixed on the spec, but I don't
see a reason why we shouldn't commit that into myfaces code, because
after all, nobody relies on the buggy behavior.

I think we should open a new issue on the spec issue tracker:

http://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC

but fix it on myfaces code.

regards,

Leonardo Uribe

2011/5/25 Martin Koci <martin.kocicak.koci@gmail.com>:
> Hi,
>
> <h:form>
>        <h:panelGroup>
>                <h:inputText id="testId"
>                rendered="#{component.id eq 'testId'}"                
                 value="#{bean.value}" />
>        </h:panelGroup>
> </h:form>
>
> please notice the expression:
>
> rendered="#{component.id eq 'testId'}"
>
> that is clearly true.
>
> But that does not work as expected: inputText is rendered, but never
> updates model value.
>
>
> Problem 1.
>
> from specification, methods UIComponent.process* and encode*
> 1) If the rendered property of this {@link UIComponent}
> false, skip further processing
> 2) Call {@link #pushComponentToEL}
>
> -> #{component} resolves in rendered="#{}" to parent!
>
>
> Problem 2.
>
> MyFaces implement that (pointless) requirement inconsistently: from
> UIComponentBase.process*:
>
> (!isRendered())
>  return;
> pushComponentToEL(context, this)
>
> and from UIComponentBase.encodeBegin*
>  pushComponentToEL(context, this);
>  if (isRendered())
>
>
> causes that example above renderes inputText, but never updates model.
>
> Problem 3.
>
> RendererUtils.renderChild(FacesContext, UIComponent):
> in this method it is unappropriate to use following code:
>
> if (!child.isRendered()) {
>            return;
>        }
> child.encodeBegin(facesContext);
>
> because:
> 1) it does not take into account pushComponentToEL ( #{component}
> resolves to parent)
> 2) behaviour is incosistent with UIComponent.encodeBegin : you'll get
> "random" rendering - depends if parent of component renders it's
> children or not! For this case I've created MYFACES-3126, but I'll
> reopen it now, because simple remove of 'if (!child.isRendered())' does
> not solve that problem and causes another problem if component
> getRendersChildren = false;
>
>
> What do yout think about this problem?
>
>
> Regards,
>
> Kočičák
>
>
>

Mime
View raw message