I have got a spring boot server and would like to validate my values by spring. Using the @Size validation I can set the max size. But i would like to get this max size from my application.property file.
I have already tried to load this value by "@Value(...)" but I can not use this value in the "@Size" field.
@Value("${max.size.in.properties}")
private int MAX_SIZE;
@Size(max = 10)
private String description;
你可以像这个帖子一样按照 Java 反射https://www.baeldung.com/java-reflection-change-annotation-params
This is not possible as annotations require constant expressions ( static final
) and @Value
cannot be used to inject values into static final fields.
Maybe this project might help you out: https://github.com/jirutka/validator-spring . It allows you to use Spring Expression Language together with bean validation.
We can programmatically specify constraints using Hibernate Validator , which is already available in the classpath when using spring-boot-starter-web
.
Given:
class MyObject {
private String description;
...
}
We can setup constraints like this:
@Value("${max.size.in.properties}")
private int MAX_SIZE;
HibernateValidatorConfiguration configuration = Validation
.byProvider( HibernateValidator.class )
.configure();
ConstraintMapping constraintMapping = configuration.createConstraintMapping();
constraintMapping.type( MyObject.class )
.property( "description", FIELD )
.constraint( new SizeDef().min( 1 ).max( MAX_SIZE ) );
and validate an instance of the object with:
Validator validator = configuration.addMapping( constraintMapping )
.buildValidatorFactory()
.getValidator();
Set<ConstraintViolation<MyObject>> constraintViolations =
validator.validate( myObjectInstance );
if (constraintViolations.size() > 0) {
... // handle constraint violations
}
The bad news : there's no way to do what you want with standard annotations from Java Validation API.
The good news : you can easily create a custom annotation that does exactly what you want.
You need to create a custom validation annotation (let's call it @ConfigurableSize
) that takes as parameters two strings, one for the name of the property holding the min size and one for the name of the property holding the max size.
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Repeatable(ConfigurableSize.List.class)
@Constraint(validatedBy = {ConfigurableSizeCharSequenceValidator.class})
public @interface ConfigurableSize {
String message() default "size is not valid";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String minProperty() default "";
String maxProperty() default "";
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
@interface List {
ConfigurableSize[] value();
}
}
The validator will retrieve the property values upon initialization, then it will perform the exact same validation checks as the @Size
constraint. Even the constraint violation will have the exact same message. Please notice that if the property name is omitted the min
and max
will default respectively to 0
and Integer.MAX_VALUE
, ie the same defaults for @Size
.
public class ConfigurableSizeCharSequenceValidator implements ConstraintValidator<ConfigurableSize, CharSequence> {
private final PropertyResolver propertyResolver;
private int min;
private int max;
@Autowired
public ConfigurableSizeCharSequenceValidator(PropertyResolver propertyResolver) {
this.propertyResolver = propertyResolver;
}
@Override
public void initialize(ConfigurableSize configurableSize) {
String minProperty = configurableSize.minProperty();
String maxProperty = configurableSize.maxProperty();
this.min = "".equals(minProperty) ? 0 :
propertyResolver.getRequiredProperty(minProperty, Integer.class);
this.max = "".equals(maxProperty) ? Integer.MAX_VALUE :
propertyResolver.getRequiredProperty(maxProperty, Integer.class);
validateParameters();
}
private void validateParameters() {
if (this.min < 0) {
throw new IllegalArgumentException("The min parameter cannot be negative.");
} else if (this.max < 0) {
throw new IllegalArgumentException("The max parameter cannot be negative.");
} else if (this.max < this.min) {
throw new IllegalArgumentException("The length cannot be negative.");
}
}
@Override
public boolean isValid(CharSequence value, ConstraintValidatorContext context) {
if (value == null) {
return true;
} else {
int length = value.length();
boolean retVal = length >= this.min && length <= this.max;
if (!retVal) {
HibernateConstraintValidatorContext hibernateContext =
context.unwrap(HibernateConstraintValidatorContext.class);
hibernateContext.addMessageParameter("min", this.min)
.addMessageParameter("max", this.max);
hibernateContext.disableDefaultConstraintViolation();
hibernateContext
.buildConstraintViolationWithTemplate("{javax.validation.constraints.Size.message}")
.addConstraintViolation();
}
return retVal;
}
}
}
You apply the custom annotation in your bean
public class SomeBean {
@ConfigurableSize(maxProperty = "max.size.in.properties")
private String description;
}
Then finally in your application.properties
you'll define the property
max.size.in.properties=10
And that's it. You can find more details and a full example in this blog post: https://codemadeclear.com/index.php/2021/03/22/easily-configure-validators-via-properties-in-a-spring-boot-project/
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.