27

Which annotations would I have to use for Hibernate Validation to validate a String to apply to the following:

//should always have trimmed length = 6, only digits, only positive number
@NotEmpty
@Size(min = 6, max = 6)
public String getNumber { 
   return number.trim();
}

How can I apply digit validation? Would I just use @Digits(fraction = 0, integer = 6) here?

membersound
  • 81,582
  • 193
  • 585
  • 1,120

3 Answers3

51

You could replace all your constraints with a single @Pattern(regexp="[\\d]{6}"). This would imply a string of length six where each character is a digit.

Hardy
  • 18,659
  • 3
  • 49
  • 65
15

You can also create your own hibernate validation annotation.
In the example below I created a validation annotation with name EnsureNumber. Fields with this annotation will validate with the isValid method of the EnsureNumberValidator class.

@Constraint(validatedBy = EnsureNumberValidator.class)
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface EnsureNumber {

    String message() default "{PasswordMatch}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    boolean decimal() default false;

}

public class EnsureNumberValidator implements ConstraintValidator<EnsureNumber, Object> {
    private EnsureNumber ensureNumber;

    @Override
    public void initialize(EnsureNumber constraintAnnotation) {
        this.ensureNumber = constraintAnnotation;
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        // Check the state of the Adminstrator.
        if (value == null) {
            return false;
        }

        // Initialize it.
        String regex = ensureNumber.decimal() ? "-?[0-9][0-9\\.\\,]*" : "-?[0-9]+";
        String data = String.valueOf(value);
        return data.matches(regex);
    }

}

You can use it like this,

@NotEmpty
@Size(min = 6, max = 6)
@EnsureNumber
private String number1;

@NotEmpty
@Size(min = 6, max = 6)
@EnsureNumber(message = "Field number2 is not valid.")
private String number2;

@NotEmpty
@Size(min = 6, max = 6)
@EnsureNumber(decimal = true, message = "Field number is not valid.")
private String number3;
Georgios Syngouroglou
  • 18,813
  • 9
  • 90
  • 92
  • Useful example of how to do this using a custom validator. The regex would need to be refined for this specific example to require only digits (negative numbers, decimal places, and commas should be excluded by the regex). – M. Justin May 26 '23 at 17:11
3

The @Digits annotation you reference enforces that a string has at most a given number of integral digits, and that its decimal form has at most a given number of decimal places.

The annotation cannot be used to enforce a minimum number of digits. Additionally, since its validation is implemented using the new BigDecimal(String) constructor, @Digits allows scientific notation representations such as "9.9E3".

@Digits therefore cannot be used to enforce your requirement that the value "should always have […] only digits, only positive number".

Your specific @Digits(fraction = 0, integer = 6) example allows integer values between -999999 and 999999, disallowing numbers with values after the decimal place (including zeros, such as "10.00"). It allows values written in scientific notation so long as their decimal form do not have any digits, which means it allows numbers such as "2E3" and "9.99999E5".

The @Digits Javadocs:

The annotated element must be a number within accepted range.

Supported types are:

  • BigDecimal
  • BigInteger
  • CharSequence
  • byte, short, int, long, and their respective wrapper types

null elements are considered valid.

M. Justin
  • 14,487
  • 7
  • 91
  • 130