How to Use Reflection for Parametric Validation

Parametric Validation Introduction:

How to Use Reflection for Parametric Validation. You may have questions, why not use the `@Valid` annotation! Brothers, I want to use it too! But no way! due to the nature of the project. The project will connect with various channel parties, but all channel parties use the same entity for transmission (universal), but each channel party has different effects on the field that must be transmitted (the user is God)

Parametric Validation.Foreword

Why does this feature appear!
You may have questions, why not use the @Valid annotation! Brothers, I want to use it too! But no way! due to the nature of the project. The project will connect with various channel parties, but all channel parties use the same entity for transmission (universal), but each channel party has different effects on the field must be transmitted (the user is God). For example, there are a, b, c attributes in a public entity. The AA channel only transmits the a and b attributes, and the c attribute cannot be given, so we can only pass the a and b attributes to the AA channel. Then the BB channel party gives the b and c attributes, then we can only do the mandatory transmission effect for the b and c attributes for the BB channel. It is also impossible to use if/else to judge one by one. If there are too many field attributes, it will be cold . Based on this scenario, the use of reflection as an effect appears.
import lombok.extern.slf4j.Slf4j ;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Objects;

@Slf4j
public class CheckUtil {

/**
* The validation property type is Object
* @param sourceObject source object
* @param checkFields set of fields that need to be validated
* @param sourceObject
* @param checkFields
* @return
*/
public static String checkObjNull ( Object sourceObject , List checkFields ) {
if ( Objects.isNull ( sourceObject )){
return "Please enter the correct source object" ;
}
if ( CollectionUtils.isEmpty ( checkFields )){
return "Validation field cannot be empty" ;
}
Class objClass = sourceObject.getClass ();
// Get all attribute objects of this class
Field[ ] declaredFields = objClass.getDeclaredFields ();
if ( null == declaredFields || declaredFields.length == 0 ){
return "No attribute in source object" ;
}

StringBuilder sb = new StringBuilder( );
for (String checkField : checkFields ) {
for (Field field : declaredFields ) {
//Close the security check of the program
field.setAccessible ( true );
// If the validation field is equal to the property name, it will be validated
String fieldName = field.getName ();
if ( checkField.equals ( fieldName )){
try {
// get field property value
Object fieldValue = field.get ( sourceObject );
// If the field attribute value is null or "" string, it is considered that the field has no value
if(Objects.isNull(fieldValue) || StringUtils.isEmpty(fieldValue.toString())){
sb = sb.append("[").
append(fieldName).
append("]").
append("为必传字段");
return sb.toString ();
}
} catch ( IllegalAccessException e) {
log.error ( "Error getting attribute value" ,e);
return "Please check the passed source object" ;
}
}
}
}
// pass validation
return null ;
}

/**
* Valid property type is List
* @param sourceObject source object
* @param checkFields set of fields that need to be validated
* @param listPropertyName The property name of the source object
* @return
*/
public static String checkArrayNull(Object sourceObject, List checkFields,String listPropertyName){
if(Objects.isNull(sourceObject)){
return "
Please enter the correct source object";
}
if(CollectionUtils.isEmpty(checkFields)){
return "Validation field cannot be empty" ;
}
if ( sourceObject instanceof List){
List list = (List) sourceObject ;
if ( CollectionUtils.isEmpty (list)){
return listPropertyName + "Required field" ;
}
for (Object obj : list) {
String resultStr = checkObjNull ( obj, checkFields );
return resultStr ;
}
}
return null ;
}
}
Well, the tool class has been written. How to use it!

Parametric Validation.Use



Import dependencies


org.springframework.boot
spring-boot-starter-web


org.projectlombok
lombok



io.springfox
springfox-swagger2
2.9.2



io.springfox
< artifactId > springfox- swagger- ui
< version > 2.9.2



Parametric Validation.DTO



Create three classes, UserInfoDTO , BankCardDTO , IdCardDTO
•UserInfoDTO : user information
@Data
@ApiModel ( " UserInfo " )
public class UserInfoDTO {

@ApiModelProperty ( "User Unique Number " )
private Long userId ;

@ApiModelProperty ( " Name" )
private String name;

@ApiModelProperty ( "Bank Card List Information " )
private List< BankCardDTO > cardDTOList ;

@ApiModelProperty ( "ID Information " )
private IdCardDTO idCardDTO ;
}
•BankCardDTO : Bank card list information
@Data
@ApiModel ( " Bank Card List" )
public class BankCardDTO {

@ApiModelProperty ( "card number " )
private String cardNumber ;

@ApiModelProperty ( " Bank Name" )
private String bankName ;

}
•IdCardDTO : ID card information
@Data
@ApiModel ( "ID Information " )
public class IdCardDTO {

@ApiModelProperty ( " document number" )
private String idNumber ;
@ApiModelProperty ( "Expiration Date " )
private String validity;
}

Parametric Validation.Controller



Then create a class named TestController , provide a saveUser method, and call the written tool class in the method.
@PostMapping ( value = " / saveUser " )
private String saveUser ( @RequestBody _ UserInfoDTO req) {
//validate user information
String check = CheckUtil.checkObjNull (req, Arrays.asList ( " userId " , "name" , " cardDTOList " , " idCardDTO " ));
if ( StringUtils.hasLength (check)){
return check;
}
//Validate the bank card list in the user information
List cardDTOList = req.getCardDTOList();
String check2 = CheckUtil.checkArrayNull(cardDTOList, Arrays.asList("cardNumber", "bankName"),"cardDTOList");
if(StringUtils.hasLength(check2)){
return check2;

}
//Validate the ID information in the user information
IdCardDTO idCardDTO = req.getIdCardDTO ();
String check3 = CheckUtil.checkObjNull ( idCardDTO , Arrays.asList ( " idNumber " , "validity" ));
if ( StringUtils.hasLength (check3)){
return check3;
}
return "success" ;
}


Parametric Validation.Call method



Request address: localhost: 8080 / api / saveUser
{
" userId " : "1" ,
"name" : "1" ,
" cardDTOList " : [
{
" cardNumber " : "5" ,
" bankName " : ""
}
],
" idCardDTO " : {
" idNumber " : "55" ,
"validity" : "4"
}
}
response:
[ bankName ] is a required field
In our project group this effect is good enough to use. Because we don't directly interface with the front end, we only need to send the response to the docking party. Some small partners may directly connect to the front end and display the response information on the front end. That is definitely not possible, how do users know that [ bankName ] is a required field ! It must be prompted in Chinese, for example: [Bank Name] is a required field .


Parametric Validation.Optimization of prompt information



If you want to prompt Chinese! There is also a way. You may have noticed that I imported the dependencies of swagger , one of which is annotated @ ApiModelProperty , which is written on each property and provides description information for each property, so we can take the value of this annotation.
public static String checkObjNull ( Object sourceObject , List checkFields ) {
if ( Objects.isNull ( sourceObject )){
return "Please enter the correct source object" ;
}
if ( CollectionUtils.isEmpty ( checkFields )){
return "Validation field cannot be empty" ;
}
Class objClass = sourceObject.getClass ();
// Get all attribute objects of this class
Field[ ] declaredFields = objClass.getDeclaredFields ();
if ( null == declaredFields || declaredFields.length == 0 ){
return "No attribute in source object" ;
}

StringBuilder sb = new StringBuilder( );
for (String checkField : checkFields ) {
for (Field field : declaredFields ) {
//Close the security check of the program
field.setAccessible ( true );
// If the validation field is equal to the property name, it will be validated
String fieldName = field.getName ();
// get the specified annotation
ApiModelProperty apiModelProperty = field.getAnnotation ( ApiModelProperty.class ) ; _ _
// Get the value of the value attribute
String value = apiModelProperty.value ();
if ( checkField.equals ( fieldName )){
try {
// get field property value
Object fieldValue = field.get ( sourceObject );
// If the field attribute value is null or "" string, it is considered that the field has no value
if ( Objects.isNull ( fieldValue ) || StringUtils.isEmpty ( fieldValue.toString ())){
sb = sb.append ( "[" ).
append(value).
append( "]" ).
append( "It is a mandatory field" );
return sb.toString ();
}
} catch ( IllegalAccessException e) {
log.error ( "Error getting attribute value" ,e);
return "Please check the passed source object" ;
}
}
}
}
// pass validation
return null ;
}

Call the method again

Request address: localhost: 8080 / api / saveUser
{
" userId " : "1" ,
"name" : "1" ,
" cardDTOList " : [
{
" cardNumber " : "5" ,
" bankName " : ""
}
],
" idCardDTO " : {
" idNumber " : "55" ,
"validity" : "4"
}
}
response:
[Bank Name] is a required field

Related Articles

Explore More Special Offers

  1. Short Message Service(SMS) & Mail Service

    50,000 email package starts as low as USD 1.99, 120 short messages start at only USD 1.00