Java simple verification framework
Status Quo of data verification framework
At the end of our method entry, we will inevitably see the following code:
Result. setSuccess (false); if (StringUtils. isBlank (bizOrder. getThirdOrder () {result. setResultMessage ("thirdOrder cannot be blank"); return result;} if (bizOrder. getThirdOrder (). length ()> 100) {result. setResultMessage ("thirdOrder is too long and must be within 100"); return result;} if (StringUtils. isBlank (bizOrder. getSku () {result. setResultMessage ("sku cannot be blank"); return result;} if (StringUtils. isBlank (bizOrder. getName () {result. setResultMessage ("name cannot be blank"); return result;} if (bizOrder. getName (). length ()> 20) {result. setResultMessage ("name Too Long"); return result;} if (bizOrder. getProvince () = 0 | bizOrder. getCity () = 0 | bizOrder. getCounty () = 0) {result. setResultMessage ("Incorrect address information"); return result;} if (StringUtils. isBlank (bizOrder. getAddress () {result. setResultMessage ("address cannot be blank"); return result ;}
This is obviously not good for a clean programmer. We need to be more elegant.
Well, it's a long time since JSR 303-Bean Validation
Its implementation is currently the most widely used:Hibernate Validator
Hiberante Validator, small, standard, easy to expand, easy to integrate.
But this article does not mean it...
For Web applications, we may still use Spring MVC verification, called spring mvc validator.
There are a lot of one hundred degrees, which can be well combined with the error tag of the page for page input validation.
But this article does not mean it...
This article mainly describes how to write a validation framework suitable for you.
The purpose of data framework design is simple
As a small toolkit, the code can be several K at most. It is also necessary to have no dependency.
The call method of if. else is too ugly. Let's take a look at the following:
New Validator (). notNull (name, "name"). notNull (mail, "email ");
Easy to use
Annotation is a good way to use it, just as JSR303 needs to be scalable.
The general design of the User-Defined checker should be easily created by the client program
First, you have to name MiniValidator.
It consists of two parts:
1. Annotation, parser, and validator used to annotate objects
Annotation, a group of annotations
Parser, annotation Parser, mainly used to process annotation Behavior
AnnotationValidator uses annotation and parser to verify the fields of the passed object
2. scalable checker
AnnotationRule annotation verification rule, used as the built-in rule
Rule is used for extension and can be customized.
Validator uses Rule to verify the data, or a built-in checker
Implement annotation Verification
First, writeAnnotationFor example, it cannot be blank:
@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface NotBlank { public String fieldName();}
Then, we need to annotateParser:
/*** Cannot be blank checker * @ author cdwangzijian **/public class notblkparser implements IAnnotationParser {/*** the value of field f cannot be null or a null string, check result saved in result */@ Override public ValidateResult validate (Field f, Object value) {ValidateResult result = new ValidateResult (); if (f. isAnnotationPresent (NotBlank. class) {NotBlank notBlank = f. getAnnotation (NotBlank. class); if (value = null | value. toString (). length () = 0) {result. setMessage (notBlank. fieldName () + "cannot be blank") ;}} return result ;}}
The following uses the above contentAnnotation validator:
/*** Annotation validator * @ author cdwangzijian **/public class AnnotationValidator {private static final Logger log = Logger. getLogger (AnnotationValidator. class. getName (); private final static List
VList = new ArrayList
(); Static {vList. add (new NotNullParser (); vList. add (new notblkparser ();}/*** traverses all fields and uses all Resolvers for verification. If the verification fails, the verification result is terminated. If the verification succeeds, similarly, the verification result * @ param t * @ return */public static is returned.
ValidateResult validate (T t) {ValidateResult result = null; for (Field f: t. getClass (). getDeclaredFields () {f. setAccessible (true); Object value = null; try {value = f. get (t);} catch (IllegalArgumentException e) {log. log (Level. SEVERE, "Exception", e);} catch (IllegalAccessException e) {log. log (Level. SEVERE, "Exception", e) ;}for (IAnnotationParser va: vList) {result = va. validate (f, value ); If (! Result. isValid () {return result ;}} return result;}/*** register the parser * @ param parser */public static void register (IAnnotationParser parser) {vList. add (parser );}}
You can see that the checker has registered Multiple Resolvers. Then, all the parser checks the value of each field for the input object to obtain the verification result.
Write a test program:
Class User {private Long id; @ NotBlank (fieldName = "name") private String name; @ Less (fieldName = "age", value = 100) private int age; private String phone; private String birthday; public Long getId () {return id;} public void setId (Long id) {this. id = id;} public String getName () {return name;} public void setName (String name) {this. name = name;} public int getAge () {return age;} public void setAge (int age) {this. age = age;} public String getPhone () {return phone;} public void setPhone (String phone) {this. phone = phone;} public String getBirthday () {return birthday;} public void setBirthday (String birthday) {this. birthday = birthday;} public class TestAnnotationValidator {public static void main (String [] args) {User user = new User (); ValidateResult result = AnnotationValidator. validate (user); if (result. isValid () {System. out. println ("verified");} else {System. out. println (result. getMessage ());}}}
Output result:
Name cannot be blank
Extended annotation validator
Based on this framework, it is easier to expand.
Write a new annotation, a new parser, and register a new parser to verify the new field. As follows:
New Annotation:
@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface DateFormat { public String fieldName(); public String format();}
New parser
/*** Date Format annotation parser ** @ author cdwangzijian **/public class DateFormatParser implements IAnnotationParser {/*** verify that the value of field f complies with the date format of value *@ see DateFormat */@ Override public ValidateResult validate (Field f, object value) {ValidateResult result = new ValidateResult (); if (f. isAnnotationPresent (DateFormat. class) {DateFormat dateFormat = f. getAnnotation (DateFormat. class); try {if (value! = Null) {SimpleDateFormat format = new SimpleDateFormat (dateFormat. format (); format. parse (value. toString () ;}} catch (ParseException e) {result. setMessage (dateFormat. fieldName () + "unsupported format:" + dateFormat. format () ;}} return result ;}}
Test programs using extended Annotations:
Public class TestAnnotationValidator {public static void main (String [] args) {User user = new User (); user. setName ("wzj"); user. setAge (21); user. setBirthday ("20150525"); AnnotationValidator. register (new DateFormatParser (); ValidateResult result = AnnotationValidator. validate (user); if (result. isValid () {System. out. println ("verified");} else {System. out. println (result. getMessage ());}}}
Result:
Birthday does not meet the format: yyyy-MM-dd
Well, there are so many annotations.
General Verification
The common verification part is an interface Rule, which is provided to the validator for calling:
/*** Verification Rule, used to extend the verification Rule * @ author cdwangzijian **/public interface Rule {public String getMessage (); public boolean isValid ();}
Use the Rule validator:
/*** Common Validator * @ author cdwangzijian **/public class Validator {public Validator validate (Rule rule) {if (this. isValid) {this. isValid = rule. isValid (); this. message = rule. getMessage () ;}return this;} public Validator validateAnnotation (Object o) {return validate (new AnnotationRule (o);} public Validator notNull (Object fieldValue, String fieldName) {if (this. isValid) {if (fieldValue = null) {this. isValid = false; this. message = fieldName + "cannot be blank";} return this;}/*** valid? * @ return * true: the verification is successful, valid value * error message not verified by message */public boolean isValid () {return isValid;} public String getMessage () {return message;} private boolean isValid = false; // whether the private String message is valid; // error message}
In addition to using Rule, this class also has built-in notXX methods to return this, so that the structure of. notXX () can be used for verification.
To test:
Public class TestValidator {public static void main (String [] args) {testMethod ("name", null);} public static void testMethod (String name, String mail, string thirdOrderId, String address) {Validator v = new Validator (). notNull (name, "name "). notNull (mail, "email "). notNull (address, "address"); if (v. isValid () {System. out. println ("verified");} else {System. out. println (v. getMessage ());}}}
Result:
Email cannot be blank
Extended universal checker
The extension requires the implementation of the Rule interface. The following describes how to implement a Rule based on AnnotationValidator:
/*** Use AnnotationValidator's validation rules ** @ see AnnotationValidator * @ author cdwangzijian **/public class AnnotationRule implements Rule {private String message; private Object o; public AnnotationRule (Object o) {this. o = o ;}@ Override public String getMessage () {return message ;}@ Override public boolean isValid () {ValidateResult result = AnnotationValidator. validate (this. o); this. message = result. getMessage (); return result. isValid ();}}
Then rule:
public class TestValidator { public static void main(String[] args) { new Validator().validate(new AnnotationRule(new User())); }}
Summary
At this point, this simple verification framework is complete.
Annotations are mainly used technically,
Then, through reflection, use the annotation Parser for resolution verification.
Each method of the validator returns this, and more elegant code can be used to complete the verification.
It can also be easily expanded.
Complete code, which can be obtained from here