==========
Validation
==========
Introduction
============
Krail uses the `Apache BVal `__ implementation
of `JSR303 `__ to provide
validation. It also integrates Apache BVal with the Krail I18N
framework, so that all I18N requirements can be managed through the same
process. These are some of the things you may want to do with
validation.
Validation is invoked automatically through Krail’s implementation of
``BeanFieldGroup`` (basically a form without the layout), once its
fields have been annotated.
Use standard javax Validation
=============================
That’s easy. Just use it the `same way as you always
do `__. This
also true of the additional constraints Bval provides (**@NotEmpty** and
**@Email**)
Use a different message for a single use of a javax annotation
==============================================================
If you want to change a message in just one or two places, for example,
to change a validation failure of **@Min** to say: "speed really, really
must be less than 20" you could use standard javax and provide a message
pattern: \` @Min (value=20, message="{0} really, really must be less
than {1}" private int speed; \` This is ok for one language but it will
not translate. A better option might be: \` @Min (value=20,
message="{com.example.ValidationKey.MinReally}") private int speed; \`
Note the "{}" around the message, this denotes a message key rather than
a pattern. Note also that this must be a valid ``I18NKey``.
This method means you can take advantage of Krail’s translation
mechanism, but you do lose the type-safety Krail normally provides by
using enum keys. There are no alternatives because of Java’s limitations
on what can be declared in an annotation.
Change a javax message for all uses
===================================
If you want to change the message for all uses, there is a facility
within the Bval implementation to do that. Krail provides a method in
``KrailValidationModule`` to assist.
::
public class MyValidationModule extends KrailValidationModule{
[source]
----
@Override
protected void define() {
addJavaxValidationSubstitute(Min.class,com.example.ValidationKey.Min);
}
----
}
Move all translations to one source
===================================
You may wish to put all your translations into one place, rather than
have the validation translations held separately. There could be many
good reasons for doing so, and there is an `open
ticket `__ to provide
a utility to migrate the standard keys and patterns to the I18N source
of your choice. You will need to provide a set of I18NKeys for the
validation messages (the full set of keys used by Apache Bval are listed
below). Then, by using the substitution method shown above, all standard
javax.validation.constraints and org.apache.bval.constraints messages
can directed to use the new Krail keys.
standard
--------
javax.validation.constraints.Null.message=must be null
javax.validation.constraints.NotNull.message=may not be null
javax.validation.constraints.AssertTrue.message=must be true
javax.validation.constraints.AssertFalse.message=must be false
javax.validation.constraints.Min.message=must be greater than or equal
to {value} javax.validation.constraints.Max.message=must be less than or
equal to {value} javax.validation.constraints.Size.message=size must be
between {min} and {max}
javax.validation.constraints.Digits.message=numeric value out of bounds
(<{integer} digits>.<{fraction} digits> expected)
javax.validation.constraints.Past.message=must be a past date
javax.validation.constraints.Future.message=must be a future date
javax.validation.constraints.Pattern.message=must match the following
regular expression: {regexp}
javax.validation.constraints.DecimalMax.message=must be less than or
equal to {value} javax.validation.constraints.DecimalMin.message=must be
greater than or equal to {value}
additional built-ins
--------------------
org.apache.bval.constraints.NotEmpty.message=may not be empty
org.apache.bval.constraints.Email.message=not a well-formed email
address
Create a Custom Validation
==========================
There are many cases where a custom validator can be useful, and Apache
Bval does enable the creation of custom validators. With one small
addition, a custom validation can also integrate neatly with Krail’s
enum based I18N. There are three parts to the creation of a custom
validator - the validator itself, the annotation used to invoke it and
the key for the message. Most of this is standard JSR303 - the only
difference in the annotation is the ``messageKey()`` method needed to
enable the use of Krail I18N keys.
The annotation
--------------
::
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import com.example.ValidationKey;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {AdultValidator.class})
public @interface Adult {
ValidationKey messageKey() default ValidationKey.Must_be_an_Adult;
String message() default "krail";
Class>[] groups() default { };
Class extends Payload>[] payload() default {};
long value() default 18;
/**
* Defines several @Adult annotations on the same element
* @see @Adult
*
*
*/
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
@Documented
@interface List {
Adult[] value();
}
}
The Constraint Validator
------------------------
::
public class AdultValidator implements ConstraintValidator {
private long minValue;
public void initialize(Adult annotation) {
this.minValue = annotation.value();
}
public boolean isValid(Number value, ConstraintValidatorContext context) {
if (value == null) {
return true;
} else if (value instanceof BigDecimal) {
return ((BigDecimal) value).compareTo(BigDecimal.valueOf(minValue)) != -1;
} else if (value instanceof BigInteger) {
return ((BigInteger) value).compareTo(BigInteger.valueOf(minValue)) != -1;
} else {
return value.longValue() >= minValue;
}
}
}
The Key
-------
::
public enum ValidationKey implements I18NKey {
Too_Big, Must_be_an_Adult
}