Использование NotNull Annotation в аргументе метода

Я только начал использовать аннотацию @NotNull с Java 8 и получить некоторые неожиданные результаты.

У меня есть такой метод:

public List<Found> findStuff(@NotNull List<Searching> searchingList) {
    ... code here ...
}

Я написал тест JUnit, передающий значение null для аргумента searchList. Я ожидал, что произойдет какая-то ошибка, но она прошла, как будто аннотации не было. Это ожидаемое поведение? Из того, что я понял, это должно было позволить вам пропустить код кода проверки работоспособности.

Было бы весьма полезно объяснить, что именно @NotNull должно делать.

Ответ 1

@Nullable и @NotNull ничего не делают сами по себе. Предполагается, что они действуют как инструменты документирования.

Аннотация @Nullable напоминает вам о необходимости ввести проверку NPE, когда:

  1. Вызов методов, которые могут вернуть ноль.
  2. Разыменование переменных (полей, локальных переменных, параметров), которые могут быть нулевыми.

@NotNull Аннотация, на самом деле, является явным договором, в котором говорится следующее:

  1. Метод не должен возвращать ноль.
  2. Переменная (например, поля, локальные переменные и параметры) не может содержать нулевое значение.

Например, вместо того, чтобы писать:

/**
 * @param aX should not be null
 */
public void setX(final Object aX ) {
    // some code
}

Вы можете использовать:

public void setX(@NotNull final Object aX ) {
    // some code
}

Кроме того, @NotNull часто проверяется ConstraintValidators (например, spring и в спящем режиме).

Сама аннотация @NotNull не выполняет никакой проверки, поскольку определение аннотации не предоставляет ссылки на тип ConstraintValidator.

Для получения дополнительной информации см.:

  1. Проверка бина
  2. NotNull.java
  3. Constraint.java
  4. ConstraintValidator.java

Ответ 2

Как упомянуто выше @NotNull ничего не делает само по себе. Хороший способ использования @NotNull - использовать его с Objects.requireNonNull

public class Foo {
    private final Bar bar;

    public Foo(@NotNull Bar bar) {
        this.bar = Objects.requireNonNull(bar, "bar must not be null");
    }
}

Ответ 4

SO @NotNull просто является тегом... Если вы хотите его проверить, вы должны использовать что-то вроде hibernate validator jsr 303

ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
Validator validator = validatorFactory.getValidator();
 Set<ConstraintViolation<List<Searching>> violations = validator.validate(searchingList);

Ответ 5

Если вы используете Spring, вы можете форсировать проверку, аннотируя класс с помощью @Validated:

import org.springframework.validation.annotation.Validated;

Более подробная информация доступна здесь: проверка Javax @NotNull аннотации использования

Ответ 6

Чтобы проверить валидацию метода в тесте, вы должны заключить его в прокси в методе @Before.

@Before
public void setUp() {
    this.classAutowiredWithFindStuffMethod = MethodValidationProxyFactory.createProxy(this.classAutowiredWithFindStuffMethod);
}

С MethodValidationProxyFactory как:

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

}

А затем добавьте свой тест:

@Test
public void findingNullStuff() {
 assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> this.classAutowiredWithFindStuffMethod.findStuff(null));

}