Consider a custom UIComponent (for test purposes only):
public class UITest extends UIComponentBase {
@Override
public void encodeBegin(FacesContext context) throws IOException {
System.out.println("encodeBegin");
}
@Override
public void encodeAll(FacesContext context) throws IOException {
System.out.println("encodeAll");
}
}
When I add it to page inside a composite component, the encodeBegin()
method gets called. However, when add it to page outside a composite component, the encodeAll()
method gets called instead.
Adding it inside other UIComponents makes no difference, only composite component wrapper seems to change the behavior.
Couldn't find info why it is so? A link to the spec?
The spec is really messy in this case, stating that: "These methods are called during the Render Response phase of the request processing lifecycle. encodeAll() will cause this component and all its children and facets that return true from isRendered() to be rendered, regardless of the value of the getRendersChildren() return value. encodeBegin(), encodeChildren(), and encodeEnd()have the responsibility of creating the response data for the beginning of this component, this component’s children (only called if the rendersChildren property of this component is true), and the ending of this component, respectively."
However, this seems to be a mixture of new and old features, where the new functionality (encodeAll) seems to be incomplete in some ways:
I tried the following:
A) Calling the component directly in the page (no wrapper)
extend UIComponentBase (or other UIComponent class such as UIInput, UIOutput.. etc), declare it as a tag, and use it in the UI. In this case the encodeAll method is called IF it is present (overridden), if not the encodeBegin and encodeEnd methods will be called!!
Another thing to note is that you can create a custom Renderer for the component, so you can separate rendering logic from behaviour. (by creating another class that extends Renderer, and annotating it with @FacesRenderer) This is where it gets interesting; Renderer defines only encodeBegin, encodeChildren and encodeEnd (with no mention of encodeAll). Now the logic seems to go roughly like this: if (encodeAll is present) encodeAll is called (and the renderer is ignored!) else if(any of encodeBegin,Children,or end exist in the class that extends UIComponent) call the method that was found in that component else if(encodeBegin, children or end exist in the class that extends Renderer) call the corresponding method that was found.
So this means that implementing encodeAll (or encodeBegin.. etc ) in the class extending UIComponent causes the renderer to be ignored!
B) Wrapping the component (cc:implementation.. etc)
In this case the same thing happened as above, except that encodeAll was not called in any case, no matter what I did.
Conclusion: It seems that encodeAll is some kind of new functionality (or shortcut) to implement the rendering code, and it seems that cc:implementation has a bug in this case (it doesn't look for encodeAll).
I hope this is at least of some value to you, unfortunately I cannot provide a more thorough answer. :( It also seems that nobody else knows about this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With