Starting
with OmniFaces 2.0, we have an out of the box implementation of a read only
value expression that can be used when the value is not yet available at
construction time, or when the value would be too expensive to create and it's
not yet clear if the expression will actually be evaluated. This is an
extension of ValueExpression
and it is named ReadOnlyValueExpression.
If you need
a ValueExpression
that respects the above description then you should know that the OmniFaces implementation
can be used by instantiating ReadOnlyValueExpression class by using one of
the below three constructors. Notice that the value of this ValueExpression
is an OmniFaces Callback,
which means that when the expression is evaluated, the callback method, invoke(),
is called, as being the value of this ValueExpression. Now, the invoke()
method can return an object that was
"computed" in the meanwhile. Actually, the returned object is the "real" value of
the ValueExpression,
that wasn't available when this ValueExpression was created. So, the
"real" value MUST be calculated somewhere between the creation of the
ValueExpression
and the evaluation of it, which lead the flow in the invoke() method.
·
create a ReadOnlyValueExpression via
a callback which returns a value (the object
is the "real" needed value of this ValueExpression)
ReadOnlyValueExpression
readOnlyValueExpression = new
ReadOnlyValueExpression(type_of_object, new
Returning<Object>() {
@Override
public Object invoke() {
return object;
}
});
·
create a ReadOnlyValueExpression via
a callback which takes one argument and returns one value (the object is the "real"
needed value of this ValueExpression)
ReadOnlyValueExpression
readOnlyValueExpression = new
ReadOnlyValueExpression(type_of_object, new
ReturningWithArgument<Object,ELContext>()
{
@Override
public Object invoke(ELContext elc) {
return object;
}
});
Now depends
on you where you put this ValueExpression. Per example, based on OmniFaces 2.0 - Write a custom component that receive the FaceletContext for the Facelet in which it is declared, you
can place it in the "facelet scope", like this:
...
@Override
public void
setFaceletContext(FaceletContext faceletContext) {
ReadOnlyValueExpression
readOnlyValueExpression = new
ReadOnlyValueExpression(type_of_object, new
Returning<Object>() {
@Override
public
Object invoke() {
return object;
}
});
faceletContext.getVariableMapper().setVariable(variable_name, readOnlyValueExpression);
}
...
Now, before the #{variable_name...} is evaluated (which will call the invoke() method), you need to ensure that the object is created!
You can see
a complete use of ReadOnlyValueExpression in the OmniFaces 2.0 component, named
ResolveComponent.
In that case, OmniFaces puts in "facelet scope" a substitute for an UIComponent
that doesn't exist yet. This substitute is an ReadOnlyValueExpression
based on the Callback.Returning.
Meanwhile, the component is found in the component tree, and when the invoke()
method is called (the ValueExpression is evaluated), that UIComponent
is returned.
Read further about the OmniFaces 2.1 improvments for this artifact.
Do not
forget that this is a read only ValueExpression,
so do not try to set its value. Notice the implementation in the figure below:
Read further about the OmniFaces 2.1 improvments for this artifact.
Niciun comentariu :
Trimiteți un comentariu