问题
I have two PrimeFaces p:calendar components, one representing a begin and the other representing an end date.
I want to run a validator method now whenever one of them changes.
Here's the end date component:
<p:calendar id="end-date"
widgetVar="testEndDate"
value="#{testManager.endDate}"
mindate="#{testManager.minEndDate}"
maxdate="#{testManager.maxEndDate}"
validator="#{testManager.validateEndDate}">
<p:ajax event="dateSelect" update="begin-date msgs" global="false" />
</p:calendar>
Here's the validator method code:
@Override
public void validateEndDate(FacesContext context, UIComponent component, Object value)throws ValidatorException
{
System.out.println(this.getClass().getSimpleName() + ".validateEndDate()!");
Date beginDate = this.getBeginDate();
Date endDate = (Date)value;
if ( endDate != null && endDate.getTime() <= beginDate.getTime() )
{
System.out.println("End date less than or equal to begin date!");
// this.setValidated( false );
//
// throw new ValidatorException( JsfUtil.getValidationErrorFacesMessage( "common.validator.validTo.message" ) );
context.addMessage(null, JsfUtil.getValidationErrorFacesMessage("common.validator.validTo.message"));
}
List < FacesMessage > messages = context.getMessageList();
if ( !messages.isEmpty() )
{
System.out.println("Faces messages list not empty! Size = " + messages.size());
this.setValidated(false);
throw new ValidatorException(messages);
}
this.setValidated(true);
}
Here's what I do:
- Show the dialog via command button.
- Click into the empty end date calendar input, which pops up the calendar.
- Click on the 22 (same date as the begin date).
The code basically works, at least according to the console output:
INFO: DefaultValidatingBeginEndDateChecker.validateEndDate()!
INFO: End date less than or equal to begin date!
INFO: Faces messages list not empty! Size = 1
However, this shows the same FacesMessage twice on the UI:
As you can see, the output doesn't match what the validator method is saying.
Does anyone know what's going on/wrong and how to fix this? (Also note the outcommented code showing the working solution, but I need to know why this isn't working, because I have another more complex validator which has 1+ ifs which is supposed to show more than one message...).
回答1:
What works is to collect the faces messages in an own list:
List<FacesMessage> messages = new ArrayList<FacesMessage>();
if ( endDate != null && endDate.getTime() <= beginDate.getTime() )
{
System.out.println( "End date less than or equal to begin date!" );
// context.addMessage( null, JsfUtil.getValidationErrorFacesMessage( "common.validator.validTo.message" ) );
messages.add( JsfUtil.getValidationErrorFacesMessage( "common.validator.validTo.message" ) );
}
// ... more ifs
if ( !messages.isEmpty() )
{
System.out.println( "Faces messages list not empty! Size = " + messages.size() );
this.setValidated( false );
throw new ValidatorException( messages );
}
this.setValidated( true );
Doh.
回答2:
I think that this is an expected behaviour. Look suspiciously at the following two lines of code:
context.addMessage(null, JsfUtil.getValidationErrorFacesMessage("common.validator.validTo.message"));andthrow new ValidatorException(messages);.
Think what they do. The first line adds a message to the current context and the second one throws an exception, instructing JSF that validation has failed, and this in turn adds your list of exceptions to the current context as well.
So, the solution is straightforward: remove the redundant context.addMessage(null, JsfUtil.getValidationErrorFacesMessage("common.validator.validTo.message")); line and replace your throws clause for throw new ValidatorException(new FacesMessage(JsfUtil.getValidationErrorFacesMessage("common.validator.validTo.message")));.
来源:https://stackoverflow.com/questions/16694036/jsf-validator-method-results-in-duplicate-facesmessage-shown-in-pmessages