57

Is there are any java annotation(s) that can validate like the example below?

String test;
test = null; //valid
test = ""; //invalid
test = " "; //invalid
test = "Some values"; //valid
Usama Abdulrehman
  • 1,041
  • 3
  • 11
  • 21
Yash Krishnan
  • 2,653
  • 1
  • 18
  • 22

6 Answers6

51

You need to create a custom annotation: @NullOrNotBlank

First create the custom annotation: NullOrNotBlank.java

@Target( {ElementType.FIELD})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = NullOrNotBlankValidator.class)
public @interface NullOrNotBlank {
    String message() default "{javax.validation.constraints.NullOrNotBlank.message}";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default {};
}

Then the actual validator: NullOrNotBlankValidator.java

public class NullOrNotBlankValidator implements ConstraintValidator<NullOrNotBlank, String> {

    public void initialize(NullOrNotBlank parameters) {
        // Nothing to do here
    }

    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
        return value == null || value.trim().length() > 0;
    }
}
vegemite4me
  • 6,621
  • 5
  • 53
  • 79
  • 7
    Just a quick one-liner for the validation: `return str == null || str.trim().length() > 0;` – Jefferson Lima Nov 06 '18 at 13:37
  • 3
    @JeffersonLima I am not sure why my code is so verbose (I don't even like regex). Your one liner is spot on. – vegemite4me Nov 06 '18 at 19:53
  • 2
    Great solution, I replaced the isValid check with: `return value == null || !value.isBlank();` since I am using Java 11. – Peroxy May 18 '21 at 12:37
  • FYI, this is possible to do without a custom annotation using [javax.validation.constraints.Size](https://javaee.github.io/javaee-spec/javadocs/javax/validation/constraints/Size.html). I've added an answer for this. – Phil Jul 15 '22 at 17:53
34

There isn't such an annotation in either javax.validation or Hibernate Validator. There was a request to add one to Hibernate Validator but it was closed as "won't fix" due to the possibility of writing your own relatively easily. The suggest solution was to either use your own annotation type defined like this:

@ConstraintComposition(OR)
@Null
@NotBlank
@ReportAsSingleViolation
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
@Constraint(validatedBy = { })
public @interface NullOrNotBlank {
    String message() default "{org.hibernate.validator.constraints.NullOrNotBlank.message}";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default { };
}

or to use the @Pattern annotation with a regular expression that requires a non-whitespace character to be present (as the Pattern annotation accepts nulls and does not match them against the pattern).

Jules
  • 14,841
  • 9
  • 83
  • 130
  • 5
    +1 for the `@Pattern` idea. This is great because many of the built-in annotations pass for null so that they don't conflict with `@NotNull` – Poke Oct 26 '18 at 15:24
6

This is possible without creating a custom annotation, by using javax.validation.constraints.Size

// Null values are considered valid
@Size(min=1) String test;

However as theprogrammer points out, blank strings such as " " are considered valid, which is not the case for @NotBlank.

Phil
  • 401
  • 8
  • 18
5

Where is a nice javax.validation.constraints.Pattern annotation.

You can annotate the field with:

@Pattern(regexp = "^(?!\\s*$).+", message = "must not be blank")

This checks if field matches regex. The regex itself is something but not blank (see details here). It uses negative lookahead.

Vladyslav Nikolaiev
  • 1,819
  • 3
  • 20
  • 39
0

The best way is to create your own constraint validator,

//custom annotation
@Documented
@Constraint(validatedBy = CustomCheck.class)
@Target( { ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomConstarint {
    String message() default "Invalid data";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
} 

//validation logic goes here
public class CustomCheck implements 
  ConstraintValidator<CustomConstarint, String> {
 
    @Override
    public void initialize(CustomConstarint customConstarint) {
    }
 
    @Override
    public boolean isValid(String field,
      ConstraintValidatorContext cxt) {
        //write your logic to validate the field
    }
}

Arnav Karforma
  • 112
  • 2
  • 12
-7

Did you try Hibernate-Validator? I think that's what you are looking for.

import javax.validation.constraints.NotNull;

import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.NotEmpty;

public class MyModel  {

    @NotNull
    private String  str1;

    @NotEmpty
    private String  str2;

    @NotBlank
    private String  str3;

}
bhdrk
  • 3,415
  • 26
  • 20
  • No, I don't think so, I want all those validation over my single variable – Yash Krishnan Jun 30 '15 at 08:37
  • `@NotBlank` validates for all of your requirements on a single variable. I just added the others if you want less validation. E.g. if your variable may contain blank char then use `@NotEmpty` or if it may contain empty string then use `@NotNull`. – bhdrk Jun 30 '15 at 10:59
  • http://stackoverflow.com/questions/17137307/in-hibernate-validator-4-1-what-is-the-difference-between-notnull-notempty – Yash Krishnan Jun 30 '15 at 11:30
  • I just try to explain the details of related to your questions. Not all. What's wrong? – bhdrk Jun 30 '15 at 12:12
  • 3
    None of these matches the requirements in the question, which are that the value should not be empty but may still be null. All of these validation constraints fail on null. – Jules May 01 '17 at 08:55