Wouldn't it be great to have all JSR-303, custom validation annotations, hibernate specific validations, type and so on accessible from the front end?
var clientValidations = ${ju:getValidations(client)};
Here is a new method for the JSONUtils.java I have been working on to support a richer application:
...
/**
* Given a target object it returns all fields and annotations for those related to validations: Map<String fieldName,
* Map<String annotationName, Map<String annotationAttributeName, String annotationAttributeValue>>
*
* @param target
* @return
* @throws IOException
* @throws JsonMappingException
* @throws JsonGenerationException
*/
public static String getValidations(Object target) throws JsonGenerationException, JsonMappingException, IOException {
Map<String, Map<String, Map<String, Object>>> validations = new HashMap<String, Map<String, Map<String, Object>>>();
List<String> validationPackages = new ArrayList<String>();
// JSR 303
validationPackages.add("javax.validation.constraints");
// Hibernate
validationPackages.add("org.hibernate.validator.constraints");
// Custom
validationPackages.add("com.sample.validator.constraints");
Field[] fields = target.getClass().getDeclaredFields();
for (Field field : fields) {
boolean accessible = field.isAccessible();
if (!accessible) {
field.setAccessible(true);
}
Annotation[] annotations = field.getAnnotations();
Map<String, Map<String, Object>> validationsMap = new HashMap<String, Map<String, Object>>();
for (Annotation annotation : annotations) {
if (validationPackages.contains(annotation.annotationType().getPackage().getName())) {
String annotationName = annotation.annotationType().getName();
Map<String, Object> annotationAtributes = AnnotationUtils.getAnnotationAttributes(annotation);
Iterator<String> it = annotationAtributes.keySet().iterator();
while (it.hasNext()) {
String key = it.next();
// Remove unneeded attributes
if ("groups".equals(key) || "payload".equals(key)) {
it.remove();
}
}
validationsMap.put(annotationName, annotationAtributes);
}
}
Map<String, Object> typeMap = new HashMap<String, Object>();
typeMap.put(TYPE, field.getType());
validationsMap.put(TYPE, typeMap);
if (validationsMap.size() > 0) {
validations.put(field.getName(), validationsMap);
}
}
return toJson(validations);
}
...
And then the JSONUtils.tld declaration:
<function>
<name>getValidations</name>
<function-class>com.sample.utils.JsonUtils</function-class>
<function-signature>
String getValidations(java.lang.Object)
</function-signature>
</function>
Here is an example of such JSON generated file. As you can see there are JSR-303, hibernate scpecific and custom validation constraints listed. Time for the Javascript magic!
{
"privateClientId":{
"com.sample.validator.constraints.PrivateClientId":{
"message":"validation.privateClientId"
}
},
"sampleDistributionEmailAddress":{
"javax.validation.constraints.Size":{
"min":0,
"max":50,
"message":"{javax.validation.constraints.Size.message}"
},
"org.hibernate.validator.constraints.Email":{
"message":"validation.email"
}
},
"name":{
"org.hibernate.validator.constraints.NotEmpty":{
"message":"validation.mandatoryField"
}
},
"number":{
"javax.validation.constraints.Pattern":{
"flags":[
],
"message":"validation.client.number",
"regexp":"^\\d{8}$"
}
},
"group":{
"javax.validation.constraints.NotNull":{
"message":"validation.mandatoryField"
}
},
"difficultyLevel":{
"org.hibernate.validator.constraints.Range":{
"min":1,
"max":5,
"message":"{org.hibernate.validator.constraints.Range.message}"
}
}
"numberOfEmployees":{
"type":{
"type":"java.lang.Integer"
}
}
}