복붙노트

[SPRING] 컨트롤러없이 잭슨으로 객체를 만들 때 유효합니다.

SPRING

컨트롤러없이 잭슨으로 객체를 만들 때 유효합니다.

프런트 엔드에서 요청을 보낼 때 내 컨트롤러에서 @Valid를 사용하여 유효성을 검사하는 모델이 있습니다.

@NotNull
@Size(min=1, message="Name should be at least 1 character.")
private String name;

@NotNull
@Pattern(regexp = "^https://github.com/.+/.+$", message = "Link to github should match https://github.com/USER/REPOSITORY")
private String github;

하지만 이제 컨트롤러없이 Jackson의 ObjectMapper를 사용하여 객체를 만듭니다. ObjectMapper에이 유효성 검사를 등록하는 방법이 있습니까? 아니면 설정자의 변수를 확인해야합니까?

해결법

  1. ==============================

    1.비 직렬화를 확장하고 비 직렬화 후에 객체의 유효성을 검사 할 수 있습니다. 이 Bean을 등록하려면 SimpleModule을 사용하십시오.

    비 직렬화를 확장하고 비 직렬화 후에 객체의 유효성을 검사 할 수 있습니다. 이 Bean을 등록하려면 SimpleModule을 사용하십시오.

    유효성 검증이있는 단순한 콩 디시리얼라이저 :

    class BeanValidationDeserializer extends BeanDeserializer {
    
        private final static ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        private final Validator validator = factory.getValidator();
    
        public BeanValidationDeserializer(BeanDeserializerBase src) {
            super(src);
        }
    
        @Override
        public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            Object instance = super.deserialize(p, ctxt);
            validate(instance);
    
            return instance;
        }
    
        private void validate(Object instance) {
            Set<ConstraintViolation<Object>> violations = validator.validate(instance);
            if (violations.size() > 0) {
                StringBuilder msg = new StringBuilder();
                msg.append("JSON object is not valid. Reasons (").append(violations.size()).append("): ");
                for (ConstraintViolation<Object> violation : violations) {
                    msg.append(violation.getMessage()).append(", ");
                }
                throw new ConstraintViolationException(msg.toString(), violations);
            }
        }
    }
    

    다음과 같이 사용할 수 있습니다.

    import com.fasterxml.jackson.core.JsonParser;
    import com.fasterxml.jackson.databind.BeanDescription;
    import com.fasterxml.jackson.databind.DeserializationConfig;
    import com.fasterxml.jackson.databind.DeserializationContext;
    import com.fasterxml.jackson.databind.JsonDeserializer;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.deser.BeanDeserializer;
    import com.fasterxml.jackson.databind.deser.BeanDeserializerBase;
    import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
    import com.fasterxml.jackson.databind.module.SimpleModule;
    
    import javax.validation.ConstraintViolation;
    import javax.validation.ConstraintViolationException;
    import javax.validation.Validation;
    import javax.validation.Validator;
    import javax.validation.ValidatorFactory;
    import javax.validation.constraints.NotNull;
    import javax.validation.constraints.Pattern;
    import javax.validation.constraints.Size;
    import java.io.File;
    import java.io.IOException;
    import java.util.Set;
    
    public class JsonApp {
    
        public static void main(String[] args) throws Exception {
            File jsonFile = new File("./resource/test.json").getAbsoluteFile();
    
            SimpleModule validationModule = new SimpleModule();
            validationModule.setDeserializerModifier(new BeanDeserializerModifier() {
                @Override
                public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
                    if (deserializer instanceof BeanDeserializer) {
                        return new BeanValidationDeserializer((BeanDeserializer) deserializer);
                    }
    
                    return deserializer;
                }
            });
    
            ObjectMapper mapper = new ObjectMapper();
            mapper.registerModule(validationModule);
    
            System.out.println(mapper.readValue(jsonFile, Pojo.class));
        }
    }
    
    class Pojo {
    
        @NotNull
        @Size(min = 1, message = "Name should be at least 1 character.")
        private String name;
    
        @NotNull
        @Pattern(regexp = "^https://github.com/.+/.+$", message = "Link to github should match https://github.com/USER/REPOSITORY")
        private String github;
    
        // getters, setters, toString()
    }
    

    유효한 JSON 페이로드 :

    {
      "name": "Jackson",
      "github": "https://github.com/FasterXML/jackson-databind"
    }
    

    인쇄물:

    Pojo{name='Jackson', github='https://github.com/FasterXML/jackson-databind'}
    

    잘못된 JSON 페이로드의 경우 :

    {
      "name": "",
      "github": "https://git-hub.com/FasterXML/jackson-databind"
    }
    

    인쇄물:

    Exception in thread "main" javax.validation.ConstraintViolationException: JSON object is not valid. Reasons (2): Name should be at least 1 character., Link to github should match https://github.com/USER/REPOSITORY, 
        at BeanValidationDeserializer.validate(JsonApp.java:110)
        at BeanValidationDeserializer.deserialize(JsonApp.java:97)
    

    참조 :

  2. ==============================

    2.나는 내가 어떻게 그 일을 할 수 있었는지 게시 할 것이다. validator를 구현 한 클래스 만들기 :

    나는 내가 어떻게 그 일을 할 수 있었는지 게시 할 것이다. validator를 구현 한 클래스 만들기 :

    public class UserValidator implements Validator {
    
        private static final int MINIMUM_NAME_LENGTH = 6;
    
        @Override
        public boolean supports(Class<?> clazz) {
            return User.class.isAssignableFrom(clazz);
        }
    
        public void validate(Object target, Errors errors) {
            ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "Name must be at least 7 characters long.");
            User foo = (User) target;
    
            if(foo.getGithub().length() > 0 && !extensionSpec.getGithub().matches("^(www|http:|https:)+//github.com/.+/.+$")){
                errors.rejectValue("github", "Github must match http://github.com/:user/:repo");
            }
    
            if (errors.getFieldErrorCount("name") == 0 && foo.getName().trim().length() < MINIMUM_NAME_LENGTH) {
                errors.rejectValue("name", "Name must be at least 7 characters");
            }
        }
    }
    

    그런 다음 바인딩 된 결과를 가져온 다음 객체의 유효성을 검사하여 직렬화되지 않은 객체로 databinder를 만듭니다.

    ObjectMapper mapper = new ObjectMapper();
    User foo = mapper.readValue(FooJson, User.class);
    
    Validator validator = new ObjectValidator();
    BindingResult bindingResult = new DataBinder(foo).getBindingResult();
    validator.validate(foo, bindingResult);
    
    if(bindingResult.hasErrors()){
        throw new BindException(bindingResult);
    }
    

    또한 응답 본문에서 errorCodes를 사용하려면 다음을 수행하십시오.

    @ExceptionHandler
    ResponseEntity handleBindException(BindException e){
        return ResponseEntity
                .status(HttpStatus.BAD_REQUEST)
                .body(e.getBindingResult().getAllErrors()
                        .stream()
                        .map(DefaultMessageSourceResolvable::getCode)
                        .toArray());
    
    }
    
  3. from https://stackoverflow.com/questions/55457754/valid-when-creating-objects-with-jackson-without-controller by cc-by-sa and MIT license