ChatGPT解决这个技术问题 Extra ChatGPT

Using NotNull Annotation in method argument

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.

@NotNull is just an annotation. Annotations do nothing on their own. They need an annotation processor at compile time, or something that processes it at runtime.
Are you running the code inside an application server (for example using Arquillian)?
@SotiriosDelimanolis - So then what is the point, just a warning to anyone calling the method not to pass a null value? In which case you still need the null pointer validation code.
look at hibernate validator
@jabu.10245 - Not using any application server.

l
leo

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

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

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

A method should not return null. 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:

Bean validation NotNull.java Constraint.java ConstraintValidator.java


So just to clarify part 2 of the NotNull part, really it should say "should not", not " cannot" since it can't bed enforced? Or if it can be enforced at runtime, how would you go about that?
Yes, its a "should not"... the method implementation should enforce the contract.
Alternatively, in Java 8, Optional could be used in place of @Null in return values, and method overloading in place of @Null in parameter lists: dolszewski.com/java/java-8-optional-use-cases
I believe the confusion comes from the java doc of the NotNull annotation: * The annotated element must not be {@code null}. * Accepts any type. and I think must word should be replaced with should but again it depends of how you read it. Definitely some more clarifications would be good to have
@Julian I think must is the right term because it is a rule, not a recommendation. If you use the annotation where you should not pass null but it would be allowed, you are using the annotation wrong. The term does not imply that it is validated. However, a hint that it is not validated wouldn't hurt. If you want to add automatic validation, you can use some external tools. For example, the IntelliJ IDE has builtin support to inject null-checks.
P
Paulo Merson

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

If the bar field was anotated with NotNull, the call to Objects.requireNonNull would still generate à warning as the requireNonNull method does not return a NotNull reference.
I need this !!!
R
Rany Albeg Wein

To make @NonNull active you need Lombok:

https://projectlombok.org/features/NonNull

import lombok.NonNull;

Follow: Which @NotNull Java annotation should I use?


N
Naruto

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

Where do I put this, in the beginning of the method?
yes..at the beginning of the method...this is just one of the validation implementations ,there might be others also...
Ok. But this significance of what that code does will not change whether or not I have the @NotNull annotation in the param argument?
Now you have all the Violation in the set, check its size, if its greater then zero,then return from method.
s
sisanared

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)


W
WesternGun

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.


J
Julien Feniou

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

}

s
sartysam
I resolved it with

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

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

Could you provide more explanation of how this would help resolve the asker's question?