Validation of a list of objects in Spring

后端 未结 12 1210
無奈伤痛
無奈伤痛 2020-11-28 05:30

I have the following controller method:

@RequestMapping(value=\"/map/update\", method=RequestMethod.POST, produces = \"application/json; charset=utf-8\")
@Re         


        
相关标签:
12条回答
  • 2020-11-28 05:43

    The @Valid annotation can be used inside the diamond operator:

    private List<@Valid MyType> types;
    

    or

    @Valid
    private List<MyType> types;
    

    Now, every list item will be validated.

    0 讨论(0)
  • 2020-11-28 05:48

    I'm using spring-boot 1.5.19.RELEASE

    I annotate my service with @validated and then apply @Valid to the List parameter in the method and items in my list get validated.

    Model

    @Data
    @ApiModel
    @Validated
    public class SubscriptionRequest {
        @NotBlank()
        private String soldToBpn;
    
        @NotNull
        @Size(min = 1)
        @Valid
        private ArrayList<DataProducts> dataProducts;
    
        private String country;
    
        @NotNull
        @Size(min = 1)
        @Valid
        private ArrayList<Contact> contacts;
    }
    

    Service Interface (or use on concrete type if no interface)

    @Validated
    public interface SubscriptionService {
        List<SubscriptionCreateResult> addSubscriptions(@NonNull @Size(min = 1) @Valid List<SubscriptionRequest> subscriptionRequestList)
            throws IOException;
    }
    

    Global Exception Handler method (ApiError Type is not my design)

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = ConstraintViolationException.class)
    @ResponseBody
    public ApiError[] handleConstraintViolationException(ConstraintViolationException exception) {
        List<InvalidField> invalidFields = exception.getConstraintViolations().stream()
            .map(constraintViolation -> new InvalidField(constraintViolation.getPropertyPath().toString(),
                                                         constraintViolation.getMessage(),
                                                         constraintViolation.getInvalidValue()))
            .collect(Collectors.toList());
        return new ApiError[] {new ApiError(ErrorCodes.INVALID_PARAMETER, "Validation Error", invalidFields)};
    }
    

    example bad method call from a controller

     LinkedList<SubscriptionRequest> list = new LinkedList<>();
     list.add(new SubscriptionRequest());
     return subscriptionService.addSubscriptions(list);
    

    Response body (note the index [0])

    [
        {
            "errorCode": "invalid.parameter",
            "errorMessage": "Validation Error",
            "invalidFields": [
                {
                    "name": "addSubscriptions.arg0[0].soldToBpn",
                    "message": "may not be empty",
                    "value": null
                },
                {
                    "name": "addSubscriptions.arg0[0].dataProducts",
                    "message": "may not be null",
                    "value": null
                },
                {
                    "name": "addSubscriptions.arg0[0].contacts",
                    "message": "may not be null",
                    "value": null
                }
            ]
        }
    ]
    
    0 讨论(0)
  • 2020-11-28 05:51

    I think the most elegant solution is to create a custom Validator for Collection and a @ControllerAdvice that registers that Validator in the WebDataBinders, take a look to Spring validation for RequestBody parameters bound to collections in Controller methods

    0 讨论(0)
  • 2020-11-28 05:55

    I would suggest to wrap your List categories into some DTO bean and validate it. Beside of working validation you will benefit from more flexible API.

    @RequestMapping(value="/map/update", method=RequestMethod.POST, produces = "application/json; charset=utf-8")
    @ResponseBody
    public ResponseEntityWrapper updateMapTheme(
        HttpServletRequest request, 
        @RequestBody @Valid TagRequest tagRequest,
        HttpServletResponse response
        ) throws ResourceNotFoundException, AuthorizationException {
    ...
    }
    
    public static class TagRequest {
        @Valid
        List<CompanyTag> categories;    
        // Gettes setters
    }
    
    0 讨论(0)
  • 2020-11-28 05:55

    Validating a collection does not work directly.

    For example: what should it do if multiple elements fail the validation? Stop after first validation? Validate all (if so what is to be done with the collection of messages)?

    If in your configuration Spring delegates to a Bean Validator provider like Hibernate Validator, you should look up for ways of implementing a collection validator there.

    For Hibernate, a similar problem is discussed here

    0 讨论(0)
  • 2020-11-28 06:00

    use @Validated annotate controller
    use @Valid annotate @RequestBody

    0 讨论(0)
提交回复
热议问题