Dubbo annotation method verification method parameters

Posted by cqinzx on Sun, 23 Jan 2022 11:17:58 +0100

Spring MVC annotation parameter verification support

Introduction:

JSR provides a set of API for Bean verification specification, which is maintained in the package javax validation. Constraints. The specification uses a set of concise and easy-to-use annotations on attribute or method parameters or classes for parameter verification. During the development process, developers only need to add notes such as @ notnull, @ notempty and @ email where verification is required, and they can delegate the task of parameter verification to some third-party verification frameworks.

From network:

JSR-303 is a sub specification in JAVA EE 6, called Bean Validation. The official reference implementation is Hibernate Validator.
This implementation has nothing to do with Hibernate ORM. JSR 303 is used to validate the value of a field in a Java Bean.
Spring MVC 3. JSR-303 is also strongly supported in X, which can easily verify the data submitted by the form in the controller.

In spring MVC, you only need to annotate the method parameter quotient with the @ Valid annotation. Spring MVC can verify the parameter object, and the verification results will be placed in the BindingResult object. In addition to @ Valid, the @ Validated annotation supports grouping verification of parameters. Their differences:

  • @Valid: there is no grouping function.
  • @Valid: can be used on methods, constructors, method parameters, and member properties (fields)
  • @Validated: it provides a grouping function. Different validation mechanisms can be used according to different groups during parameter validation
  • @Validated: can be used on types, methods, and method parameters. However, it cannot be used on member properties (fields)

Whether the two can be used on member properties (fields) directly affects whether nested verification can be provided

Nested validation

See the figure below:
For example, we now have an entity called Item:

public class Item {

    @NotNull(message = "id Cannot be empty")
    @Min(value = 1, message = "id Must be a positive integer")
    private Long id;

    @NotNull(message = "props Cannot be empty")
    @Size(min = 1, message = "There must be at least one attribute")
    private List<Prop> props;
}

Item has many attributes, including pid, vid, pidName and vidName, as shown below:

public class Prop {

    @NotNull(message = "pid Cannot be empty")
    @Min(value = 1, message = "pid Must be a positive integer")
    private Long pid;

    @NotNull(message = "vid Cannot be empty")
    @Min(value = 1, message = "vid Must be a positive integer")
    private Long vid;

    @NotBlank(message = "pidName Cannot be empty")
    private String pidName;

    @NotBlank(message = "vidName Cannot be empty")
    private String vidName;
}

The attribute entity also has its own verification mechanism. For example, pid and vid cannot be empty, pidName and vidName cannot be empty, etc.
Normally, the Spring Validation framework will only verify the non null and quantity of Item id and props, and will not verify the props entity in the props field.
How to perform nested verification?
In order to perform nested validation, you must manually specify in the props field of the Item entity that the entities in this field should also be Validated. Since @ Validated cannot be used on member attributes (fields), but @ Valid can be added on member attributes (fields), and the annotation of @ Valid class also indicates that it supports nested validation function, we can infer that @ Valid can not be used for nested validation automatically when it is added to method parameters, but is used on corresponding fields of classes requiring nested validation, To cooperate with @ Validated or @ Valid on method parameters for nested validation.

Modify the Item class as follows:

public class Item {

    @NotNull(message = "id Cannot be empty")
    @Min(value = 1, message = "id Must be a positive integer")
    private Long id;

    @Valid // Nested validation must use @ Valid
    @NotNull(message = "props Cannot be empty")
    @Size(min = 1, message = "props There must be at least one custom attribute")
    private List<Prop> props;
}

In addition to the above common @ NotNull, @ Min, @ NotBlank and @ Size verification annotations, we can also customize the verification annotations~

Custom verification

An example is given to illustrate the implementation of user-defined annotation: a user-defined annotation is required to verify that the input parameter name cannot have the same name as the existing name

1. User defined annotation

@Target({ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UniqueConstraintValidator.class)
public @interface UniqueConstraint {

    //The following three attributes are mandatory

    String message();

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

2. Create a UniqueConstraintValidator class to validate the annotation

//Verification logic of custom verification annotation
//There is no need to annotate @ Component, because the ConstraintValidator interface is implemented and automatically registered as a spring bean
public class UniqueConstraintValidator implements ConstraintValidator<UniqueConstraint,Object> {

    @Autowired
    private UserService userService;

    @Override
    public void initialize(UniqueConstraint uniqueConstraint) {
        System.out.println("my validator init");
    }

    //Object is the field type of verification
    //If true is returned, the verification is successful
    //o is the value of the verification field, and constraintValidatorContext is the attribute value in the verification annotation
    @Override
    public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
        String username = (String) o;
        TbUser user = userService.findByUsername(username);
        return user==null?true:false;
    }
}
  • The UniqueConstraintValidator class must implement the initialize method of the ConstraintValidator interface and the isValid validation method

  • The specific verification logic is verified in isValid method

When using, mark the annotation on the required field:

Dubbo RPC parameter verification

So, as a domestic excellent open source RPC framework, does Dubbo support annotation verification parameters? The answer is, of course, yes~

ValidationFilter


ValidationFilter invokes validation by finding the correct {Validator} instance according to the validation property value configured by the caller url before the actual method call.
How ValidationFilter is called is not mentioned here, but to be effective, you need to configure it on the consumer or provider side:

consumer:

   @DubboReference(validation = "true")
    private DemoService demoService;

or
provider:

@DubboService(validation = "true")
public class DemoServiceImpl implements DemoService {

Note: if parameter verification is enabled on the consumer, rpc calls will not be initiated to the server if it fails, but the verification exception ConstraintViolationException should be handled by yourself

Validator validator

The validator used by the default ValidationFilter is shown in the following figure

JValidation implementation code is still relatively small

/**
 * Creates a new instance of {@link Validator} using input argument url.
 * @see AbstractValidation
 * @see Validator
 */
public class JValidation extends AbstractValidation {

    /**
     * Return new instance of {@link JValidator}
     * @param url Valid URL instance
     * @return Instance of JValidator
     */
    @Override
    protected Validator createValidator(URL url) {
        return new JValidator(url);
    }

}

You can see that the actual work is org apache. dubbo. validation. support. jvalidation. JValidator

You can see a @ MethodValidated annotation in its validate method

Click open to view its comments

It can be understood that this annotation supports group verification in marking methods!

Simple example:

Consumer code:

@Component("demoServiceComponent")
public class DemoServiceComponent implements DemoService {
    
    @DubboReference(validation = "true")
    private DemoService demoService;

    @Override
    public String sayHello(String name) {
        return demoService.sayHello(name);
    }

    @Override
    public String sayGoodBye(Content content) {
        return demoService.sayGoodBye(content);
    }

    @Override
    public CompletableFuture<String> sayHelloAsync(String name) {
        return null;
    }
}

dubbo client interface:

public interface DemoService {

    String sayHello(String name);

    @MethodValidated({TestGroup.class})
    String sayGoodBye(Content content);

    default CompletableFuture<String> sayHelloAsync(String name) {
        return CompletableFuture.completedFuture(sayHello(name));
    }

}

Method input parameter Content:

public class Content implements Serializable {

    @NotNull(message = "name Cannot be empty",groups = {TestGroup.class})
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Note: the verification annotation without groups will also be verified as the default group

Topics: Dubbo