Value and Method Bindings in XPages

Jul 21, 2014, 5:45 PM

Tags: xpages

When you use any binding in XPages - anything with "#{...}" or "${...}", regardless of whether it's EL, SSJS, or other - you're creating what is called in JSF-land either a ValueBinding or a MethodBinding, and the distinction is important but can be subtle, particularly when dealing with SSJS.

Value Bindings

The simplest case of value bindings are sprinkled throughout even the most basic XPage app, created when you bind a control to a document's field:

<xp:inputText value="#{doc.Title}"/>

The meaning is clear: "this text box connects to the 'Title' property of the 'doc' object". Though simple in concept and syntax, there's a lot of cleverness built into this, both in how many types of objects it can deal with to figure out what "Title" means and also in that it supports both read and write operations with the same syntax. This ability applies to your own Java beans as well. In the absence of any supported interface, EL will map something like #{} to both bean.getFoo() and bean.setFoo(...) as appropriate.

The same does not apply to SSJS, however. You may have tried something like this once, only to find your text box became read-only:

<xp:inputText value="#{javascript:doc.getItemValueString('Title')}"/>

The reason for this is that, though you are still creating a value binding, SSJS is only capable of producing read-only bindings. This is because the XPage has no idea that the code inside the brackets is getting the value of a Notes document item; anything in between #{javascript: and } may as well be static as far as the page is concerned. It knows that the code can produce a value, but that's it. Custom binding languages like this CAN allow value writing - the little-used XPath binding does - but SSJS does not, for good reason.

Method Bindings

So that's a value binding - what about method bindings? Well, you're writing these all the time, too. Here's an example of one:


Method bindings written in SSJS are effectively the same as SSJS value bindings: they just execute the code contained in them and optionally return a value (for example, in button actions).

EL is also capable of creating method bindings, but it behaves slightly differently than it does with value bindings. Take the same binding as before, #{}, except now it's attached to the action property of an event handler instead of the value property of a text box. In this context, it is a method binding, and EL no longer cares about supported interfaces or bean conventions. Instead of converting the call into getValue(...) on a DataObject or getFoo()/setFoo(...) on a normal object, EL looks for a method named foo() explicitly. There's no translation and there's no "read mode" or "write mode".

You can see this at play in the stub home page in XPages Scaffolding. The beforePageLoad and afterPageLoad events are method bindings, and so they are bound to methods on the controller with the exact names specified.

There's is a weird gotcha, but it's rare: some method bindings pass parameters along. If you look at the additional event methods on the basic controller class, you see that they expect a PhaseEvent object to be passed in. If you write these same methods in SSJS, you don't have to care about that - in this case, it appears that the page just throws the argument away. However, if you bind an event with arguments to a method without, you'll get an exception like java.lang.IllegalArgumentException: wrong number of arguments. And unfortunately, even adding the parameter doesn't solve it on its own... you have to manually bind the event for some reason. The good news is that those are the only cases I know of where that happens - everything else expects an argument-less method.

When you're writing in primarily SSJS, the distinction between the two only matters for write-mode value bindings, but the more you deal with Java in XPages, the more it pays to know a little about how the XPages framework perceives the binding types.

New Comment