I want to validate the inputs to my JSF page inside my Managed bean, but for some reason it does not work?
#ManagedBean
#RequestScoped
public class RegistrationController {
//values passed from the JSF page
private String name;
...
public void validateName(FacesContext context, UIComponent validate,
Object value) {
String inputFromField = (String) value;
String simpleTextPatternText = "^[a-zA-Z0-9]+$";
Pattern textPattern = null;
Matcher nameMatcher = null;
textPattern = Pattern.compile(simpleTextPatternText);
nameMatcher = textPattern.matcher(getName());
if (!nameMatcher.matches()) {
((UIInput) validate).setValid(false);
FacesMessage msg = new FacesMessage(
"your name cant contain special characters");
context.addMessage(validate.getClientId(), msg);
}
}
This is how input component looks like(Inside a form):
<h:inputText value="#{registrationController.name}" validator="#{registrationController.validateName}" required="true">
<h:message for="nameInput"/>
When i enter a wrong input i dont see the validation message, and in the console i see this:
INFO: Instantiated an instance of org.hibernate.validator.engine.resolver.JPATraversableResolver.
INFO: WARNING: FacesMessage(s) have been enqueued, but may not have been displayed.
sourceId=bRegForm:j_idt7[severity=(ERROR 2), summary=(bRegForm:j_idt7: Validation Error: Value is required.), detail=(bRegForm:j_idt7: Validation Error: Value is required.)]
What it could be? Am i forgetting something? Do i have to add something to my configuration files...?
You forgot to give your input component an id. That's where the for attribute of <h:message> should point to.
<h:inputText id="nameInput">
Unrelated to the concrete problem, your approach is clumsy and technically wrong. As per the specification, you should throw a ValidatorException. So instead of
((UIInput) validate).setValid(false);
context.addMessage(validate.getClientId(), msg);
do
throw new ValidatorException(msg);
Then JSF will worry about setting the component as invalid and adding the message to the context.
There's a second problem, you're validating the local value instead of the submitted value.
Replace
nameMatcher = textPattern.matcher(getName());
by
nameMatcher = textPattern.matcher(inputFromField);
Related
I am trying to improve an old application that uses Oracle ADF 12c.
I need to compute the file name before it will be downloaded.
Currently the download of the file is written like this.
<af:table value="#{DocListManagedBean.list}" var="row"
disableColumnReordering="true" varStatus="vs" id="t1"
columnStretching="column:c2" emptyText="#{PageLabels.emptyText}"
styleClass="AFStretchWidth">
<af:column width="100px" align="center">
<f:facet name="header">
<af:outputText value="#{PageLabels.document}"/>
</f:facet>
<af:commandImageLink shortDesc="#{PageLabels.downloadDocument} ID: #{row.idDocument}"
icon="/skin/images/icons/pdf_icon4.gif">
<af:setPropertyListener from="#{row.idDocument}"
to="#{DocListManagedBean.selectedIdDocument}" type="action"/>
<af:fileDownloadActionListener contentType="application/pdf"
filename="#{row.documentName}"
method="#{DocListManagedBean.downloadFileListener}"/>
</af:commandImageLink>
</af:column>
<af:column>
<f:facet name="header">
<af:outputText value="#{PageLabels.documentName}"/>
</f:facet>
<af:outputText value="#{row.documentName}"/>
</af:column>
</af:table>
And it should now be so that (based on the document id) the file name should be computed, i.e. concatenated from several elements that are not in the object, the list of which is presented in af:table.
I already have the method returning the new file name in managed bean (called generateDocumentFileName). This method based on selectedIdDocument field in DocListManagedBean computes the correct filename and saves it in another field DocListManagedBean named selectedDocumentNewFilename.
Is it possible (without changing - without adding another field to the type of object presented by af:table) before running the af:downloadFileListener method, to run another method in managed bean (my generateDocumentFileName) ? ... which would calculate the missing name, save it to the field selectedDocumentNewFilename in managed bean and then new filename will be available e.g. via
<af:fileDownloadActionListener contentType="application/pdf"
filename="#{DocListManagedBean.selectedDocumentNewFilename}"
method="#{DocListManagedBean.downloadFileListener}"/>
Where I should put a call to my generateDocumentFileName method in the code above or is it a stupid idea and I should have done it differently ?
Thanks for help,
koli
The idea is mostly correct. You can programmatically set the file name in the filename attribute of the af:fileDownloadActionListener. (no need to call another function before hand - so you can remove the af:setPropertyListener).
You can get value from any iterator binding using the resolveExpression from the JsfUtils library. (detailled here https://cedricleruth.com/how-to-retreive-the-value-of-an-iterator-binding-variable-programmatically-in-adf/) For example your #{DocListManagedBean.selectedDocumentNewFilename} could look like this :
private String selectedDocumentNewFilename;
public String getSelectedDocumentNewFilename(){
//Using below function you can easily get any of those value in your ADF Bean as follow :
Long currentIdDocument = (Long)resolveExpression("#{row.idDocument}");//if idDocument is a Long in your VO
String currentNameDocument= (String)resolveExpression("#{row.documentName}"); //for example
String anyOtherStringValueYouWant= (String)resolveExpression("#{bindings.YOUR_VO.YOUR_VO_ATTRIBUTE.inputValue}"); //for example
//add any function to do something with this ID
String generatedName = this.generateDocumentFileName(currentIdDocument);
return "" + currentIdDocument.toString() + "_" + currentNameDocument + ".pdf"; //format as you like
//or in your case : return "" + generatedName + ".pdf";
}
/**
* Method for taking a reference to a JSF binding expression and returning
* the matching object (or creating it).
* #param expression EL expression
* #return Managed object
* #author : Duncan Mills, Steve Muench and Ric Smith's JSFUtils class
*/
public static Object resolveExpression(String expression) {
FacesContext facesContext = getFacesContext();
Application app = facesContext.getApplication();
ExpressionFactory elFactory = app.getExpressionFactory();
ELContext elContext = facesContext.getELContext();
ValueExpression valueExp = elFactory.createValueExpression(elContext, expression, Object.class);
return valueExp.getValue(elContext);
}
I have a validator defined for my checkbox control:
<xp:checkBox uncheckedValue="false"
checkedValue="true" readonly="#{!matterBean.matter.editable}"
id="cbKCSupport" style="width:100%"
value="#{matterBean.matter.creatorKCSupport}"
validator="#{matterValidators.valCreatorKCSupport}">
</xp:checkBox>
the method is nothing fancy, I just check the value true or false of the checkbox:
public void valCreatorKCSupport(FacesContext facesContext, UIComponent component, Object value) {
utils.printToConsole(this.getClass().getSimpleName().toString() + " - valCreatorKCSupport(...), value = " + value.toString());
String msg = null;
if (value.toString().equals("false")){
msg = matterProp.getProperty("gen_KCSupport");
FacesMessage message = new FacesMessage(msg);
throw new ValidatorException(message);
}
}
I notice that this validation blocks the behaviour of other components e.g. the opening of dialog boxes.
For other controls I have a similar approach where the required property is based upon which component (buttons) have initiated the call to the server:
<xp:this.required><![CDATA[#{javascript:return ( submittedBy('btnSendToCommitee') || submittedBy('btnForCompletion') )}]]></xp:this.required>
I tried to set up a similar approach for my checkbox:
but then I get presented an error message:
Error while executing JavaScript action expression
Script interpreter error, line=2, col=33: Error calling method 'valCreatorKCSupport(com.ibm.xsp.domino.context.DominoFacesContext, com.ibm.xsp.component.xp.XspInputCheckbox, string)' on java class 'se.sebank.kkom.test.MatterValidators'
Message (text with text from matterProp.getProperty("gen_KCSupport"))
Anyone a suggestion how I should apply some conditional statement to my validator?
So the class I'm doing JSR-303 bean validation on has two fields with the same pattern constraint applied to each:
#Column(name="test_suite_revision")
#XmlElement(name="test_suite_revision")
#NotNull
#Pattern(regexp = "\\d\\d-\\d\\d-\\d\\d\\d\\d", message = "value must be of the form xx-xx-xxxx")
private String revisionTestSuite;
#Column(name="test_revision")
#XmlElement(name="test_revision")
#NotNull
#Pattern(regexp = "\\d\\d-\\d\\d-\\d\\d\\d\\d", message = "value must be of the form xx-xx-xxxx")
private String revisionTest;
IMPORTANT - this class is NOT a form-backing class in a classic Spring MVC webapp but an entity class that lives at the base of a web service. So the validation is occuring in the service.
Now the web client that consumes the web service is a Spring MVC and does have a form-backing bean which ties to a jsp with places to put error messages.
So suppose a user enters an incorrectly-formatted string into one of the two fields. I can trap for it with this pretty standard code snippet
Set<ConstraintViolation<TestCase>> violations = validator.validate( permit);
if( !violations.isEmpty()) {
logger.debug( "basic validation FAILED with " + violations.size() + " errors");
Iterator<ConstraintViolation<TestCase>> iter = violations.iterator();
while( iter.hasNext()) {
ConstraintViolation<TestCase> cv = iter.next();
logger.debug( "invalidValue:" + cv.getInvalidValue());
logger.debug( "message:" + cv.getMessage());
ConstraintDescriptor<?> cd = cv.getConstraintDescriptor();
Map<String, Object> mapp = cd.getAttributes();
for( String keey : mapp.keySet()) {
logger.debug("mapp key:" + keey + ":" + mapp.get(keey));
}
which writes out
basic validation FAILED with 1 errors
invalidValue:050607
message:value must be of the form xx-xx-xxxx
mapp key:message:value must be of the form xx-xx-xxxx
mapp key:payload:[Ljava.lang.Class;#1367702
mapp key:flags:[Ljavax.validation.constraints.Pattern$Flag;#bf5210
mapp key:groups:[Ljava.lang.Class;#a49be5
mapp key:regexp:\d\d-\d\d-\d\d\d\d
Here's the rub: How does one figure out WHICH field failed validation? I can't seem to find a way to extract the field name , "revisionTest" or "revisionTestSuite"
from the ConstraintViolation object nor the ConstraintDescritpor object.
the getValidationAppliesTo() method newly available in version 1.1.0.Final of javax.validation-api seems promising but so far this method throws an AbstractMethodError during runtime. Ugh.
TIA,
Still-learning Steve
See ConstraintViolation#getPropertyPath method:
/**
* #return the property path to the value from {#code rootBean}
*/
Path getPropertyPath();
Path.Node#getName will give you the property name. For field names in nested beans, you have walk the path.
Here is my Java code, before call I call the save() method. I want to check this business rule.
if (endDate.before(startDate)){
message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "",
"The end date should be not before the start date.");
// Throw exception so that it prevents document from being saved
FacesContext facesContext = FacesContext.getCurrentInstance();
facesContext.addMessage("travel_endDate",message);
return false;
}
I want this message display at the "travel_endDate" component.
You have to use the client id of your component when adding the message.
1.) Add a binding to you component
<xp:inputText
id="travel_endDate"
binding="#{errorComponent}">
</xp:inputText>
2.) resolve the variable in your save method
UIComponent cmp = (UIComponent) facesContext.getApplication().getVariableResolver().resolveVariable(facesContext, "errorComponent");
String clientId = cmp.getClientId(facesContext);
3.) Add the message with the id to the facesContext
facesContext.addMessage(clientId,message);
I have a <h:commandButton> on my page connected with action in my bean. It work just fine, but I wanted to add confirmation message. When I used:
<h:commandButton onclick="confirm('Are you sure?')">
it alco works just fine. But when I try to get string from bean, by making it looks like this:
<h:commandButton onclick="confirm('#{bean.confirmQ}')"> it doesn't display this string. In getter for this string I invoke method to take some info from DB, and I format it then I return it. When I use this approach nothing is shown, not even empty box, and page looks like just refreshing.
Here is code from bean:
private String confirmQ;
public String getConfirmQ() {
WycenioneAuta wa = getWycenioneAuto();
String question = "are you sure \n" + wa.getName + "?";
confirmQ = question;
return confirmQ;
}
public void setConfirmQ(String confirmQ) {
this.confirmQ = confirmQ;
}
Escape the line by writing String question = "are you sure \\n" + wa.getName + "?";
If your String variable is confirmQ , then the right EL pointing to that variable is #{bean.confirmQ} and not #{bean.confirm} as you've written.
In complement to ஜன்'s Answer:
At least for Firefox , I should had a return in the Javascript code, otherwise the cancel does not work:
<h:commandButton onclick="return confirm('Are you sure?')" ... />