I'm trying to create my own composite validation annotation to validate a String - so far it is made up of the annotations #NotNull, #NotBlank and #Size
However, I do not want to leave these at default values and want to be able to pass in a parameter value, for example if I do #ValidString (min = 1, max = 50), then the #Size annotation can read these values - is this possible?
My constraint -
#NotNull()
#NotBlank()
#Size()
#Constraint(validatedBy = ValidStringValidator.class)
#Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
#Retention(RUNTIME)
public #interface ValidString {
String message();
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
int min() default 1;
int max() default 255;
}
You may use OverridesAttribute
#Size(min=1, max=255)
#Retention(RUNTIME)
#Target({ TYPE, FIELD })
#Constraint(validatedBy={})
public #interface ValidString {
String message();
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
#OverridesAttribute(constraint=Size.class, name="min")
int min() default 1;
#OverridesAttribute(constraint=Size.class, name="max")
int max() default 255;
}
No, but your annotation can contain other annotations, e.g.
#NotNull()
#NotBlank()
#Constraint(validatedBy = ValidStringValidator.class)
#Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
#Retention(RUNTIME)
public #interface ValidString {
String message();
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
Size size() default #Size(/*enter default size arguments here*/);
}
Related
I'm wondering if it's possible to do something like:
#Min(1)
#Max(100)
public #interface ValidationForX {}
and then
#ValidationForX
int X;
For some reason #Min and #Max are applicable on annotations so I'm assuming it should be possible
I want to hide this validation behind one annotation because I want to reuse it
Thanks for your help!
You annotation must look like this:
#Min(1)
#Max(100)
#Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
#Retention(RUNTIME)
#Documented
#Constraint(validatedBy = {})
public #interface ValidationForX {
String message() default "value should be greater or equal than 1 and less or equal than 100.";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Read more about composing constraints here: https://www.baeldung.com/java-bean-validation-constraint-composition
You can directly use #Min and #Max annotation on top of the field which you want to validate.
Something like this:
#Max(value=100)
#Min(value=1)
int X;
I have a working custom class level constraint that validates all annotations that do not belong in a group. How can I change that to validate a specific group with that constraint?
This is the annotation class I have:
#Target({TYPE, ANNOTATION_TYPE})
#Retention(RUNTIME)
#Constraint(validatedBy = CheckCase.class)
#Documented
public #interface ValidName {
String message() default "{message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
#Target({TYPE, ANNOTATION_TYPE})
#Retention(RUNTIME)
#Documented
#interface List {
ValidName[] value();
}
}
Right now, the validation works only if I use:
#CheckCase(message = "Error message")
I would like to use this:
#CheckCase(message = "Error message", groups = CheckCaseGroup.class)
Do I have to change something in the following line?
Class<?>[] groups() default {};
Separate question:
If I run the validator without passing in a group, will it go through all validations including the ones that have a group, or will it go only through the ones that don't have a specified group? For example:
will running this:
validator.validate(inputData);
go through this annotations:
#NotBlank(groups = CheckCaseGroup.class)
or only this:
#NotBlank()
I have create a validation annotation to validate the content of a string. The definition of my annotation looks like this:
#NotNull
#Size(min = 2, max = 128, groups = First.class)
#Pattern(regexp = "^(?!WP_([0-9])+$)[A-Z_][A-Z0-9_-]+", groups = Second.class)
#Target({FIELD, ANNOTATION_TYPE})
#Retention(RUNTIME)
#Documented
#Constraint(validatedBy = {})
#GroupSequence(value={First.class, Second.class})
public #interface ValidIntentName {
String message() default "";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
My problem is that i cannot order the #Size and #Pattern execution. I've tried a couple of things but no luck so far.
Basically I need #Size to be executed before #Pattern
First and Second interfaces are defined. There are no errors during compilation is just that during run-time #Patter is executed before #Size.
Any idea what I'm doing wrong?
I'm running Java 8.
Thanks
I want to build a NotNull check that only work on Create group, so I can write like this
#Data
public static class TestDto {
#NotNullOnCreate
// #NotNull(groups = Create.class) // instead of this
private String id;
}
I create the NotNullOnCreate like this
#Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
#Retention(RUNTIME)
#Documented
#Repeatable(NotNullOnCreate.List.class)
#ReportAsSingleViolation
#Constraint(validatedBy = {})
#NotNull(groups = Create.class)
#interface NotNullOnCreate {
String message() default "{javax.validation.constraints.NotNull.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
#Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
#Retention(RUNTIME)
#Documented
#interface List {
NotNullOnCreate[] value();
}
}
This doesn't work, because composing constraint annotation's (see ConstraintDescriptorImpl#createComposingConstraintDescriptor) group will be set to host annotation's group('Default').
I also tried this Class<?>[] groups() default {Create.class};, but this is not allowed, the default group must empty.
How can I achieve this ? I don't want to write the group everywhere.
EDIT
Create HV-1355 Constraint annotation with explicit groups
Wrote a workable demo project hv-annotation-with-group
This is not possible at the moment. If you like, open an issue in the Hibernate Validator issue tracker and we can explore this feature.
While writing my custom annotation and validator I faced with problem:
My code for annotation:
#Documented
#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME)
#Constraint(validatedBy = NumericValidator.class)
public #interface Numeric {
String message() default "{constraint.postcode}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
int digitCount();
}
So that as you can see I need the addition parameter "digitCount". But this parameter is not mandatory so that I can use validation without, but according to this annotation I have to specify it anyway. I'd like to provide some default value for this parameter, and actually I have no idea how to do this.
Just provide a magic number for the default and ignore any annotation with the magic number. I used -1 as the magic number in this example:
#Documented
#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME)
#Constraint(validatedBy = NumericValidator.class)
public #interface Numeric {
String message() default "{constraint.postcode}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
int digitCount() default -1;
}