2017년 1월 31일 화요일

JSR-303 (bean validation) and validating collection for Spring


SpringBoot를 쓰면 RequestBody나 ModelAttribute로 Json을 객체에 그대로 바인딩하면서 유효성 체크까지 할 수 있다.

이때 기본적인 Validator는 Collection 형태의 객체는 유효성을 체크하지 않는데 이걸 해주게끔 Validator를 구현했다.


import org.springframework.beans.BeanUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;


public class JSR303CollectionListValidator implements Validator {

    private final Validator validator;

    public JSR303CollectionListValidator(LocalValidatorFactoryBean localValidatorFactoryBean) {
        this.validator = localValidatorFactoryBean;
    }

    @Override    
    public boolean supports(Class clazz) {
        return clazz.isAssignableFrom(clazz);
    }

    @Override    
    public void validate(Object target, Errors errors) {
        ValidationUtils.invokeValidator(validator, target, errors);

        if(!target.getClass().isPrimitive()){
            PropertyDescriptor[] propertyDescriptors  = BeanUtils.getPropertyDescriptors(target.getClass());

            for(PropertyDescriptor descriptor : propertyDescriptors){
                if(List.class.isAssignableFrom(descriptor.getPropertyType())){
                    Method method = descriptor.getReadMethod();

                    try {
                        Object object = method.invoke(target);

                        if(!Objects.isNull(object)){
                            List typeOfObject = (List) object;

                            for(Object resource : typeOfObject){
                                validate(resource, errors);
                            }
                        }
                    } catch (IllegalAccessException | InvocationTargetException e) {
                        FieldError error = new FieldError(target.getClass().getSimpleName(), descriptor.getName()
                              , "List 형태의 하위 정보에 대한 validation에 실패하였습니다");
                        errors.getFieldErrors().add(error);
                    }
                }
            }
        }
    }
}


Spring에서 간단히 DataBind에 등록만 해주면 된다.


@ControllerAdvice
public class WebDataBindHandler {

    @Inject
    private LocalValidatorFactoryBean localValidatorFactoryBean;

    @InitBinder
    void initBinder(WebDataBinder binder) {
        binder.addValidators(new JSR303CollectionListValidator(localValidatorFactoryBean));
    }
}

댓글 없음:

댓글 쓰기