First, the mini version of the project is presented

@Data
public class User {
    @NotNull
    @Size(min = 1)
    private List<String> strings;
}

    @RequestMapping("")
    public User hello(@Validated @RequestBody User user) {
        user.setStrings(user.getStrings()
                            .stream()
                            .map(String::toUpperCase)
                            .collect(Collectors.toList()));
        return user;
    }
Copy the code

The User class is a data class, which contains a list of strings. The business logic is to return the String in the User class from lowercase to uppercase.

In the previous business code, only strings is not empty, and if the length is greater than 1, the verification can be passed.

But is it foolproof? I thought so, too, until one day the receptionist sent me this object

"strings": ["abc",null,"def"]
Copy the code

Then I got a NullPoint exception. So there’s a little bit of a checksum missing here, and even objects in the set can’t be empty!

What if an object in a collection can’t be empty? If you don’t want to put this validation in business code, there are two solutions:

1. Filter out null during conversion. 2. During verification, objects in the verification set are non-empty.Copy the code

1. Filter at transition time

Let’s first look at what happens if filtering is required during conversion? Directly on the code:

@configuration Public class GlobalConfiguration {@bean // Inject the FastJSON message converter into the Spring container (I prefer to use this, Public HttpMessageConvertersmessage(){
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
        FastJsonHttpMessageConverter fastJson = new FastJsonHttpMessageConverter();
        fastJson.setFastJsonConfig(fastJsonConfig);
        returnnew HttpMessageConverters(fastJson); } // Public class ListNotNullDeserializer implements ObjectDeserializer {@override @SuppressWarnings({"unchecked"."rawtypes" })
    public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
        if (parser.lexer.token() == JSONToken.NULL) {
            parser.lexer.nextToken(JSONToken.COMMA);
            return null;
        }

        Collection list = TypeUtils.createCollection(type);

        Type itemType = TypeUtils.getCollectionItemType(type); parser.parseArray(itemType, list, fieldName); // Filter out null objects in the collection on returnreturn (T) list.stream().filter(Objects::nonNull).collect(Collectors.toList());
    }

    @Override
    public int getFastMatchToken() {
        return0; }} / / above the collection of the need to filter added corresponding converter symbol @ JSONField (deserializeUsing = ListNotNullDeserializer. Class) private a List < String > strings;Copy the code

In this case, we get a list that has already been filtered out of null objects. At this time, the whole set of non-null checksum length check, you can ensure that no problem.

But to be honest, the front desk to transmit this kind of data, mostly their own logic problems, we eat the problem is not particularly appropriate. So we have to check and tell them what’s wrong.

Custom validator

In Springboot, I did not find an annotation that verifies that all objects in the collection are non-empty. So I guess I have to make one myself.

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
@Inherited
@Documented
@Constraint(validatedBy = NotNullEleValidator.class)
public @interface NotNullElement {
    String message() default "Null element in collection!"; Class<? >[] groups() default {}; Class<? extends Payload>[] payload() default {}; } public class NotNullEleValidator implements ConstraintValidator<NotNullElement, List<? >> { @Override public boolean isValid(List<? > value, ConstraintValidatorContext context) {if (value == null) {
            return true;
        }

        for (Object o : value) {
            if (o == null) {
                return false; }}return true; }}Copy the code

The custom verifier rule is also simple: by returning true, but not false, springBoot can retrieve the verifier information to decide whether to throw an exception.

It is important to note that the loading of the validator is done by the Spring framework, meaning that the validator can use classes in the Spring container. This feature is also useful.


Returns the directory