Using NotNull Annotation in method argument

Java

Java Problem Overview


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.

Java Solutions


Solution 1 - Java

@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:

  1. Calling methods that can return null.
  2. Dereferencing variables (fields, local variables, parameters) that can be null.

The @NotNull Annotation is, actually, an explicit contract declaring the following:

  1. A method should not return null.
  2. A variable (like fields, local variables, and parameters) cannot should not hold null value.

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 (eg. 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.

For more info see:

  1. Bean validation
  2. NotNull.java
  3. Constraint.java
  4. ConstraintValidator.java

Solution 2 - Java

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");
    }
}

Solution 3 - Java

Solution 4 - Java

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);

Solution 5 - Java

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: https://stackoverflow.com/questions/43670862/javax-validation-notnull-annotation-usage

You could also use @NonNull from projectlombok (lombok.NonNull)

Solution 6 - Java

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.

Solution 7 - Java

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));

}

Solution 8 - Java

I resolved it with

@JsonSetter(nulls = Nulls.AS_EMPTY)
@NotBlank
public String myString;

Request Json:
{
  myString=null
}
 Response:
 error must not be blank

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDavidRView Question on Stackoverflow
Solution 1 - JavaLucas OliveiraView Answer on Stackoverflow
Solution 2 - JavaBollywoodView Answer on Stackoverflow
Solution 3 - JavagavenkoaView Answer on Stackoverflow
Solution 4 - JavaNarutoView Answer on Stackoverflow
Solution 5 - JavasisanaredView Answer on Stackoverflow
Solution 6 - JavaWesternGunView Answer on Stackoverflow
Solution 7 - JavaJulien FeniouView Answer on Stackoverflow
Solution 8 - JavasartysamView Answer on Stackoverflow