我刚开始在 Java 8 中使用 @NotNull
注释并得到了一些意想不到的结果。
我有这样的方法:
public List<Found> findStuff(@NotNull List<Searching> searchingList) {
... code here ...
}
我编写了一个 JUnit 测试,传入参数 searchList 的空值。我期待会发生某种类型的错误,但它就像注释不存在一样。这是预期的行为吗?据我了解,这是为了让您跳过编写样板空检查代码。
非常感谢您解释@NotNull 应该做什么。
@NotNull
只是一个注释。注释本身没有任何作用。他们在编译时需要一个注释处理器,或者在运行时处理它的东西。
@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
本身什么也不做。使用 @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");
}
}
要激活 @NonNull
,您需要 Lombok:
https://projectlombok.org/features/NonNull
import lombok.NonNull;
关注:Which @NotNull Java annotation should I use?
所以 @NotNull 只是一个标签......如果你想验证它,那么你必须使用类似 hibernate validator jsr 303
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
Validator validator = validatorFactory.getValidator();
Set<ConstraintViolation<List<Searching>> violations = validator.validate(searchingList);
如果您使用的是 Spring,您可以通过使用 @Validated
注释类来强制验证:
import org.springframework.validation.annotation.Validated;
此处提供更多信息:Javax @NotNull annotation usage
您还可以使用 projectlombok
中的 @NonNull
(lombok.NonNull)
我这样做是为了创建自己的验证注释和验证器:
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
非常相似的操作。
要在测试中测试您的方法验证,您必须在 @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));
}
I resolved it with
@JsonSetter(nulls = Nulls.AS_EMPTY)
@NotBlank
public String myString;
Request Json:
{
myString=null
}
Response:
error must not be blank
Optional
代替@Null
,在参数列表中使用方法重载代替@Null
:dolszewski.com/java/java-8-optional-use-cases* The annotated element must not be {@code null}. * Accepts any type.
,我认为应该将 must 单词替换为 should 但这又取决于您如何阅读它.肯定有更多的澄清会很好null
但允许的地方使用注释,则说明您使用了错误的注释。该术语并不意味着它已被验证。但是,暗示它未经验证不会受到伤害。如果要添加自动验证,可以使用一些外部工具。例如,IntelliJ IDE 内置了对注入空检查的支持。