78

There are lot of materials out there differentiating value attribute and binding attribute in JSF.

I'm interested in how both approaches differ from each other. Given:

public class User {
    private String name;
    private UICommand link;

    // Getters and setters omitted.
}
<h:form>
    <h:commandLink binding="#{user.link}" value="#{user.name}" />
</h:form>

It is pretty straight forward what happens when a value attribute is specified. The getter runs to return the name property value of the User bean. The value is printed to HTML output.

But I couldn't understand how binding works. How does the generated HTML maintain a binding with the link property of the User bean?

Below is the relevant part of the generated output after manual beautification and commenting (note that the id j_id_jsp_1847466274_1 was auto-generated and that there are two hidden input widgets). I'm using Sun's JSF RI, version 1.2.

<form action="/TestJSF/main.jsf" enctype="application/x-www-form-urlencoded"
    id="j_id_jsp_1847466274_1" method="post"  name="j_id_jsp_1847466274_1">
    <input name="j_id_jsp_1847466274_1" type="hidden" value="j_id_jsp_1847466274_1">
    <a href="#" onclick="...">Name</a>
    <input autocomplete="off" id="javax.faces.ViewState" name="javax.faces.ViewState"
        type="hidden" value="-908991273579182886:-7278326187282654551">
</form>

Where is the binding stored here?

BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
John
  • 9,897
  • 20
  • 63
  • 107

2 Answers2

132

How does it work?

When a JSF view (Facelets/JSP file) get built/restored, a JSF component tree will be produced. At that moment, the view build time, all binding attributes are evaluated (along with id attribtues and taghandlers like JSTL). When the JSF component needs to be created before being added to the component tree, JSF will check if the binding attribute returns a precreated component (i.e. non-null) and if so, then use it. If it's not precreated, then JSF will autocreate the component "the usual way" and invoke the setter behind binding attribute with the autocreated component instance as argument.

In effects, it binds a reference of the component instance in the component tree to a scoped variable. This information is in no way visible in the generated HTML representation of the component itself. This information is in no means relevant to the generated HTML output anyway. When the form is submitted and the view is restored, the JSF component tree is just rebuilt from scratch and all binding attributes will just be re-evaluated like described in above paragraph. After the component tree is recreated, JSF will restore the JSF view state into the component tree.

Component instances are request scoped!

Important to know and understand is that the concrete component instances are effectively request scoped. They're newly created on every request and their properties are filled with values from JSF view state during restore view phase. So, if you bind the component to a property of a backing bean, then the backing bean should absolutely not be in a broader scope than the request scope. See also JSF 2.0 specitication chapter 3.1.5:

3.1.5 Component Bindings

...

Component bindings are often used in conjunction with JavaBeans that are dynamically instantiated via the Managed Bean Creation facility (see Section 5.8.1 “VariableResolver and the Default VariableResolver”). It is strongly recommend that application developers place managed beans that are pointed at by component binding expressions in “request” scope. This is because placing it in session or application scope would require thread-safety, since UIComponent instances depends on running inside of a single thread. There are also potentially negative impacts on memory management when placing a component binding in “session” scope.

Otherwise, component instances are shared among multiple requests, possibly resulting in "duplicate component ID" errors and "weird" behaviors because validators, converters and listeners declared in the view are re-attached to the existing component instance from previous request(s). The symptoms are clear: they are executed multiple times, one time more with each request within the same scope as the component is been bound to.

And, under heavy load (i.e. when multiple different HTTP requests (threads) access and manipulate the very same component instance at the same time), you may face sooner or later an application crash with e.g. Stuck thread at UIComponent.popComponentFromEL, or Java Threads at 100% CPU utilization using richfaces UIDataAdaptorBase and its internal HashMap, or even some "strange" IndexOutOfBoundsException or ConcurrentModificationException coming straight from JSF implementation source code while JSF is busy saving or restoring the view state (i.e. the stack trace indicates saveState() or restoreState() methods and like).

Using binding on a bean property is bad practice

Regardless, using binding this way, binding a whole component instance to a bean property, even on a request scoped bean, is in JSF 2.x a rather rare use case and generally not the best practice. It indicates a design smell. You normally declare components in the view side and bind their runtime attributes like value, and perhaps others like styleClass, disabled, rendered, etc, to normal bean properties. Then, you just manipulate exactly that bean property you want instead of grabbing the whole component and calling the setter method associated with the attribute.

In cases when a component needs to be "dynamically built" based on a static model, better is to use view build time tags like JSTL, if necessary in a tag file, instead of createComponent(), new SomeComponent(), getChildren().add() and what not. See also How to refactor snippet of old JSP to some JSF equivalent?

Or, if a component needs to be "dynamically rendered" based on a dynamic model, then just use an iterator component (<ui:repeat>, <h:dataTable>, etc). See also How to dynamically add JSF components.

Composite components is a completely different story. It's completely legit to bind components inside a <cc:implementation> to the backing component (i.e. the component identified by <cc:interface componentType>. See also a.o. Split java.util.Date over two h:inputText fields representing hour and minute with f:convertDateTime and How to implement a dynamic list with a JSF 2.0 Composite Component?

Only use binding in local scope

However, sometimes you'd like to know about the state of a different component from inside a particular component, more than often in use cases related to action/value dependent validation. For that, the binding attribute can be used, but not in combination with a bean property. You can just specify an in the local EL scope unique variable name in the binding attribute like so binding="#{foo}" and the component is during render response elsewhere in the same view directly as UIComponent reference available by #{foo}. Here are several related questions where such a solution is been used in the answer:

See also:

Community
  • 1
  • 1
BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
  • I set user as request scoped bean. And tried sysout in getlink and setlink methods. When landing on the page = `User.User(), User.getLink(), User.setLink(), User.getValue()` When i click the link = `User.User(), User.setLink()...` – John Feb 20 '13 at 03:55
  • Why is setLink() called again and an another UICommand object created when it has one already? – John Feb 20 '13 at 03:58
  • "if you bind [...], then the backing bean should absolutely not be in a broader scope than the request scope". Is this still true in JSF 2.2? What's is the best option if I have to programatically include components in the page using getChildren().addAll(...)? – RinaldoDev Jun 18 '14 at 20:06
  • @Rinaldo: Use JSTL to programmatically build the view in just XML syntax. – BalusC Jun 18 '14 at 20:47
  • What if XML syntax is not an option? :P – RinaldoDev Jun 18 '14 at 21:04
  • @BalusC: You mentioned in your answer that ..When the form is submitted and the view is restored,....(POSTBACK), the JSF component tree is just (REBUILT) from scratch. I am a little confused here. Since a view is a just a tree of UI components, and in this specific case was restored from the initial GET request, it must be also be providing that specific tree structure. Why the need to rebuilt it again for the POST request. Or is the component tree rebuilt on every single request? Please elaborate. – Farhan Shirgill Ansari Apr 22 '16 at 12:31
  • @Shirgill: "view state" is not the component tree itself, but its (changed) state. I.e. all properties/attribtues which are different from defaults. When the component tree is rebuilt, the (changed) state is restored. Maybe this is helpful: http://stackoverflow.com/questions/31890433/whats-the-view-build-time (also the 1st link in 1st paragraph of the above answer) – BalusC Apr 22 '16 at 12:35
  • @BalusC: So, when they say the view state needs to be preserved(stateful) so as to process the lifecycle, it implies only saving the component state, but not the component tree. – Farhan Shirgill Ansari Apr 22 '16 at 12:37
  • 1
    @Shirgill: Indeed. `UIViewRoot` (all of `UIComponent` basically) is unserializable anyway. – BalusC Apr 22 '16 at 12:39
  • @BalusC: Component instances are request scoped. Since, the bean will be garbage-collected after the request has been served, and so will that component instance declared in the same bean. So, in which case will there be a precreated component? – Farhan Shirgill Ansari Apr 22 '16 at 12:54
  • @Shirgill: you're all responsible for it yourself. E.g. `component = new SomeComponent()` in post construct. If there isn't such one, JSF will take care of it. – BalusC Apr 22 '16 at 12:55
  • @BalusC: Didn't get your point. You mean that component instance won't be garbage collected. – Farhan Shirgill Ansari Apr 22 '16 at 12:57
  • @Shirgill: it will be GC'ed. You're all responsible for precreating one, if necessary (usually not). – BalusC Apr 22 '16 at 12:58
  • @BalusC: Got it. You second last comment after being edited was reflected when I had added a comment. Thank you very much. – Farhan Shirgill Ansari Apr 22 '16 at 13:01
  • @BalusC Is binding can be responsible of high memory consuming? We were using binding with `p:toolbarGroup` in a ViewScoped bean, and the retain heap of the bean was 15Mo! Wish I could attach an image to show you... Since, we replaced the use of toolbarGroup with another Primefaces component and no binding, it looks way much better now :) But I'm still wondering why so much memory consumed... – Rapster Dec 09 '16 at 09:07
  • @Rapster: that can happen if bean is not request scoped, as explained in answer. You're basically referencing the entire JSF component tree. – BalusC Dec 09 '16 at 09:15
  • Does it mean ViewScoped is much more memory consuming than RequestScoped? In theory, yes of course, but is it possible it could be that much (outside binding) ? – Rapster Dec 09 '16 at 09:21
  • @Rapster: view scoped beans are stored in session. It's only memory consuming if you store unnecessary data along it. That's not JSF's fault. – BalusC Dec 09 '16 at 09:28
1

each JSF component renders itself out to HTML and has complete control over what HTML it produces. There are many tricks that can be used by JSF, and exactly which of those tricks will be used depends on the JSF implementation you are using.

  • Ensure that every from input has a totaly unique name, so that when the form gets submitted back to to component tree that rendered it, it is easy to tell where each component can read its value form.
  • The JSF component can generate javascript that submitts back to the serer, the generated javascript knows where each component is bound too, because it was generated by the component.
  • For things like hlink you can include binding information in the url as query params or as part of the url itself or as matrx parameters. for examples.

    http:..../somelink?componentId=123 would allow jsf to look in the component tree to see that link 123 was clicked. or it could e htp:..../jsf;LinkId=123

The easiest way to answer this question is to create a JSF page with only one link, then examine the html output it produces. That way you will know exactly how this happens using the version of JSF that you are using.

ams
  • 52,592
  • 57
  • 169
  • 252
  • I would say that I've only used component binding when generating the component dynamically in server side, setting all the attributes like `action` and `value`, and then let the JSF framework make his job. – Luiggi Mendoza Feb 16 '13 at 17:38
  • I stored `user` as application scoped managed bean and when I click the link every time only the second number in `value="-908991273579182886:-7278326187282654551"` changes and every thing else is same. Wonder what magic these does. – John Feb 16 '13 at 17:46