Hi.
Because of lack of examples a lot of people got into the same issue: they add attribute to UIComponent with some EL expression but in the Validator they couldn't get the value by callng component.getAttributes().get("attributeName"). Last one always returned null. But for some reason if the add attribute with plain text value it worked fine.
Today I decided to digg into it and after re-reading specification for
JSF 1.2 I got the answer: there are 2 places for attribute values! Here is the quote of the description for section "9.4.2 <f:attribute> (page 9-17)":
"If the associated component already has a component attribute with that name, take no action.
Otherwise, call the isLiteralText() method on the argument value. If it returns
true, store the value in the component�s attribute Map under the name derived above.
If it returns false, store the ValueExpression in the component�s ValueExpression
Map under the name derived above."
In other words we looked for value in wrong place. If value of f:attribute is EL expression we should use component.getValueExpression("attributeName") to get ValueExpression instance and call getValue(elContext) to get theValue.
Here is 2 examples.
Example 1. Value of attribute is plain text.
Page code:
<h:inputText id="userName" value="#{mybean.userName}">
<f:attribute name="payCode" value="regular"/>
<f:validator id="userNameValidator"/>
</h:inputText>
...
faces-context.xml
<validator>
<validator-id>userNameValidator</validator-id>
<validator-class>your.package.UserNameValidator</validator-class>
</validator>
...
Validator code
public class UserNameValidator implements Validator {
public void validate(FacesContext context, UIComponent component, Object value) {
String paycode = component.getAttributes().get("payCode");
...
}
Example 2. Value of attribute is EL (expression language).
Page code:
<h:inputText id="userName" value="#{mybean.userName}">
<f:attribute name="payCode" value="#{otherBean.payCode}"/>
<f:validator id="userNameValidator"/>
</h:inputText>
...
faces-context.xml
<validator>
<validator-id>userNameValidator</validator-id>
<validator-class>your.package.UserNameValidator</validator-class>
</validator>
...
<managed-bean>
<description>Some other bean we get value from. Scope "request" just for example. It could be session or application too or even no scope</description>
<managed-bean-name>otherBean</managed-bean-name>
<managed-bean-class>your.package.OtherBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
OtherBean code:
public class OtherBean {
private PayCode payCode;
...
public PayCode getPayCode() {
return this.payCode;
}
public void setPayCode(PayCode payCode) {
this.payCode = payCode;
}
}
...
Validator code
public class UserNameValidator implements Validator {
public void validate(FacesContext context, UIComponent component, Object value) {
ValueExpression ve = component.getValueExpression().get("payCode");
PayCode paycode = (ve != null) ? (PayCode)ve.getValue(context.getELContext()) : null;
...
}
I beleive that you could extend my examples for JSF Converters, ValueChangeListeners and ActionListeners. Now you know where look for attribute value!
[ September 03, 2008: Message edited by: Viacheslav Garmash ]