3

Like that

@NotNull(code=10000)
@Size(min=5, max=10, code=10001)

Java bean validation has 3 properties: message, payload and groups. I wanna add a new one: code.

I've checked some docs, like https://docs.jboss.org/hibernate/validator/5.0/reference/en-US/html/validator-customconstraints.html and https://docs.oracle.com/javaee/6/tutorial/doc/gkfgx.html. It seems not possible?

wwulfric
  • 521
  • 1
  • 4
  • 14
  • Welcome to StackOverflow. Check the StackOverflow's help on asking questions first, please. Focus on [How to ask a good question](http://stackoverflow.com/help/how-to-ask) and [How to create a Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve), but also other [help topics](http://stackoverflow.com/help/asking) would be useful. – David Ferenczy Rogožan Jan 05 '16 at 02:05

1 Answers1

5

Short answer to your question: No, you can't just add an extra field, nor can you use inheritance too add the extra field. See this question which explains why Java doesn't allow inheritance with annotations.

What you'll have to do is create your own particular version of the @Size annotation. But you should be able to apply the @Size annotation to your custom annotation so that @Size is checked automatically when you run your validations.

Your annotation would probably look something like this:

@Constraint(validatedBy = { })
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@ReportAsSingleViolation
//The only downside of this approach 
//is that you have to hardcode your min and max values
@Size(min=5, max=10)
public @interface CodedSize {
    String message() default "{Default Validation Message}";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default { };
    int code() default 0;
}

If you wanted to specify the size as well in the annotation, you could do that, and write a custom validator that validates your annotation.

@Constraint(validatedBy = { CodedSizeValidator.class })
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface CodedSize {
    String message() default "{Default Validation Message}";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default { };
    int minSize() default 5;
    int maxSize() default 10;
    int code() default 0;
}

Then your custom validator looks something like this:

public class CodedSizeValidator implements ConstraintValidator<CodedSize, String> {

    private int minSize;
    private int maxSize;
    private int code;

    @Override
    public void initialize(CodedSize constraintAnnotation){
        this.minSize = constraintAnnotation.minSize();
        this.maxSize = constraintAnnotation.maxSize();
        this.code = constraintAnnotation.code();
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        boolean isValid = false;
        if(value == null || value.isEmpty()) {
            //if a null or empty value is valid, then set it here.
            isValid = true;   
        } else {
            //Logic here to determine if your value is valid by size constraints.
        }
        return isValid;
    }
}

I used String because that seemed the most applicable, but you could easily use Number, or even a generic type to allow you to use this annotation on more than one field. The advantage of doing it this way is that if you want to add a null check in with this validation, you can do so.

The ConstraintValidatorContext can be used to build out your error message if multiple validations fail. You can make this as detailed as you want, but be aware that this code can spaghetti-fy very quickly.

Community
  • 1
  • 1
JamesENL
  • 6,400
  • 6
  • 39
  • 64