Missing @Repeatable annotation on SpELAssert
Hello,
As the title says, there's no @Repeatable meta annotation on SpELAssert, preventing use of multiple annotations on the same element.
Other than that, SpELAssert seems to be configured to be used in such scenarios:
@Documented
@Retention(RUNTIME)
@Target({METHOD, FIELD, TYPE})
@interface List {
SpELAssert[] value();
}
Edit:
Adding @Repeatable(SpELAssert.List.class) to SpELAssert seems to work properly in my tests.
Hello,
I saw the problem too ,but I wrote my own ,which fit my needs.
Here is a example:
I.First create your validation annotation:
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {SpELValidationValidator.class})
@Repeatable(value = SpELValidation.List.class)
public @interface SpELValidation {
String message() default "Message wasn't set!";
String value();
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@interface List {
SpELValidation[] value();
}
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
II.Now write the SpELValidator:
Note that you MUST specify a BeanResolver ,because it will not find your Beans ,if you want to use them in the SpEL expression
@Component
public class SpELValidationValidator implements ConstraintValidator<SpELValidation, Object> {
private SpELValidation annotation;
private ExpressionParser parser;
private final ApplicationContext applicationContext;
@Autowired
public SpELValidationValidator(ApplicationContext applicationContext) {
this.parser = new SpelExpressionParser();
this.applicationContext = applicationContext;
}
public void initialize(SpELValidation constraintAnnotation) {
this.annotation = constraintAnnotation;
}
public boolean isValid(Object value, ConstraintValidatorContext context) {
StandardEvaluationContext spelContext = this.getSpELContext(value);
boolean result = (boolean) this.parser.parseExpression(this.annotation.value()).getValue(spelContext);
return result;
}
private StandardEvaluationContext getSpELContext(Object value) {
AutowireCapableBeanFactory beanFactory = this.applicationContext.getAutowireCapableBeanFactory();
BeanFactoryResolver beanResolver = new BeanFactoryResolver(beanFactory);
StandardEvaluationContext spELContext = new StandardEvaluationContext(value);
spELContext.setBeanResolver(beanResolver);
return spELContext;
}
}
III.Then add a configuration for the Validator ,which you will use to validate objects:
@Configuration
public class ValidatorConfiguration {
@Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
}
IV.Voilà now you can use it,repeat it and will not be dependent on 3rd party dependencies:
@Getter
@Setter
@SpELValidation(value = "@commentReportServicesImp.hasReported(#this.userId,#this.commentId,#this.type) == false",message = "You have already reported that comment!")
@SpELValidation(value = "#this.commentId == 'joreto2'",message = "Comment ID is not equal!")
public class CommentReportCreateRequest extends ReportCreateRequest {
@NotNull
private String commentId;
@NotNull
private Type type;
}