Show error details when throwing Validator Exception - validation

I have code in a managed bean:
public void setTestProp(String newProp) {
FacesMessage yourFailure = new FacesMessage();
yourFailure.setDetail("Really you need to promise to never do that again!");
yourFailure.setSummary("Stop here, now!");
yourFailure.setSeverity(FacesMessage.SEVERITY_FATAL);
throw new ValidatorException(yourFailure);
}
and in the XPage:
<xp:messages id="messages1" layout="table" showSummary="false"
showDetail="true" globalOnly="false">
</xp:messages>
but I get as result message (nicely in the yellow box as expected, not in an error page):
Error setting property 'testProp' in bean of type com.ibm.sg.demo.Test: javax.faces.validator.ValidatorException: Stop here, now!
I would like to:
not have the technical part
see the summary
What do I miss?

The problem is that the property resolver catches all java.lang.Throwable from the get/set method of the managed beans. The "original" facesMessage is replaced with a new one (the previous message is appended).
You have three possibilities:
Create your own property resolver
Create your own validator and attach it to the field binded to the managed bean
Add a validation method to your bean
Hope this helps
Sven
EDIT:
How to add a validation method to your bean
a) Add a validation method to your bean
public void validate(FacesContext context, UIComponent toValidate, Object value){
// Do your validation with value
// if everything is ok, exit method
// if not, flag component invalid...
((UIInput)toValidate).setValid(false);
// ... create your message ...
FacesMessage yourFailure = new FacesMessage();
yourFailure.setDetail("Really you need to promise to never do that again!");
yourFailure.setSummary("Stop here, now!");
yourFailure.setSeverity(FacesMessage.SEVERITY_FATAL);
context.addMessage(toValidate.getClientId(context), yourFailure);
}
b) Add your validator to the field
<xp:inputText id="inputText1"
value="#{TBean.test}"
validator="#{TBean.validate}">
(You can name the method whatever you want.)
This validator has not to be added to the faces-config.xml.

Once you determine your field has failed validation, all you need to do is do this, and you'll get what you want:
throw new javax.faces.validator.ValidatorException(new javax.faces.application.FacesMessage("Stop here, now!"));

Related

Inputtext validator attribute set by an existing field in a bakedbean

I have some inputtext in a form which is managed by a bean #Named and i would like to centralize the information concerning this fields such as which validator is assigned to which field.
If i directly write the name of the #FaceValidator, it works.
<h:inputText validator="validatorLogin"/>
If i tried to put the name of the validator with a bean property such as String validatorLogin = validatorLogin.
It will throw an error in the .xhtml like "Expression must be a method expression but is a value expression".
If i try to still run the code it will throw the following exception "validator=#{bean.validatorLogin}: Method not found".
<h:inputText validator="#{bean.validatorLogin}"/>
I expect the validator name to be set in the bean and the bean to feed the validator id in the inputtext field. So all informations about the form are centralized in one bean.
As well is it dumb to do so or is it something that will make the code more organized ?
As the validator attribute documentation states, there is no way to provide a validatorId via bean property to this attribute:
validator: MethodExpression representing a validator method that will be called
during Process Validations to perform correctness checks on the value
of this component. The expression must evaluate to a public method
that takes FacesContext, UIComponent, and Object parameters, with a
return type of void.
You would normally either hard code a validatorId as you did in your first example, or a method expression (in your second example) that resolves to a method like this:
public void validatorLogin(FacesContext context, UIComponent component, Object value)
throws ValidatorException {
// ...
}
Of course it's up to this bean implementation how the input is validated then. If you want to combine both approaches, you can delegate validation to one (or multiple) validators known by ID in your validatorLogin method:
public void validatorLogin(FacesContext context, UIComponent component, Object value)
throws ValidatorException {
final Collection<String> validatorIds = determineValidatorIds(context, component);
for (String validatorId : validatorIds) {
Validator<Object> validator = context.getApplication().createValidator(validatorId);
validator.validate(context, component, value);
}
}
private Collection<String> determineValidatorIds(FacesContext context, UIComponent component) {
// return hard coded validatorIDs or determine them on arbitrary logic.
}
If you urgently need to provide a validatorId via bean property, you can do so by using the f:validator tag within your input component:
<h:inputText id="txt" value="#{myBean.textValue}">
<f:validator validatorId="#{myBean.arbitraryValidatorId}" />
</h:inputText>

Pass a List to a Validator , Conversion Error setting value '[]' for 'null Converter

I am new in JSF, and my question is realted to the Validator. I have an FileUploader (primefaces) and a Form. when the Submit button is clicked , a method should check the DataTable inside of the Form and also a validator should check if any file has been uploaded via FileUploader. Hence, I have put a Hidden button which calls the validator.
In my Bean I have the following getter and setter:
public List<Attachment> getAttachmentList() {
return attachmentList;
}
public void setAttachmentList(List<Attachment> attachmentList) {
this.attachmentList= attachmentList;
}
and then in my validator I have the following code:
#FacesValidator("uploadValidator")
public class uploadValidator implements Validator {
public uploadValidator() {
// TODO Auto-generated constructor stub
}
#Override
public void validate(FacesContext context, UIComponent component,
Object value) throws ValidatorException {
FacesMessage msg =
new FacesMessage(" this is the uploader message.",
"this is the uploader message.");
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(msg);
}
when I call the validator from my XHTML file (<f:validator validatorId="uploadValidator" />), in Primefaces growl message, I recieve the error :
Conversion Error setting value '[]' for 'null Converter
Here is XHTML code:
<h:inputHidden id="hidenB" value="#{myBean.attachmentList}">
<f:validator validatorId="uploadValidator" />
</h:inputHidden>
I know the problem is when I pass value to "Object value" but i don't know how to resolve it.
In Validator I just need to know if the attachmentList is empty or not, while in myBean i do other things with attachmentList, How can I send just a boolean value to the Validator ? can I have another getter and setter that send a Boolean value ?? if yes then I don't need a converter
Thanks in advance for any help.

CustomRequiredvalidator did not get triggered

I am confused because my custom required validation did not get triggered.
I got a class which creates my HtmlTextInput element programmatically and adds
the validator. Moreover I got my custom validator class. Console tells me that
validators got bound to HtmlTextInput. Anyway after hitting 'save'
CustomRequiredValidator did not get called! I am using JSF 2.x. Thanks in
advance.
// programmatically built HtmlInput-element
if (freeText.isRequired()) {
// Validator-Objekt
System.out.println("CustomRequiredValidator bound.");
final CustomRequiredValidator validator = (CustomRequiredValidator) FacesContext.getCurrentInstance().getApplication().createValidator("CustomRequiredValidator");
inputText.addValidator(validator);
}
// CustomValidator
#FacesValidator("CustomRequiredValidator")
public class CustomRequiredValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent uiComponent, Object value) throws ValidatorException {
System.out.println("RequiredValidator.validate ..."); ...
}
}
Validators are only invoked if conversion has succeed. So if there's a converter, either explicitly registered or implicitly used (e.g. having an Integer bean property would trigger the JSF builtin IntegerConverter) and it threw a ConverterException, then the validator will never be triggered. You should however have noticed this converter exception in any of the associated <h:message(s)> component or the server logs.
If the converter is excluded from being suspect, then another possible cause is that JSF is configured to not validate empty fields by having the following context parameter in webapp's web.xml:
<context-param>
<param-name>javax.faces.VALIDATE_EMPTY_FIELDS</param-name>
<param-value>false</param-value>
</context-param>
Other than that, well, running a debugger, starting with a breakpoint at UIInput#validate() method should give insights.

catch DB exception in JSF+EJB application

I'm using Glassfish 3.1 with JSF2 and EJB stateless to query and write an Oracle DB. The table the user wants to populate in this web application has a primary key. When the user tries to add a new record the ejb method invoking em.persist is called. Now, if the user tries to add a record that has an already used primary key value, I got an exception in the EJB.
I would like to pop up a message to the user indicating that an error in the database occurred but I can't figure out how the JSF managed bean could catch the EJB exception.
Is there any way?
EJB has the concept of system exceptions and application exceptions.
Runtime exceptions, like EntityExistsException are system exceptions. These will among others cause any transaction to be rolled-ed back and cause the EJB instance bean to be discarded (destroyed). Most importantly for your problem, they will be wrapped in an EJBException.
There is no magic surrounding catching these exceptions. Adjusting the code from Petr above,
the following will just work:
Backing bean:
#EJB
private DAOBean daoBean;
public void savePerson(Entity e) {
try {
daoBean.save(e);
} catch (EJBException e) {
FacesMessage message = new FacesMessage("entity is already exists.");
FacesContext.getCurrentInstance.addMessage(null, message);
}
}
EJB:
private EntityManager em;
public void save(Entity e) {
em.persist(e);
}
Note that you can retrieve the cause of the exception to see if was an EntityExistsException or not (omitted above for brevity).
Since you probably have no need to destroy your EJB instance for this case, a better pattern is to define your own exception that inherits from a RuntimeException and is annotated with the #ApplicationException with the rollback attribute set to true.
E.g.
#ApplicationException(rollback = true)
public class MyException extends RuntimeException {
public MyException(Throwable cause) {
super(cause);
}
}
Wrap your EntityExistsException in your EJB into this exception and throw and catch it.
I strongly advise you NOT to use error codes or boolean success/failure as a result. This is a well-known anti pattern and makes your code incredible error prone.
You can create a custom exception class. Let's say UserException with a enum values of possible exception option.
In you EJB you can define your methods as throwable. If you need throw a exception.
In your JSF-SiteBean you only need to use a simple try/catch.
Is exception from type UserException ... get enum reason ... etc.

How do I wire up ModelAndViewDefiningException to send errors to my view

In the easiest, most straightforward way, how do I wire up a/the ModelAndViewDefiningException doodad to send errors to my specified view?
This guy should be called from: org.springframework.web.servlet.ModelAndViewDefiningException
Much thanks to anyone in advance!
How do I wire up ModelAndViewDefiningException to send errors to my view?
It's an exception. You throw it!
The ModelAndViewDefiningException is an exception wrapper for a ModelAndView. The Spring framework recognizes it, catches it, extracts the model and view name from it and forwards to the resolved view exposing the model to the view.
...
if (someBadThingy) {
ModelAndView modelAndView = new ModelAndView("errorView"); // "errorView" name resolved to a view by the ViewResolver of your app
throw new ModelAndViewDefiningException(modelAndView);
}
...
You can throw it at any time during handler processing. Normally, inside a Controller's code you don't usually throw the exception because Controller request handler methods return a ModelAndView. So instead of throwing an exception with the ModelAndView inside, you can just return the ModelAndView.
But there are situations when you can't return a ModelAndView. Interceptors are a good example of this because their methods are of void or boolean return. If some condition isn't met inside the interceptor the ModelAndViewDefiningException allows you to break the flow and go to the error view.

Resources