I have a question here:
Scenario: I have a JSF-2, Spring (Beans wiring) Application. I have written a custom validator, which I want to execute.
@FacesValidator("com.test.vali")
@Named("com.test.vali")
public class TestValidator implements Validator {
@Override
public void validate(FacesContext arg0, UIComponent arg1, Object arg2) throws ValidatorException {
System.out.println("dhkdfkbhdfbkdfksdfdfk");
}
}
I was trying to inject the validator using the following ways:
Way#1:
<h:inputText value="#{helloWorld.name}">
<f:validator binding="#{com.test.vali}" />
</h:inputText>
Output
When tried to render the page, it threw an exception.
javax.servlet.ServletException: /testRichFaces.xhtml @17,48 <f:validator> A validator id was not specified. Typically the validator id is set in the constructor ValidateHandler(ValidatorConfig)
Searched a lot on this, and verified few ways like:
Way#2
<f:validator validatorId="com.test.vali" />
Output
javax.servlet.ServletException: Expression Error: Named Object: com.test.vali not found.
So from way#1 and way#2, I could interpret that none of the annotations were working for me.
Then, I tried to move to the last approach:
Way#3: Adding validator in faces-config.xml, just to show I am using 2.0 compliance:
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version="2.0">
And validator config is:
<validator>
<validator-id>com.test.vali</validator-id>
<validator-class>teet.TestValidator</validator-class>
</validator>
Output
Works
Now the question arises, even using JSF-2.0, I had to resort to faces-config.xml.
What might be the mistake am doing?
Let know if any more configurations are required.
First of all, you're basically mixing 2 ways of registering a validator instance which work completely independently from each other: registering as faces validator via @FacesValidator
, or registering as CDI managed bean via @Named
. Those annotations do not know each other, nor do they take each other into account. You basically end up with two completely distinct instances which do not share each others data. To avoid future confusion, it's therefore strongly recommended to remove one of those annotations so that you can guarantee that you always use the one and the same instance.
As to why way 1 failed:
@Named("com.test.vali")
public class TestValidator implements Validator {
// ...
}
<f:validator binding="#{com.test.vali}" />
This is because the period .
is a special operator in EL representing a bean property access or bean method call. Using #{com.test.vali}
would only look for a bean #{com}
and then its test
property and then in turn its vali
property. In other words, it's basically trying to get the validator via com.getTest().getVali()
where com
is a CDI managed bean like so @Named("com")
.
This is not what you intented. Get rid of those periods in the name. Better, just stick to the default instance name, testValidator
. It's the most sane choice, for sure if you give your classes sensible names.
@Named
public class TestValidator implements Validator {
// ...
}
<f:validator binding="#{testValidator}" />
As to why way 2 failed:
@FacesValidator("com.test.vali")
public class TestValidator implements Validator {
// ...
}
<f:validator validatorId="com.test.vali" />
That may happen when the @FacesValidator
isn't been properly picked up during startup. That may in turn happen when the class in question is not inside the WAR, but instead inside e.g. EAR or EJB. In this case, you'd need to explicitly register the validator in faces-config.xml
. But better is to put the class in the WAR, you should namely absolutely not have any JSF artifacts in the EAR or EJB part of the project. It would tight-couple the model/service logic (JPA, EJB, etc) to the view (JSF) and make them not reusable anymore for other views (front-ends) such as JAX-RS, Spring MVC, Struts2, etc.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With