ChatGPT解决这个技术问题 Extra ChatGPT

在方法参数中使用 NotNull 注解

我刚开始在 Java 8 中使用 @NotNull 注释并得到了一些意想不到的结果。

我有这样的方法:

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

我编写了一个 JUnit 测试,传入参数 searchList 的空值。我期待会发生某种类型的错误,但它就像注释不存在一样。这是预期的行为吗?据我了解,这是为了让您跳过编写样板空检查代码。

非常感谢您解释@NotNull 应该做什么。

@NotNull 只是一个注释。注释本身没有任何作用。他们在编译时需要一个注释处理器,或者在运行时处理它的东西。
您是否在应用程序服务器中运行代码(例如使用 Arquillian)?
@SotiriosDelimanolis - 那么重点是什么,只是警告任何调用该方法的人不要传递空值?在这种情况下,您仍然需要空指针验证代码。
查看休眠验证器
@jabu.10245 - 不使用任何应用程序服务器。

l
leo

@Nullable@NotNull 自己什么都不做。它们应该充当文档工具。

@Nullable 注释提醒您在以下情况下引入 NPE 检查的必要性:

调用可以返回 null 的方法。取消引用可以为空的变量(字段、局部变量、参数)。

@NotNull 注解实际上是一个明确的契约,声明如下:

方法不应返回 null。变量(如字段、局部变量和参数)不应包含空值。

例如,不要写:

/**
 * @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 和 hibernate 中)。

@NotNull 注释本身不进行任何验证,因为 annotation definition 不提供任何 ConstraintValidator 类型引用。

有关更多信息,请参阅:

Bean 验证 NotNull.java Constraint.java ConstraintValidator.java


所以只是为了澄清 NotNull 部分的第 2 部分,真的应该说“不应该”,而不是“不能”,因为它不能强制执行?或者如果它可以在运行时强制执行,你会怎么做?
是的,它是“不应该”......方法实现应该强制执行合同。
或者,在 Java 8 中,可以在返回值中使用 Optional 代替 @Null,在参数列表中使用方法重载代替 @Nulldolszewski.com/java/java-8-optional-use-cases
我相信混淆来自 NotNull 注释的 java 文档:* The annotated element must not be {@code null}. * Accepts any type.,我认为应该将 must 单词替换为 should 但这又取决于您如何阅读它.肯定有更多的澄清会很好
@Julian 我认为 must 是正确的术语,因为它是规则,而不是建议。如果您在不应通过 null 但允许的地方使用注释,则说明您使用了错误的注释。该术语并不意味着它已被验证。但是,暗示它未经验证不会受到伤害。如果要添加自动验证,可以使用一些外部工具。例如,IntelliJ IDE 内置了对注入空检查的支持。
P
Paulo Merson

如上所述,@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");
    }
}

如果 bar 字段使用 NotNull 进行注释,则对 Objects.requireNonNull 的调用仍会生成 à 警告,因为 requireNonNull 方法不返回 NotNull 引用。
我需要这个 !!!
R
Rany Albeg Wein

要激活 @NonNull,您需要 Lombok:

https://projectlombok.org/features/NonNull

import lombok.NonNull;

关注:Which @NotNull Java annotation should I use?


N
Naruto

所以 @NotNull 只是一个标签......如果你想验证它,那么你必须使用类似 hibernate validator jsr 303

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

在方法的开头,我应该把它放在哪里?
是的..在方法的开头......这只是验证实现之一,可能还有其他......
好的。但是,无论我在 param 参数中是否有 @NotNull 注释,该代码所做的事情的重要性都不会改变?
现在你有了集合中的所有 Violation,检查它的大小,如果它大于零,则从方法返回。
s
sisanared

如果您使用的是 Spring,您可以通过使用 @Validated 注释类来强制验证:

import org.springframework.validation.annotation.Validated;

此处提供更多信息:Javax @NotNull annotation usage

您还可以使用 projectlombok 中的 @NonNull (lombok.NonNull)


W
WesternGun

我这样做是为了创建自己的验证注释和验证器:

ValidCardType.java(用于方法/字段的注释)

@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 {};
}

并且,触发检查的验证器: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));
    }
}

您可以执行与检查 @NotNull 非常相似的操作。


J
Julien Feniou

要在测试中测试您的方法验证,您必须在 @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));

}

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

您能否提供更多解释这将如何帮助解决提问者的问题?