Reputation: 6962
I just started using the @NotNull
annotation with Java 8 and getting some unexpected results.
I have a method like this:
public List<Found> findStuff(@NotNull List<Searching> searchingList) {
... code here ...
}
I wrote a JUnit test passing in the null value for the argument searchingList. I was expecting some type of error to happen but it went through as though the annotation was not there. Is this expected behavior? From what I understood, this was to allow you to skip writing the boilerplate null check code.
An explanation of what exactly @NotNull is supposed to do would be greatly appreciated.
Upvotes: 249
Views: 330709
Reputation: 3477
@Nullable
and @NotNull
do nothing on their own. They are supposed to act as Documentation tools.
The @Nullable
Annotation reminds you about the necessity to introduce an NPE check when:
The @NotNull
Annotation is, actually, an explicit contract declaring the following:
For example, instead of writing:
/**
* @param aX should not be null
*/
public void setX(final Object aX ) {
// some code
}
You can use:
public void setX(@NotNull final Object aX ) {
// some code
}
Additionally, @NotNull
is often checked by ConstraintValidators (e.g. in Spring and Hibernate).
The @NotNull
annotation doesn't do any validation on its own because the annotation definition does not provide any ConstraintValidator
type reference.
NotNull
Constraint
ConstraintValidator
Upvotes: 291
Reputation: 48753
To make @NonNull
active you need Lombok:
https://projectlombok.org/features/NonNull
import lombok.NonNull;
Follow: Which @NotNull Java annotation should I use?
Upvotes: 32
Reputation: 4287
If you are using Spring, you can force validation by annotating the class with @Validated
:
import org.springframework.validation.annotation.Validated;
More info available here: Javax @NotNull annotation usage
You could also use @NonNull
from projectlombok
(lombok.NonNull)
Upvotes: 8
Reputation: 93
I resolved it with
@JsonSetter(nulls = Nulls.AS_EMPTY)
@NotBlank
public String myString;
Request Json:
{
myString=null
}
Response:
error must not be blank
Upvotes: -3
Reputation: 12728
I do this to create my own validation annotation and validator:
ValidCardType.java
(annotation to put on methods/fields)
@Constraint(validatedBy = {CardTypeValidator.class})
@Documented
@Target( { ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidCardType {
String message() default "Incorrect card type, should be among: \"MasterCard\" | \"Visa\"";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
And, the validator to trigger the check:
CardTypeValidator.java
:
public class CardTypeValidator implements ConstraintValidator<ValidCardType, String> {
private static final String[] ALL_CARD_TYPES = {"MasterCard", "Visa"};
@Override
public void initialize(ValidCardType status) {
}
public boolean isValid(String value, ConstraintValidatorContext context) {
return (Arrays.asList(ALL_CARD_TYPES).contains(value));
}
}
You can do something very similar to check @NotNull
.
Upvotes: 4
Reputation: 1004
To test your method validation in a test, you have to wrap it a proxy in the @Before method.
@Before
public void setUp() {
this.classAutowiredWithFindStuffMethod = MethodValidationProxyFactory.createProxy(this.classAutowiredWithFindStuffMethod);
}
With MethodValidationProxyFactory as :
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
public class MethodValidationProxyFactory {
private static final StaticApplicationContext ctx = new StaticApplicationContext();
static {
MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
processor.afterPropertiesSet(); // init advisor
ctx.getBeanFactory()
.addBeanPostProcessor(processor);
}
@SuppressWarnings("unchecked")
public static <T> T createProxy(T instance) {
return (T) ctx.getAutowireCapableBeanFactory()
.applyBeanPostProcessorsAfterInitialization(instance, instance.getClass()
.getName());
}
}
And then, add your test :
@Test
public void findingNullStuff() {
assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> this.classAutowiredWithFindStuffMethod.findStuff(null));
}
Upvotes: 1
Reputation: 484
As mentioned above @NotNull
does nothing on its own. A good way of using @NotNull
would be using it with Objects.requireNonNull
public class Foo {
private final Bar bar;
public Foo(@NotNull Bar bar) {
this.bar = Objects.requireNonNull(bar, "bar must not be null");
}
}
Upvotes: 44
Reputation: 4329
SO @NotNull just is a tag...If you want to validate it, then you must use something like hibernate validator jsr 303
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
Validator validator = validatorFactory.getValidator();
Set<ConstraintViolation<List<Searching>> violations = validator.validate(searchingList);
Upvotes: 6