विधि तर्क में NotNull एनोटेशन का उपयोग करना


156

मैंने अभी @NotNullजावा 8 के साथ एनोटेशन का उपयोग करना शुरू किया और कुछ अप्रत्याशित परिणाम प्राप्त किए।

मेरे पास एक तरीका है:

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

मैंने तर्क खोजकर्ता के लिए शून्य मान में पास होने वाला JUnit परीक्षण लिखा। मैं किसी प्रकार की त्रुटि होने की उम्मीद कर रहा था, लेकिन यह इस तरह से गुजर रहा था जैसे कि एनोटेशन नहीं था। क्या यह अपेक्षित व्यवहार है? मुझे जो समझ में आया, वह यह था कि आप बॉयलरप्लेट नल चेक कोड लिखना छोड़ दें।

क्या वास्तव में @NotNull क्या करना चाहिए की एक व्याख्या बहुत सराहना की जाएगी।


29
@NotNullसिर्फ एक एनोटेशन है। एनोटेशन अपने दम पर कुछ नहीं करते हैं। उन्हें संकलन समय पर एक एनोटेशन प्रोसेसर की आवश्यकता होती है, या ऐसा कुछ जो इसे रनटाइम पर संसाधित करता है।
सोतिरियोस डेलिमोलिसिन 17

क्या आप एक एप्लिकेशन सर्वर के अंदर कोड चला रहे हैं (उदाहरण के लिए Arquillian का उपयोग करके )?
jabu.10245

1
@SotiriosDelimanolis - तो क्या बात है, बस किसी को भी चेतावनी देने के लिए एक विधि के लिए एक अशक्त मूल्य पारित नहीं है? जिस स्थिति में आपको अभी भी अशक्त सूचक सत्यापन कोड की आवश्यकता है।
डेविड डिक

1
हाइबरनेट सत्यापनकर्ता को देखें
arisalexis

@ jabu.10245 - किसी भी एप्लिकेशन सर्वर का उपयोग नहीं करना।
डेविड डीआर

जवाबों:


183

@Nullableऔर @NotNullअपने दम पर कुछ नहीं करते। वे दस्तावेज़ीकरण उपकरण के रूप में कार्य करने वाले हैं।

@Nullableएनोटेशन आवश्यकता एक एनपीई जांच जब शुरू करने की बारे में याद दिलाता:

  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 (वसंत ऋतु में जैसे। और हाइबरनेट)।

@NotNullएनोटेशन अपने दम पर किसी भी सत्यापन नहीं करता है क्योंकि एनोटेशन परिभाषा किसी भी प्रदान नहीं करता है ConstraintValidatorप्रकार संदर्भ।

अधिक जानकारी के लिए देखें:

  1. बीन सत्यापन
  2. NotNull.java
  3. Constraint.java
  4. ConstraintValidator.java

3
तो बस NotNull भाग के भाग 2 को स्पष्ट करने के लिए, वास्तव में इसे "नहीं करना चाहिए" कहना चाहिए, न कि "नहीं" कर सकता क्योंकि यह बिस्तर पर लागू नहीं हो सकता है? या अगर इसे रनटाइम पर लागू किया जा सकता है, तो आप इसके बारे में कैसे जाएंगे?
20

हाँ, इसका "नहीं होना चाहिए" ... विधि के कार्यान्वयन को अनुबंध को लागू करना चाहिए।
justAnotherUser ...

1
वैकल्पिक रूप से, जावा 8 में, रिटर्न वैल्यू के स्थान पर और पैरामीटर सूचियों के स्थान पर ओवरलोडिंग के लिए विधि Optionalका उपयोग किया जा सकता है : dolszewski.com/java/java-8-optional-use-cases@Null@Null
चाड K

13
मेरा मानना है कि भ्रम की स्थिति NotNull एनोटेशन के जावा दस्तावेज़ से आता है: * The annotated element must not be {@code null}. * Accepts any type.और मुझे लगता है कि होना चाहिए के साथ शब्द प्रतिस्थापित किया जाना चाहिए चाहिए लेकिन फिर यह कैसे आप इसे पढ़ के निर्भर करता है। निश्चित रूप से कुछ और स्पष्टीकरण के लिए अच्छा होगा
जूलियन

@Julian मुझे लगता है कि होना चाहिए सही शब्द है, क्योंकि यह एक नियम है, नहीं एक सिफारिश है। यदि आप उस एनोटेशन का उपयोग करते हैं जहाँ आपको पास नहीं होना चाहिएnull लेकिन इसकी अनुमति होगी, तो आप एनोटेशन का उपयोग गलत कर रहे हैं। शब्द का अर्थ यह नहीं है कि यह मान्य है। हालांकि, एक संकेत है कि यह मान्य नहीं है चोट नहीं होगा। यदि आप स्वचालित सत्यापन जोड़ना चाहते हैं, तो आप कुछ बाहरी उपकरणों का उपयोग कर सकते हैं। उदाहरण के लिए, इंटेलीज आईडीई ने अशक्त-जांचों को इंजेक्ट करने के लिए अंतर्निहित समर्थन किया है।
जोजोतएक्सजीएमई

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

टिप के लिए धन्यवाद @ लोलुंग - मैंने अब आपकी टिप्पणी के आधार पर उपर्युक्त कोड को अपडेट कर दिया है।
बॉलीवुड


6

SO @NotNull सिर्फ एक टैग है ... यदि आप इसे सत्यापित करना चाहते हैं, तो आपको हाइबरनेट सत्यापनकर्ता jsr 303 जैसी किसी चीज़ का उपयोग करना चाहिए

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

विधि की शुरुआत में, मैं इसे कहां रखूं?
डेविड डिआर

हां..इस विधि की शुरुआत ... यह सत्यापन कार्यान्वयन में से एक है, अन्य भी हो सकते हैं ...
नारुतो

ठीक। लेकिन उस कोड का यह महत्व इस बात से नहीं बदलेगा कि परम तर्क में मेरे पास @NotNull एनोटेशन है या नहीं?
18

अब आपके पास सेट में सभी उल्लंघन हैं, इसके आकार की जांच करें, यदि इसका अधिक से अधिक शून्य है, तो विधि से वापस लौटें।
नारुतो


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

आप जाँच करने के लिए कुछ समान कर सकते हैं @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));

}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.