JSR 303 - Bean Validation Spec
JSR 303 is the Spec dealing with Bean Validation
Two important concepts
- API provided by the JEE lib - javax.validation
- IMPL provided by others (similar to other specs). In this case the reference implementation is the Hibernate validator and is used extensively (e.g. D-API)
Bean Validation can be done by
- Annotations directly on the Bean class itself (most popular way :))
- xml validations file -> useful when no control over bean class you want to validate.
- Programmatic addition of constraints (might be Hibernate specific though ….. )
Example of directly calling the Bean Validation http://stackoverflow.com/questions/19190592/manually-call-spring-annotation-validation
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Driver driver = new Driver();
driver.setAge(16);
Car porsche = new Car();
driver.setCar(porsche);
Set<ConstraintViolation<Driver>> violations = validator.validate(driver);
Future Developments:
- BeanValidation 1.0 - JSR 303 is the first spec and is quite old. (2009)
- BeanValidation 1.1 - JSR 349 - already in JEE7 - method-level validation, CDI integration (2013)
- BeanValidation 2.0 - JSR 380 - planned for JEE8 - allow use of Java8 language features.
Useful Links:
- JEE 6 Tutorial example of Bean Validation using the Annotations - http://docs.oracle.com/javaee/6/tutorial/doc/gircz.html
- StackOverflow talking about "programmatic" adding of validation constraints - http://stackoverflow.com/questions/21736365/jsr-303-bean-validation-contraints-without-annotations
- StackOverflow about calling validation directly - http://stackoverflow.com/questions/19190592/manually-call-spring-annotation-validation
- Specification Home + lots of useful info (RedHat)
- Hibernate Validator links
- Programmatic addition of constraints - https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#section-programmatic-api
- XML Config - https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#chapter-xml-configuration
Errors that can happen if you don't have a provider jar available:
Unable to create a Configuration, because no Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath
Hibernate validator
Bean Validation API
Fun with reflection and getting Bean Validation API Payloads
Getting the Payload from the Bean Validation definition
@Test
public void throwaway() throws Exception {
TestBean test = new TestBean();
test.test = null;
Set<ConstraintViolation<TestBean>> violations = validator.validate(test);
for (ConstraintViolation<TestBean> violation : violations) {
ConstraintDescriptor<?> constraintDescriptor = violation.getConstraintDescriptor();
for (Class<? extends Payload> payload : constraintDescriptor.getPayload()) {
payload.getClass();
// Cast to a subclass and then get the fields
CannedMessageEnum msg = (CannedMessageEnum)
payload.asSubclass(MissingMandatoryData.class).getFields()[0].get(payload);
msg.getMsgId();
// Don't bother with cast and get the field by name instead of index.
CannedMessageEnum msg2 = (CannedMessageEnum)payload.getField("msg").get(payload);
msg2.getMsgId();
Assert.assertEquals(CannedMessageEnum.MANDATORY_DATA_MISSING.getMsgId(), msg2.getMsgId());
}
}
assertFalse(violations.isEmpty());
}
public class TestBean {
@NotNull(message = "Name is mandatory",
payload = MandatoryData.class)
String test;
@NotNull(message = "Name is mandatory",
payload = DCTest.class)
String testNonExistantCannedMsg;
}
public interface DCTest extends Payload {
CannedMessageEnum msg = CannedMessageEnum.NOT_EXISTING_MSG;
}
Getting the QueryParam "value" attribute to see the query parameter input field value
static final String QUERY_PARAM_SOURCE = "value";
/**
* Look for QueryParam annotation and retrieve its "value" property as the source e.g. @QueryParam("origin")String
* origin;
*
* @param annotations
* @return String - parameter value to use as the issue source. null if the parameter could not be determined from the
* annotations
*/
public String getSourceParameter(Annotation[] annotations) {
String parameter = null;
if (annotations.length == 1) {
Annotation annotation = annotations[0];
if (annotation.annotationType() == javax.ws.rs.QueryParam.class) {
try {
parameter = annotation.annotationType().getMethod(QUERY_PARAM_SOURCE).invoke(annotation).toString();
} catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException | IllegalArgumentException
| SecurityException e) {
logger.warn("Query Parameter Value could not be determined, default value null will be used. ", e);
parameter = null;
}
}
}
return parameter;
}