Validating Models and User Inputs in Java
How to create model validations in Java?
While working on an Android application that I developed, I felt a strong need to implement validations on the client side i.e. the Android application, although the Server does implement all the validations. But I feel if we can validate inputs on the client itself it would help us save a lot of things like:
Why validate data on the client-side?
- Time – A request takes time to return the response, which is dependent upon the speed of the internet connection. So if a user is making a request with a bad input, (s)he will still have to wait unnecessarily. Alternatively, if a validation prevents that request from being executed, this time can be saved.
- Data / Bandwidth – Nowadays, a lot of users tend to use applications on the go, which in turn consumes their cellular data. But remember with great data comes great cost, so why use someone's data unnecessarily when we can very easily save it?
Now that the problem is evident, we must do something to cater to users' needs. If you’ve ever thought about this problem, you are a good programmer who not just wants to write and deliver code but also wants to use resources the codes runs on “very judiciously.”
Validating null checks for required fields
The solution(s):
The first solution that I could think about was to write a method in each model to check if the fields that you want should be required should not be null. Something like this:
public class User {
private Integer id;
private String firstName;
private String sex; // I'm ready when you are :P
/**
* ... All Your Getters and Setters Here
*/
public boolean validate() {
if (this.firstName == null) {
return false;
}
if (this.sex == null) {
return false;
}
return true;
}
The validate method can be called each time you are about to throw the object to the server for some processing, and if it returns true
, you can go ahead. Else you must check for the problem and do the needful to pass the validation.
This is the most basic solution anyone would follow, but this brings in a lot of overhead of code, time and effort. Imagine writing your validate method for a project that has over 100 models with 5 required fields in each of them. From a broader view, you’ll write no less than 1700 lines of code just for your validations and all that is repetitive.
The second solution that I came up with was to find out a way to make the fields required by some means, and check at runtime if the required fields have been initialised or not.
I then deep dived into the Reflections and Annotations Frameworks provided in java. I followed this approach:
- Write an Annotation called Required
that has a boolean value which is by default true
.
- Now declare the required fields in a model as
@Required
- After this, I wanted a centralised class where I could pass a Model object that has to be validated and then using the
Reflections
framework iterate over all the fields, and check if the field has a@Required
annotation on it and then check whether it is still null or not. If it is, then I would throw an Exception. If not and the loop ends without any troubles, I’ll returntrue
. Here’s how I have implemented this for my Android App, I have a model calledProfile
in which I have three fields that can never beNull
whenever aProfile
is created i.e.fName
,description
andpictureUrl
. So all of them have a@Required
annotation on them.
public class Profile {
private Integer id;
@Required
private String fName;
private String lName;
@Required
private String description;
private String dateOfBirth;
@Required
private String pictureUrl;
/**
* Getter and Setter methods written here
*/
}
Now here is what my Annotation declaration looks like
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Required {
public boolean value() default true;
}
Now I wrote a Validator class that will have my implementation of the validate method, and it can be applied for any model throughout my app. This uses Reflections framework.
public class Validator {
public static boolean validateForNulls(Object objectToValidate)
throws RequiredFieldException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
/**
* Get all the fields of the class
*/
Field[] declaredFields = objectToValidate.getClass().getDeclaredFields();
/**
* Iterate over each field to check if that field
* has the "Required" annotation declared for it or not
*/
for(Field field : declaredFields) {
Annotation annotation = field.getAnnotation(Required.class);
/**
* Check if the annotation is present on that field
*/
if (annotation != null) {
Required required = (Required) annotation;
/**
* Check if it says this field is required
*/
if (required.value()) {
/**
* Now we make sure we can access the private
* fields also, so we need to call this method also
* other wise we would get a {@link java.lang.IllegalAccessException}
*/
field.setAccessible(true);
/**
* If this field is required, then it should be present
* in the declared fields array, if it is throw the
* {@link RequiredFieldException}
*/
if (field.get(objectToValidate) == null) {
throw new RequiredFieldException(objectToValidate.getClass().getName()+"."+field.getName());
}
}
}
}
return true;
}
}
And this is how I have declared my own Exceptions. This can be quite useful in the cases where you want to inform the user about some validation errors.
public class ShowableException extends Exception {
public void notifyUserWithToast(Context context) {
Toast.makeText(context, toString(), Toast.LENGTH_SHORT).show();
}
}
public class RequiredFieldException extends ShowableException{
private String fieldName;
private String localisedErrorMessage;
public RequiredFieldException(String fieldName, String localisedErrorMessage) {
this.fieldName = fieldName;
this.localisedErrorMessage = localisedErrorMessage;
}
public RequiredFieldException(String fieldName) {
this.fieldName = fieldName;
}
@Override
public String toString() {
return this.getClass().getName() + "\n" + fieldName + " " + (localisedErrorMessage != null ? localisedErrorMessage : " cannot be null") ;
}
}
Usage:
Profile profile = new Profile();
profile.setDescription("The Product Guy");
try {
if (Validator.validateForNulls(profile)) {
// Do something that you want to
Log.d(TAG, "Validations Successful");
}
} catch (RequiredFieldException | ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
// Inform user about his SINS
e.printStackTrace();
}
This solution for sure saves a lot of time, effort and code that I would have spent while writing a validator for each class.
Hope you found this tutorial useful!
i think its usefull maybe you could add also other validations for example max min or type checks too
Nice tutorial