mavriksc
mavriksc

Reputation: 1132

Java Spring Validation and custom patterns

I have a DTO class that takes customer information. Many of the fields are annotated with validation retrictions. @NotNull @Length @Min @Max @Pattern... and so on. We have the need as it seems many do for loading regex's for validation from properties files, so @CustomPattern was created, along with CustomerValidationAdvice.

@Before("@annotation(customPattern)")
public void validateWithPropertyFileValue(JoinPoint joinPoint, CustomPattern customPattern) throws Throwable {
    if(applicationProps==null) {
        applicationProps = (Properties) ApplicationContextProvider.getApplicationContext().getBean(
                "applicationProps");
    }
    Object[] paramValues = joinPoint.getArgs();
    String valueToValidate="";
    if (!ArrayUtils.isEmpty(paramValues)) {
        valueToValidate = paramValues[0] != null ? (String) paramValues[0] : valueToValidate;
    }
    if (!serverValidationUsingRegexPattern(valueToValidate, applicationProps.getProperty(customPattern.regexp()))) {
        throw new ValidationException("Validation Failed");
    }

}

The problem is that this executes when setting the values on the DTO from the incoming request even though the method is not Annotated with @Valid. The other validation parameters do not execute unless object is passed to validator or @valid is on the method. Are there things i can look at in the joinPoint to figure out where it was called from and skip validation?

Upvotes: 0

Views: 2131

Answers (1)

mavriksc
mavriksc

Reputation: 1132

Seems it's just better to go with how normal validation works. So instead of trying to modify legacy code using aspects. i created 2 files
the annotation:

@Documented
@Retention(RUNTIME)
@Target({METHOD,FIELD})
@Constraint(validatedBy=PropertyPaternValidator.class)
public @interface PropertyPatern {
    String property();
    String message() default "{validator.propertypatern}";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};

}  

and the processor:

public class PropertyPaternValidator implements ConstraintValidator<PropertyPatern, CharSequence> {

    private Map<String, Pattern> patterns = new HashMap<>();
    private Pattern pattern;

    @Override
    public void initialize(PropertyPatern propPattern) {
        String property = propPattern.property();

        pattern = patterns.computeIfAbsent(property, prop -> {
            Properties applicationProps = (Properties) ApplicationContextProvider.getApplicationContext()
                .getBean("applicationProps");
            String p = applicationProps.getProperty(prop);
            return Pattern.compile(p);
        });
    }    
    @Override
    public boolean isValid(CharSequence inputToValidate, ConstraintValidatorContext ctx) {
        CharSequence input = inputToValidate != null ? inputToValidate : "";
        Matcher m = pattern.matcher(input);
        return m.matches();
    }
}

This will work just like @Pattern but allow the loading of the regex from application properties. Usage annotate field like so @PropertyPatern(property = "pattern.zip") and ensure there is a regex in application properties with that key.

Upvotes: 0

Related Questions