Understanding javax.el.ValueExpression purpose - jsf

I'm trying to understand the working principles of UIInput component and EL-expressions in JSF. Here is the code fragment of UIInput component source code:
public void updateModel(FacesContext context) {
if (context == null) {
throw new NullPointerException();
}
if (!isValid() || !isLocalValueSet()) {
return;
}
ValueExpression ve = getValueExpression("value");
if (ve != null) {
Throwable caught = null;
FacesMessage message = null;
try {
ve.setValue(context.getELContext(), getLocalValue()); //1
setValue(null);
setLocalValueSet(false);
}
//catch clause
Now, I have a simple bean and the input component binded to its property:
<h:inputText value="#{myBean.hello}" />
#ManagedBean
#SessionScoped
public class MyBean{
private String hello;
//getter,setter
}
As far as I understand, the updateModel method is called by the inherited from the UIComponentBase class processUpdates(FacesContext) method which is a standard callback for the Update Model Values phase. So, after setting breakpoint at //1 and performing step next the flow's stopped at the corresponding bean property setter method.
My question is about of purpose of javax.el.ValueExpression. Is it resposible for all interatctions (incapsulates) between the component class and the bean's property in order for getting/setting values to bean's properties?

EL is like a "path" and is needed to navigate the bean. The UIInput is the MVC "view" to the MVC "model" represented by your bean. EL links the two together. It only encapsulates the traversal itself. It identifies the subject of the interaction, but the interactions are defined by the component class. Compare h:outputText to h:inputText: both basically take a value="#{some.el}" attribute; the fact that one allows the user to modify it is a fact about the component, not the path to the bean property itself.
Some components define attributes that should be populated by references to methods rather than bean properties, but again, the EL is just the traversal—invoking those methods is something the component does. And in that case you would be dealing with a MethodExpression instead of a ValueExpression.
The JSF lifecycle dictates that things happen in a certain overall order, but the component author still has ample opportunity to be creative (or wreak havoc) by doing things their own way.

Related

Is it normal behavior of JSF session-scoped validator?

Implementation: org.glassfish 2.2.12
I have the following session-scoped validator:
#ManagedBean
#SessionScoped
public class CreateGroupNameValidator extends LengthValidator implements Serializable{
#ManagedProperty(value="#{myDao}")
private MyDao myDao;
//Validate methods
}
In spite of being session-scoped and Serializable, the validator fails to restore the value of the property myDao when postback comes. I used debugger and figuredOut that the state is saved by the class StateHolderSaver which has the following consturctor:
public StateHolderSaver(FacesContext context, Object toSave) {
className = toSave.getClass().getName();
if (toSave instanceof StateHolder) {
// do not save an attached object that is marked transient.
if (!((StateHolder) toSave).isTransient()) {
Serializable [] tuple = new Serializable[StateHolderTupleIndices.LastMember.ordinal()];
tuple[StateHolderTupleIndices.StateHolderSaverInstance.ordinal()] =
(Serializable) ((StateHolder) toSave).saveState(context);
if (toSave instanceof UIComponent) {
tuple[StateHolderTupleIndices.ComponentAddedDynamically.ordinal()] = ((UIComponent)toSave).getAttributes().containsKey(DYNAMIC_COMPONENT) ? Boolean.TRUE : Boolean.FALSE;
}
savedState = tuple;
} else {
className = null;
}
} else if (toSave instanceof Serializable) {
savedState = (Serializable) toSave;
className = null;
}
}
So, since LenghtValidator implements javax.faces.component.StateHolder it didn't save my initial Dao value. Is it a normal behavior?
This is indeed specified behavior. See also a.o. Validator javadoc:
...
Validator implementations must have a zero-arguments public constructor. In addition, if the Validator class wishes to have configuration property values saved and restored with the view, the implementation must also implement StateHolder.
...
Converters and validators can be saved in JSF state so that the JSF implementation can ensure that they have after restoring the view exactly the intented property values as they were during rendering the view of the previous request (such as minimum and maximum in case of LengthValidator, might it happen that they refer a dynamic EL expression).
Although I must admit that they did during designing the JSF 1.0 specification (on which the converter/validator is still based) not really thought about the possibility to inject business service instances in a JSF converter/validator. You of course don't want to save it in the JSF view state. In case of managed properties (and thus not EJB/CDI proxies), it would only blow up the JSF view state (and thus also the HTTP session in case of server side state saving).
If you don't need your validator being JSF state aware, use composition instead of inheritance.
public class CreateGroupNameValidator {
private LengthValidator lengthValidator;
public CreateGroupNameValidator() {
lengthValidator = new LengthValidator();
}
// ...
}
Nonetheless, putting a validator in the session scope is kind of fishy. This implies that the validator's behavior is specific to the current HTTP session. I can't think of sensible real world use cases for this as they are inherently view scoped (not the validator instances but the validator properties). Usually the session scoped data (such as logged-in user) is instead injected/resolved on a thread local basis. You'd better make it request scoped if it's stateful (i.e. validator properties may vary on a per request/view basis), or application scoped if it's stateless (i.e. validator properties are the same throughout application's lifetime).

JSF Backing Component - Composite Component - Stackoverflow Exception

I want to use a backing component as a layer for accessing the attributes of my composite component (as defined in its interface).
What I wanted to achieve was reading the attributes of my componentent via my backing component class where i give back the property value of the attribute provided.
public String getName() {
if (this.name == null) {
this.name = getAttributes().get("name");
}
return this.name;
}
But when setting a new value e.g. via an input field I wanted to store the value only within my backing bean properties not updating the values of the original properties passed as attribute arguments to my composite component.
public void setName(final String name) {
this.name = name;
}
My problem now is when the getter of my backing component is called the first time or at some early stage of his life the code of the getter as shown above results in a Stackoverflow exception as getAttributes.get("name") calls the getter of my backing component (itself) instead fetching the property/attribute provided to my composite component.
Fun part is using a simple getter only returning this.name instead of calling getAttributes() I can set a breakpoint there and then calling getAttributes.get("name") (via debugger) results not in a overflow/ calling its own getter but instead the attribute provided to my composite component is returned.
I guess it has something to do with the coupling betweend the backing component and the composite component. That when the getter gets called for the first time no coupling between them is given and therefor the call of getAttributes.get("name") results in calling the getter of my backing component whereas later the call does not invoke its own getter but instead fetches the attribute provided to my comp component.
Anyone have any idea how to solve this issue?
Thnx in advance.
UIComponent#getAttributes() is a very special map. On a given key, say "foo", it first evaluates #{component.foo} as a ValueExpression which implicitly invokes UIComponent#getFoo() method. See also the javadoc. That totally explains the infinite loop. If the getFoo() method was absent, then it'd just have continued to look in the "static" map (which you can control by overriding UIComponent#getValueExpression()).
You need to solve your concrete functional requirement differently. I have actually had a hard time in wrapping my head around your concrete functional requirement, but I believe that you actually need to define separate properties with separate getters/setters, all properly delegating to the state helper:
public String getLocalName() {
return getStateHelper().eval("localName", getAttributes().get("name")); // Note: this thus defaults to #{cc.attrs.name} when not set before.
}
public void setLocalName(String localName) {
return getStateHelper().put("localName", localName);
}
and then use it in the composite implementation as
<h:inputText value="#{cc.localName}" />
instead of
<h:inputText value="#{cc.attrs.name}" />

After validation jsf fails to reset values

I have a jsf composite component implemented from two p:calendar components.
The idea is when the first calendar is selected, the value of the second calendar need to be reset. There is a problem when the validation takes place, and the reset of the second calendar is not performed.
After reading posts I decided to use EditableValueHolder in my validator.
I have custom validator: in which I added the following code:
#Override
public void validate(FacesContext fc, UIComponent uic, Object o) throws ValidatorException {
//....
resetValues(fc);
}
public void resetValues(FacesContext fc) {
PartialViewContext partialViewContext = fc.getPartialViewContext();
Collection<String> renderIds = partialViewContext.getRenderIds();
UIComponent input;
UIViewRoot viewRoot = fc.getViewRoot();
for (String renderId : renderIds) {
input = viewRoot.findComponent(renderId);
if (input.isRendered() && input instanceof EditableValueHolder) {
EditableValueHolder editableValueHolder = (EditableValueHolder) input;
editableValueHolder.setSubmittedValue(null);
editableValueHolder.setValue(null);
editableValueHolder.setValid(true);
editableValueHolder.setLocalValueSet(false);
}
}
}
After debug I can see that each code line is passed, but nothing is happening on jsf side.
This is not the right moment to reset the values. They will be overridden anyway for the current component after the validate() method leaves and also for the second calendar once it get validated. You need to perform the reset somewhere after the update model values phase, preferably before the invoke action phase, so that you've chance to change the model value in an action(listener) method. You could use an ActionListener or a PhaseListener for this.
By the way, the JSF utility library OmniFaces has a reuseable solution for this in flavor of ResetInputAjaxActionListener.

Refresh JSF validator attributes on rerender

I have an issue with the attributes values of a validator component.
Apparently the validator is created when I first visit a page.
Please see my code below:
<h:inputText value="#{qsetting.value}" rendered="#{qsetting.dataType=='Double'}">
<mw:validateRange min="#{qsetting.minValue}" max="#{qsetting.maxValue}" />
</h:inputText>
The inputText component is rerendered through ajax but apparently, including the value that is displayed.
Unfortunately, the qsetting.minValue and qsetting.maxValue are not refreshed, causing my validator to not work correctly.
Is there a possibility to refresh the validator, to make sure it re-retrieves its attributes or to just create a new instance of the validator?
The validator class itself is currently implementing "Validator, Serializable".
Also, I'm using jsf1.2 with facelets...
Thanks,
Steven
I've hit this problem in a non-ajax environment a few times over the years, and hit it again today. The addition of Ajax doesn't really change anything since a validator attribute is never evaluated again once the page is initially built, ajax or otherwise.
The only solution I've come up with is to set the validator attribute to a validator expression, then evaluate that expression inside the validate method.
One other issue I hit (also with JSF 1.2 and Facelets) is that not all EL variables worked. I had to use a static managed bean as the root of my expression to access the value. A facelet ui:param value as a root would not work. I haven't tested to see what else may not correctly evaluate. This could be due to another bug in the design of JSF itself. See http://myfaces.apache.org/core12/myfaces-api/apidocs/javax/faces/context/FacesContext.html#getELContext%28%29.
For example, instead of:
max="#{qsetting.maxValue}"
use
maxExpression="qsetting.maxValue"
Then
public String getMax(FacesContext context) {
Application app = context.getApplication();
ExpressionFactory exprFactory = app.getExpressionFactory();
ValueExpression ve = exprFactory.createValueExpression(context.getELContext(),
"#{" + getMaxExpression() + "}",
String.class);
Object result = ve.getValue(context.getELContext());
return (String)result;
}
public String getMaxExpression() {
return this.maxExpression;
}
public void setMaxExpression(String maxExpression) {
this.maxExpression = maxExpression;
}
//// StateHolder
public boolean isTransient() {
return isTransient;
}
public void setTransient(boolean newTransientValue) {
isTransient = newTransientValue;
}
public Object saveState(FacesContext context) {
Object[] state = new Object[1];
state[0] = maxExpression;
return state;
}
public void restoreState(FacesContext context, Object state) {
Object[] values = (Object[]) state;
maxExpression = (String) values[0];
}
UPDATE 2012-09-19:
After investigating how MyFaces Commons solves this problem, the better solution is to change the rules Facelets uses to evaluate validator and converter attribute expressions.
It basically comes down to adding a new validator or converter MetaRule which, when applied, checks to see if the attribute value is non-literal. If it is non-literal, call a special method on your validator or converter which passes in the value expression rather than the current value.
http://svn.apache.org/viewvc/myfaces/commons/trunk/myfaces-commons-validators/src/main/java/org/apache/myfaces/commons/validator/_ValidatorRule.java?view=markup
The validator at that point needs to store the value expression as state and evaluate it when needed. MyFaces commons provides all of the complicated infrastructure to make this happen generically, but you could dump all of that and write a simple custom rule and directly manage the ValueExpression yourself, similar to what I originally posted.

NullpointerException Binding not working JSF managed bean

I created a simple HtmlInputText
<h:inputText binding="#{IndexBean.objUIInput}" />
Then in my managed bean, it is :-
private UIInput objUIInput;
public UIInput getObjUIInput() {
objUIInput.setValue("laala");
return objUIInput;
}
public void setObjUIInput(UIInput objUIInput) {
System.out.println("Set!!");
this.objUIInput = objUIInput;
}
But i always get NullpointerException. Do i need to do anything extra on my JSF page? like we do jsp:usebean setproperty? Please help me.
Whenever you'd like to change the component's default state/behaviour prior to display, then you need to instantiate it yourself. I.e. during declaration:
private UIInput objUIInput = new HtmlInputText();
or during construction:
public Bean() {
this.objUIInput = new HtmlInputText();
}
or, as Bozho suggested, using #PostConstruct:
#PostConstruct
public void init() {
this.objUIInput = new HtmlInputText();
}
(which will take place after construction of the bean and initialization/setting of all managed properties).
And indeed, you should preferably not do any business logic in getters/setters. They are to be used to access bean properties and they can be called more than once during bean's life.
As per the comments, you can alternatively also move the UIInput#setValue() call to the setter method. JSF will call it once directly after precreating the component.
public void setObjUIInput(UIInput objUIInput) {
this.objUIInput = objUIInput;
this.objUIInput.setValue("laala");
}
When you bind a component, the getter and setter are supposed to be simple - only get/set - no logic inside them.
Perhaps the JSF lifecycle is calling the getter to check whether it needs to instantiate the component, and the getter initially would throw a NPE.
Remove all logic from your getter, or at least add a null check.
Actually, I'd advice for not using binding at all.
If you want to set an initial value to your component, use a method annotated with #PostConstruct and assign the value there, then use the value attribute.

Resources