Parameter mapping
JavAjax offers a simple way to bind a request parameter to a method input parameter: @Param annotation.
This annotation can be used at parameter level, or inside a @ParameterMapping annotation specified at method level. In any case, number and order of @Param annotations must match input parameters.
Validation is always performed before the Action method is actually invoked, using one of the standard Validator classes based on the data type of the method parameter, or using the Validator declared on the @Param annotation.
protected Response myMethod(@Param("inputParam") String value){
...
}
@ParameterMapping(
params={@Param("inputParam")}
)
protected Response myMethod(String value){
...
}
Framework level validation
The annotation @Param can be configured to inform the framework about the validation that should be done on the parameter, before the method is actually called. As already said, data conversion is always done and eventually an invalid.format validation error is raised, but more specific validation steps can be added.
- mandatory: can be applied on any type of parameter, if the check fails the mandatory message is raised.
- minLength: can be applied on String parameter, indicates the minimum length of the received String, if the check fails the string.too.short message is raised.
- maxLength: can be applied on String parameter, indicates the maximum length of the received String, if the check fails the string.too.long message is raised.
- match: can be applied on String parameter, indicates a regular expression the input value must match, if the check fails the string.not.match message is raised.
- minValue: can be applied on any numeric type parameter, indicates the minimum value the parameter should represent, if the check fails the number.too.low message is raised.
- maxValue: can be applied on any numeric type parameter, indicates the maximum value the parameter should represent, if the check fails the number.too.high message is raised.
- maxFileSize: can be applied on UploadFile parameter, indicates the maximum size of an uploaded file represented by the parameter, if the check fails the file.too.big message is raised.
- accepts: can be applied on UploadFile parameter, indicates a comma separated list of file extension valid for an uploaded file represented by the parameter, if the check fails the file.not.allowed message is raised.
- deny: can be applied on UploadFile parameter, indicates a comma separated list of file extension invalid for an uploaded file represented by the parameter, if the check fails the file.not.allowed message is raised.
- validator: A custom Validator class to be used for validation, it overrides default Validator for this parameter.
@ParameterMapping {
params={
@Param(value="userName", mandatory=true, minLength=5)
, @Param(value="email", mandatory=true, minLength=5, match="^[a-z0-9_-\\.]?@.?\\..?$"))
, @Param(value="yearOfBirth", minValue=5)
}
}
protected Response myMethod(String userName, String email, int year) {
...
}
Custom validation
Sometimes a more specific validation is needed, i.e. when we need to validate the parameter against a pattern or a range. In this case we can use a custom Validator, implementing the Validator<?> class or extending one of the custom validators. One example is the EmailValidator, already available in the framework, which extends the StringValidator and checks if the given value is a valid email address.
Validators can be used directly on a @Param annotation, to be used on a specific parameter, or declared in the Filer init parameter "custom.validators", so that all the parameters of that Class will be validated using this Validator. This is strongly suggested when a custom data type is used and you want to validate the value received.
Following the example above, we can validate the email address using a Validator class instead of a pattern:
@ParameterMapping {
params={
@Param(value="userName", mandatory=true, minLength=5)
, @Param(value="email", mandatory=true, validator=EmailValidator.class))
, @Param(value="yearOfBirth", minValue=5)
}
}
protected Response myMethod(String userName, String email, int year) {
...
}
To validate a custom data type, we can implement the Validator class...
public class MyDateValidator implements Validator<MyDate> {
@Override
public void validate(RequestContext context, Param param, Object value) throws ValidationException
{
... your code here...
}
}
...and declare the new validator in the Filter configuration
<init-param>
<param-name>custom.validators</param-name>
<param-value>myPackage.MyDateValidator</param-value>
</init-param>
In-Method validation
When framework or custom validation are passed, the method is invoked and executed. In the case more specific validation is needed, it can be performed in the method and generating, if needed, ValidationError objects.
If method execution should not be interrupted, these objects can be added to the RequestContext, otherwise can be added to an ValidationException, which will be then thrown, interrupting the execution.
This code will generate a message without interrupting the method execution
if(a < b) {
getContext().addMessage(new ValidationError("fieldName", "my.first.message"));
}
This code will generate a message interrupting the method execution
if(a > c) {
throw new ValidationException("fieldName", "my.second.message");
}
where "my.first.message" and "my.second.message" are keys to retrieve the message text from the properties file.