Java Bean Validation With Annotation

Introduction

 
As you know we can validate a Java Bean or a POJO with all its fields against the values. There are many ways we can do that. In earlier days we got the complete Java Bean and we would determine each and every field and getter or setter methods to validate the values. For example, to validate an email id we would obtain the Employee object and called the getter method for the email id and we validated the value against an email pattern. Currently, modern Java programming suggests the use of Java annotations in the field and method levels for bean validation. The best way to validate any Java Bean is to use the Hibernate POJO validator. Before going into validation, this article provides an outline of the usage of Java annotation in a Java Bean. Using this annotation we can have full control of the validation of the Java Bean.
 

Java Bean Validation With Annotation

 
According to a Wiki, an annotation is a kind of metadata that can be applied to classes, fields, methods, parameters etcetera, that can provide a meaningful inference of the functionality to be done. As you already know, some of the commonly used annotations are @Override, @Deprecated etcetera. You have also seen that when we write Javadocs we write @Author, @Since etcetera. However, all the annotations have a very specific precise meaning. In most of the cases, it increases readability, reduces redundant code and provides better performance. Most of the APIs currently adhere to the principles of annotation usage. Some of the critics also argue that it increases code complexity and is another form of hard-coding. It is the developer's responsibility to have a clear and pragmatic approach of annotation in their code. However, in this article, I will provide a basic structure of validation of Java Bean with annotation.
 
You know that while forming the object model for a specific purpose, we normally validate email id, credit card, mobile number, age verification, date of birth, empty characters or blank, min value, max value etcetera. I have seen many developers write their own code to validate email ids, mobile numbers etcetera. Sometimes it becomes difficult to maintain the code structure. In a particular project, you may find many Java Beans with common fields like email id and date of birth. These kinds of Java Beans are validated in various ways. In a project, there will be some developers that will work for a period of time but then they leave the project. The new developers may not be able to cope with the code structure so they re-write their way. Finally, we will have a pile of unnecessary code structure for the same functionality. Let us learn how to use your own annotation for the validation of a Java Bean.
 
Let us write a small Java Bean as in the following:
  1. public class Person1 {  
  2.     private String name;  
  3.     private String email;  
  4.     private String salary;  
  5.     // ~~ define getter and setter methods below  
  6. }  
In the above bean, we have validate an email id and the salary. As you see all the data types defined here are of String type. There are certain situations where you must define all the data types of the fields to String type. Since we will define our own annotations, we must use it in the fields of a Java Bean. Let us see a code structure where I have used annotations in the fields for validation. 
  1. public class Person {  
  2.     @Validate(value = Type.MOBILE)  
  3.     private String mobilePhone;  
  4.     @Validate(value = Type.URL)  
  5.     private String website;  
  6.     @Validate(value = Type.EMAIL)  
  7.     private String email;  
  8.     @Validate(value = Type.AGE)  
  9.     private String age;  
  10.     @Validate(value = Type.BLOODGROUP)  
  11.     private String bloodGroup;  
  12.     @Validate(value = Type.AMOUNT_DOUBLE)  
  13.     private String salary;  
  14.     // ~~ All getter and setter methods below  
  15.     public String getMobilePhone() {  
  16.         return mobilePhone;  
  17.     }  
  18.     public void setMobilePhone(String mobilePhone) {  
  19.         this.mobilePhone = mobilePhone;  
  20.     }  
  21.     public String getWebsite() {  
  22.         return website;  
  23.     }  
  24.     public void setWebsite(String website) {  
  25.         this.website = website;  
  26.     }  
  27.     public String getEmail() {  
  28.         return email;  
  29.     }  
  30.     public void setEmail(String email) {  
  31.         this.email = email;  
  32.     }  
  33.     public String getAge() {  
  34.         return age;  
  35.     }  
  36.     public void setAge(String age) {  
  37.         this.age = age;  
  38.     }  
  39.     public String getBloodGroup() {  
  40.         return bloodGroup;  
  41.     }  
  42.     public void setBloodGroup(String bloodGroup) {  
  43.         this.bloodGroup = bloodGroup;  
  44.     }  
  45.     public String getSalary() {  
  46.         return salary;  
  47.     }  
  48.     public void setSalary(String salary) {  
  49.         this.salary = salary;  
  50.     }  
  51. }  
As you see in the code above, the following things are important for the purposes of validation. The following fields have been annotated with custom annotations.
  1. @Validate(value = Type.MOBILE)  
  2. private String mobilePhone;  
  3.   
  4. @Validate(value = Type.URL)  
  5. private String website;  
  6.   
  7. @Validate(value = Type.EMAIL)  
  8. private String email;  
  9.   
  10. @Validate(value = Type.AGE)  
  11. private String age;  
  12.   
  13. @Validate(value = Type.BLOODGROUP)  
  14. private String bloodGroup;  
  15.   
  16. @Validate(value = Type.AMOUNT_DOUBLE)  
  17. private String salary;  
The structure of the annotations above is "Validate the field for the type(mobile number, URL, AGE, Email …))". The information is given to the field that, once the object is populated with data, all the data must be validated with the respective validation type. In other words, the email id field needs to be validated based on the Email type Type.Email.
 

How to do it

 
To do bean validation we must focus on the following four points:
  1. Define your own annotation
  2. Define the Type for the specific validation
  3. Define the actual code logic to validate
  4. Integrate with the validator
Let us define our own annotation, as in the following. The name of the annotation is "Validate" . The code is given below.
  1. @Target(ElementType.FIELD)  
  2. @Retention(RetentionPolicy.RUNTIME)  
  3. @Documented  
  4. public @interface Validate {  
  5.     public Type value();  
  6. }  
The preceding annotation can only be applied to the fields of the Java Bean since it is specified as "@Target(ElementType.FIELD)".
 
Let us define the type of validation. The code is given below.
  1. public enum Type {  
  2.     AMOUNT_DOUBLE, // For amount  
  3.     EMAIL,  
  4.     URL,  
  5.     MOBILE, //For Indian mobile number (10 digits mobile number with the correct format 9845-123456  
  6.     BLOODGROUP,  
  7.     AGE; // Age of a Person can not be less than 0 and can not be greater than 100  
  8. }  
The preceding is an "enum" type since it suggests the meaningful name. This enum type will be applied to validate annotation. In other words what to validate.
 
Let us define the actual logic for the validation. Let us consider the Indian mobile number validation. The code is given below.
  1. public static boolean isValidMobile(String mobile) {  
  2.     // Indian mobile number  
  3.     Pattern p = Pattern.compile("^[0-9]\\d{2,4}-\\d{6,8}$");  
  4.     Matcher m = p.matcher(mobile);  
  5.     return m.matches();  
  6. }  
The code above validates a mobile number against a regular expression. The actual format of the mobile number should be "9856-123456".
 
Finally, we must integrate it inside a generic validator. The structure of the validate method is given below.
  1. public void validate(Object obj) throws Exception {  
  2.     // Step 1. Find all the declared fields of the Java Bean  
  3.     //Step 2. Determine the annotations defined for that particular field.  
  4.     //Step 3. If it is our custom annotation "Validate", get the value ie type of annotation.  
  5.     //Step 4. Obtain the field value through Java reflection  
  6.     //Step 5. Apply the validation logic for that field value and return true or false.  
  7. }  
The brief code for the validation of the Java Bean is given below.
  1. public void validate(Object obj) throws Exception {  
  2.     Field[] fields = obj.getClass().getDeclaredFields();  
  3.     for (Field field: fields) {  
  4.         Annotation[] annotations = field.getAnnotations();  
  5.         for (Annotation annotation: annotations) {  
  6.             if (annotation instanceof Validate) {  
  7.                 Validate validator = (Validate) annotation;  
  8.                 if (field.getModifiers() == Modifier.PRIVATE) {  
  9.                     field.setAccessible(true);  
  10.                 }  
  11.                 boolean result = false;  
  12.                 String fieldValue = (String) field.get(obj);  
  13.                 switch (validator.value()) {  
  14.                     case AMOUNT_DOUBLE:  
  15.                         result = ValidationUtil  
  16.                             .isValidAmountDouble(fieldValue);  
  17.                         break;  
  18.                     case AGE:  
  19.                         result = ValidationUtil.isValidAge(fieldValue);  
  20.                         break;  
  21.                 }  
  22.                 if (!result) {  
  23.                     System.err.println("Validation failed due to invalid " + field.getName() + ": " + fieldValue);  
  24.                 }  
  25.             }  
  26.         }  
  27.     }  
  28. }  
The complete source code can be downloaded from the following location.
 
After downloading the zip file, extract it and configure the project in the Eclipse editor. You can also choose any Java IDE of your choice. Ensure that you configure this project as a Maven project. After making the proper configuration, try to run the Java class "TestPerson.java". You will get the following output.
 
Validation failed due to invalid email: john.p@gmailcom
Validation failed due to invalid age: 211
Validation failed due to invalid bloodGroup: O++
 

Conclusion

 
This article is only meant for the novice developer. It gives an insight into the use of custom annotation for bean validation. In the actual project or product development, it is always recommended to use the Hibernate bean validator. Follow my next article about the Hibernate bean validator. I hope you will enjoy my article. 
 
References
 
I provide the following the links for your further reference:


Similar Articles