메소드 인수에서 NotNull 어노테이션 사용


156

방금 @NotNullJava 8 에서 주석을 사용하고 예기치 않은 결과를 얻었습니다.

다음과 같은 방법이 있습니다.

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

searchList 인수에 대해 null 값을 전달하는 JUnit 테스트를 작성했습니다. 어떤 유형의 오류가 발생할 것으로 예상했지만 주석이없는 것처럼 진행되었습니다. 이것이 예상되는 동작입니까? 내가 이해 한 바에 따르면, 상용구 null 확인 코드 작성을 건너 뛸 수 있습니다.

@NotNull이 정확히 무엇을하는지에 대한 설명은 크게 감사하겠습니다.


29
@NotNull그냥 주석입니다. 주석은 아무 것도하지 않습니다. 컴파일 타임에 주석 프로세서가 필요하거나 런타임에 주석 처리기가 필요합니다.
Sotirios Delimanolis

응용 프로그램 서버 내에서 코드를 실행하고 있습니까 (예 : Arquillian 사용 )?
jabu.10245

1
@SotiriosDelimanolis-그렇다면 요점은 무엇입니까, null 값을 전달하지 않도록 메소드를 호출하는 사람에게 경고? 이 경우 여전히 널 포인터 유효성 검사 코드가 필요합니다.
DavidR

1
최대 절전 모드 검사기
arisalexis

@ jabu.10245-응용 프로그램 서버를 사용하지 않습니다.
DavidR

답변:


183

@Nullable그리고 @NotNull아무것도하지 마십시오. 그것들은 문서 도구로 작용해야합니다.

@Nullable주석이 때 NPE 확인을 소개하는 필요성에 대해 생각 나게한다 :

  1. null을 돌려주는 메소드 호출
  2. null 일 수있는 역 참조 변수 (필드, 로컬 변수, 매개 변수)

@NotNull주석 실제로, 다음을 선언하는 명시 적 계약이다 :

  1. 메소드는 널을 리턴해서는 안됩니다.
  2. (필드, 로컬 변수, 파라미터 등) 변수는 없다 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 (봄에 예를 들어.와 최대 절전 모드).

@NotNull때문에 주석은 자신이 검증하지 않는다는 주석 정의가 어떤 제공하지 않습니다 ConstraintValidator유형 참조.

자세한 내용은 다음을 참조하십시오.

  1. 빈 검증
  2. NotNull.java
  3. 제약 사항 .java
  4. ConstraintValidator.java

3
따라서 NotNull 부분의 2 부를 명확히하기 위해, 실제로 강제 할 수 없기 때문에 "할 수 없음"이 아니라 "하지 않아야합니다"라고 말해야합니까? 또는 런타임에 시행 할 수 있다면 어떻게 할 것입니까?
DavidR

그렇습니다. "실행해서는 안됩니다"... 메소드 구현은 계약을 시행해야합니다.
justAnotherUser ...

1
또는 Java 8에서는 반환 값 대신 에 매개 변수 목록 대신 메서드 오버로드를 Optional사용할 수 있습니다 . dolszewski.com/java/java-8-optional-use-cases@Null@Null
Chad K

13
혼란은 NotNull 주석의 Java 문서에서 비롯된 * The annotated element must not be {@code null}. * Accepts any type.것이라고 생각 합니다. 단어를 바꿔야 하지만 다시 읽는 방법에 따라 달라집니다. 분명히 더 많은 설명이 필요합니다
Julian

@Julian 나는 추천이 아니라 규칙이기 때문에 올바른 용어 라고 생각 합니다 . 전달 해서는 안되지만 null허용되는 주석을 사용하면 주석이 잘못 사용 된 것입니다. 이 용어는 그것이 유효하다는 것을 의미하지는 않습니다. 그러나 확인되지 않은 힌트는 아프지 않습니다. 자동 유효성 검사를 추가하려는 경우 일부 외부 도구를 사용할 수 있습니다. 예를 들어, IntelliJ IDE에는 널 검사를 주입하기위한 지원 기능이 내장되어 있습니다.
JojOatXGME

27

위에서 언급했듯이 @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");
    }
}

6
그냥 팁. 한 줄로 그러한 과제를 작성할 수도 있습니다.this.bar = Objects.requireNonNull(bar, "bar must not be null");
lolung

팁 @lolung에 감사드립니다-귀하의 의견에 따라 도청 된 위의 코드를 업데이트했습니다.
Bollywood


6

@NotNull은 태그 일뿐입니다 ... 유효성을 확인하려면 최대 절전 모드 유효성 검사기 jsr 303과 같은 것을 사용해야합니다

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

방법의 시작 부분에서 이것을 어디에 두어야합니까?
DavidR

예.. 메소드의 시작 부분에서 ... 이것은 검증 구현 중 하나 일뿐입니다. 다른 것들도있을 수 있습니다 ...
Naruto

확인. 그러나 그 코드가 무엇을 의미하는지는 param 인수에 @NotNull 주석이 있는지 여부를 변경하지 않습니까?
DavidR

이제 세트에 모든 위반이 있고 크기를 확인한 다음 0보다 크면 메서드에서 돌아옵니다.
나루토


2

내 자신의 유효성 검사 주석과 유효성 검사기를 만들려면 다음과 같이하십시오.

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

check와 매우 비슷한 것을 할 수 있습니다 @NotNull.


0

테스트에서 메소드 유효성 검증을 테스트하려면 @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));

}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.