Yöntem bağımsız değişkeninde NotNull Ek Açıklama'yı kullanma


156

@NotNullJava 8 ile ek açıklamayı kullanmaya ve beklenmedik sonuçlar elde etmeye başladım .

Ben böyle bir yöntem var:

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

SearchList argümanı için null değerinde geçen bir JUnit testi yazdım. Bir tür hatanın olmasını bekliyordum ama ek açıklama orada değilmiş gibi geçti. Bu beklenen davranış mı? Anladığım kadarıyla, bu, boş levha null kontrol kodunu yazmayı atlamanıza izin vermekti.

@NotNull'un tam olarak ne yapması gerektiğine dair bir açıklama çok takdir edilecektir.


29
@NotNullsadece bir ek açıklamadır. Ek açıklamalar kendi başlarına hiçbir şey yapmaz. Derleme zamanında bir ek açıklama işlemcisine veya çalışma zamanında işleyen bir şeye ihtiyaçları vardır.
Sotirios Delimanolis

Kodu bir uygulama sunucusunda mı çalıştırıyorsunuz (örneğin Arquillian kullanarak )?
jabu.10245

1
@SotiriosDelimanolis - Öyleyse bunun anlamı nedir, yöntemi çağıran herkese bir null değeri geçmemesi için bir uyarı mı? Bu durumda yine de boş işaretçi doğrulama koduna ihtiyacınız vardır.
DavidR

1
hazırda bekleme doğrulayıcı bak
arisalexis

@ jabu.10245 - Hiçbir uygulama sunucusu kullanmıyor.
DavidR

Yanıtlar:


183

@Nullableve @NotNullkendi başlarına hiçbir şey yapma. Dokümantasyon araçları gibi davranmaları gerekiyor.

@NullableEk Açıklama sırasında bir NPE çeki tanıtmak gerekliliği hakkında size hatırlatır:

  1. Boş dönebilen çağrı yöntemleri.
  2. Boş olabilen kayıttan çıkarma değişkenleri (alanlar, yerel değişkenler, parametreler).

@NotNullEk açıklama, aslında, aşağıdakileri bildirerek açık sözleşmedir:

  1. Bir yöntem null döndürmemelidir.
  2. (Alanların, yerel değişkenler ve parametreler gibi) Bir değişken olamaz olmamalı boş değer tutun.

Örneğin, yazmak yerine:

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

Kullanabilirsiniz:

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

Ayrıca, @NotNullgenellikle ConstraintValidators tarafından kontrol edilir (örneğin, ilkbahar ve hazırda bekletme modunda).

@NotNullÇünkü açıklama kendi başına herhangi doğrulama yapmaz açıklama tanım herhangi sağlamaz ConstraintValidatortip referansı.

Daha fazla bilgi için:

  1. Fasulye validasyonu
  2. NotNull.java
  3. Constraint.java
  4. ConstraintValidator.java

3
Yani sadece NotNull bölümünün 2. bölümünü açıklığa kavuşturmak için, gerçekten zorlanamayacağı için “yapmamalı”, “yapamaz” demeli mi? Ya da çalışma zamanında uygulanabiliyorsa, bunu nasıl yapardınız?
DavidR

Evet, onun bir "olmamalı" ... yöntem uygulama sözleşmeyi yürürlüğe koymalıdır.
justAnotherUser ...

1
Alternatif olarak, Java 8'de, Optionalyerine kullanılabilir @Nulldönüş değerleri ve yöntemi yerine aşırı @Nullparametre listelerinde: dolszewski.com/java/java-8-optional-use-cases
Çad K

13
Ben karışıklık NotNull ek açıklama java doc gelir inanıyoruz: * The annotated element must not be {@code null}. * Accepts any type.ve sanırım zorunluluk ile kelime değiştirilmesi gerektiğini gerektiği ama yine onu okuyarak nasıl bağlıdır. Kesinlikle daha fazla açıklama yapmak iyi olurdu
Julian

@Julian sanırım doğru terim olmalı çünkü bir kural değil, bir öneri değil. Eğer ek açıklama kullanırsanız nerede olmamalıdır geçmesi nullEk açıklamalarda yanlış kullanıyor, ancak izin verilecek. Terim, valide edildiği anlamına gelmez. Ancak, onaylanmadığına dair bir ipucu incitmez. Otomatik doğrulama eklemek istiyorsanız, bazı harici araçlar kullanabilirsiniz. Örneğin, IntelliJ IDE'nin boş denetimleri enjekte etmek için yerleşik desteği vardır.
JojOatXGME

27

Yukarıda belirtildiği gibi @NotNulltek başına hiçbir şey yapmaz. Kullanmanın iyi bir yolu @NotNullile kullanmaya olurduObjects.requireNonNull

public class Foo {
    private final Bar bar;

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

6
Sadece bir ipucu. Ayrıca bu gibi ödevleri bir satırla da yazabilirsiniz:this.bar = Objects.requireNonNull(bar, "bar must not be null");
lolung

@Lolung ipucu için teşekkürler - Şimdi yorumunuza göre yukarıdaki kodu snipped güncelledik.
Bollywood


6

SO @NotNull sadece bir etiket ... Eğer doğrulamak istiyorsanız, o zaman hazırda bekleme doğrulayıcısı jsr 303 gibi bir şey kullanmalısınız

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

Yöntemin başında bunu nereye koyabilirim?
DavidR

evet .. yöntemin başlangıcında ... bu doğrulama uygulamalarından sadece biri, başkaları da olabilir ...
Naruto

Tamam. Ama bu kod ne bu önemi, param argümanında @NotNull ek açıklama olsun ya da olmasın değişmez?
DavidR

Şimdi sette tüm İhlali var, boyutunu kontrol edin, sıfırdan büyükse, yöntemden dönün.
Naruto


2

Kendi doğrulama notumu ve doğrulayıcıyı oluşturmak için bunu yapıyorum:

ValidCardType.java(yöntem / alan eklemek için ek açıklama)

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

Ve, kontrolü tetikleyen doğrulayıcı 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));
    }
}

Kontrol etmek için çok benzer bir şey yapabilirsiniz @NotNull.


0

Bir testte yöntem doğrulamanızı test etmek için, @Before yönteminde bir proxy'yi sarmanız gerekir.

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

MethodValidationProxyFactory ile şu şekilde:

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

}

Ardından, testinizi ekleyin:

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

}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.