क्या जावा में एनोटेशन इनहेरिटेंस जैसा कुछ है?


119

मैं एनोटेशन की खोज कर रहा हूं और एक ऐसे बिंदु पर आया हूं जहां कुछ एनोटेशन में उनके बीच एक पदानुक्रम है।

मैं कार्ड के लिए पृष्ठभूमि में कोड उत्पन्न करने के लिए एनोटेशन का उपयोग कर रहा हूं। कार्ड के विभिन्न प्रकार (इस प्रकार विभिन्न कोड और एनोटेशन) हैं, लेकिन कुछ ऐसे तत्व हैं जो उनके बीच एक नाम की तरह आम हैं।

@Target(value = {ElementType.TYPE})
public @interface Move extends Page{
 String method1();
 String method2();
}

और यह सामान्य व्याख्या होगी:

@Target(value = {ElementType.TYPE})
public @interface Page{
 String method3();
}

ऊपर दिए गए उदाहरण में मुझे उम्मीद है कि Move to inherit method3 होगा, लेकिन मुझे यह कहते हुए एक चेतावनी मिलती है कि इसका विस्तार एनोटेशन के साथ मान्य नहीं है। मैं कोशिश कर रहा था कि एक एनोटेशन एक आम आधार को बढ़ाता है लेकिन वह काम नहीं करता है। यह भी संभव है या सिर्फ एक डिजाइन मुद्दा है?


3
एनोटेशन के आधार पर डीएसएल बनाने के लिए एनोटेशन वंशानुक्रम लगता है। इस तरह की अफ़सोस की बात है कि एनोटेशन वंशानुक्रम समर्थित नहीं है।
19

2
मैं सहमत हूं, ऐसा करना एक स्वाभाविक बात है। विशेष रूप से जावा पर विरासत को समझने के बाद, आप इसे हर चीज पर लागू करने की अपेक्षा करते हैं।
javydreamercsw

जवाबों:


76

दुर्भाग्यवश नहीं। जाहिरा तौर पर यह उन कार्यक्रमों के साथ कुछ करना है जो एक वर्ग पर एनोटेशन को पढ़ने के लिए उन्हें पूरे तरीके से लोड किए बिना करते हैं। देखें कि जावा में एनोटेशन का विस्तार क्यों संभव नहीं है?

हालाँकि, यदि वे एनोटेशन हैं, तो प्रकार उनके सुपरक्लास के एनोटेशन को प्राप्त करते हैं @Inherited

इसके अलावा, जब तक कि आपको बातचीत करने के लिए उन तरीकों की आवश्यकता न हो, आप अपनी कक्षा में केवल एनोटेशन को रोक सकते हैं:

@Move
@Page
public class myAwesomeClass {}

क्या कोई कारण है जो आपके लिए काम नहीं करेगा?


1
यही मैंने सोचा था लेकिन मैं चीजों को आसान बनाने की कोशिश कर रहा था। हो सकता है कि आम को एक अमूर्त वर्ग में लागू करने से चाल
चल पड़े

1
हाँ, यह बहुत चालाक लग रहा था। सौभाग्य!
andronikus

67

आप अपने एनोटेशन को वंशानुक्रम के बजाय आधार एनोटेशन के साथ एनोटेट कर सकते हैं। इसका उपयोग स्प्रिंग फ्रेमवर्क में किया जाता है

एक उदाहरण देना है

@Target(value = {ElementType.ANNOTATION_TYPE})
public @interface Vehicle {
}

@Target(value = {ElementType.TYPE})
@Vehicle
public @interface Car {
}

@Car
class Foo {
}

आप तब जांच सकते हैं कि क्या किसी वर्ग को स्प्रिंग एनोटेशन यूटिल्स के Vehicleउपयोग के साथ एनोटेट किया गया है :

Vehicle vehicleAnnotation = AnnotationUtils.findAnnotation (Foo.class, Vehicle.class);
boolean isAnnotated = vehicleAnnotation != null;

इस विधि को इस प्रकार लागू किया जाता है:

public static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType) {
    return findAnnotation(clazz, annotationType, new HashSet<Annotation>());
}

@SuppressWarnings("unchecked")
private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType, Set<Annotation> visited) {
    try {
        Annotation[] anns = clazz.getDeclaredAnnotations();
        for (Annotation ann : anns) {
            if (ann.annotationType() == annotationType) {
                return (A) ann;
            }
        }
        for (Annotation ann : anns) {
            if (!isInJavaLangAnnotationPackage(ann) && visited.add(ann)) {
                A annotation = findAnnotation(ann.annotationType(), annotationType, visited);
                if (annotation != null) {
                    return annotation;
                }
            }
        }
    }
    catch (Exception ex) {
        handleIntrospectionFailure(clazz, ex);
        return null;
    }

    for (Class<?> ifc : clazz.getInterfaces()) {
        A annotation = findAnnotation(ifc, annotationType, visited);
        if (annotation != null) {
            return annotation;
        }
    }

    Class<?> superclass = clazz.getSuperclass();
    if (superclass == null || Object.class == superclass) {
        return null;
    }
    return findAnnotation(superclass, annotationType, visited);
}

AnnotationUtilsतरीकों और अन्य एनोटेट तत्वों पर एनोटेशन की खोज के लिए अतिरिक्त तरीके भी शामिल हैं। स्प्रिंग क्लास भी शक्तिशाली तरीके से खोज करने के लिए काफी शक्तिशाली है, परदे के पीछे, और अन्य कोने-मामलों, विशेष रूप से स्प्रिंग में सामना करना पड़ा।


13
कृपया इस तरह के एनोटेशन को संसाधित करने के तरीके की व्याख्या शामिल करें।
०१३ फ़िनिश डेबिनस्की

1
आप वसंत के AnnotationUtils.findAnnotation (..) का उपयोग कर सकते, देखें: docs.spring.io/spring/docs/current/javadoc-api/org/...
rgrebski

2
जब एनोटेशन ए को अन्य एनोटेशन बी के साथ एनोटेट किया जाता है, और हम क्लास सी को ए के साथ एनोटेट करते हैं, तो क्लास सी को ए और बी दोनों के साथ एनोटेट माना जाता है। यह स्प्रिंग फ्रेमवर्क का विशिष्ट व्यवहार है - एनोटेशन यूजिल्स.फ़ेड एन्नोटेशन मैजिक करता है यहाँ एक एनोटेशन के एनोटेशन को खोजने के लिए ट्राउजर का उपयोग किया जाता है। इसलिए गलतफहमी न पालें कि यह एनोटेशन हैंडलिंग से संबंधित जावा का डिफ़ॉल्ट व्यवहार है।
qartal

यह तभी संभव है जब आप जो एनोटेशन रचना करना चाहते हैं, उसका एक लक्ष्य हो TYPEया ANNOTATION_TYPE
ऑरेंजडॉग

7

Grygoriys के अलावा एनोटेटिंग एनोटेशन का जवाब।

आप इस लूप द्वारा @Qualifierएनोटेशन (या एनोटेशन युक्त एनोटेशन) युक्त उदाहरणों की जांच कर सकते हैं @Qualifier:

for (Annotation a : method.getAnnotations()) {
    if (a.annotationType().isAnnotationPresent(Qualifier.class)) {
        System.out.println("found @Qualifier annotation");//found annotation having Qualifier annotation itself
    }
}

आप मूल रूप से जो कर रहे हैं, वह है कि सभी एनोटेशन को पद्धति पर मौजूद करें और उन एनोटेशन से आप अपने प्रकार प्राप्त करें और उन प्रकारों की जांच करें यदि वे @Qualifier के साथ एनोटेट हैं। इस कार्य को प्राप्त करने के लिए आपके एनोटेशन को Target.Annotation_type सक्षम होना चाहिए।


यह ग्रिगोरिए के उत्तर से कैसे भिन्न है?
Aleksandr Dubinsky

@AleksandrDubinsky: बसंत का उपयोग किए बिना यह बहुत सरल कार्यान्वयन है। यह पुनरावर्ती एनोटेट एनोटेशन को पुन: खोज नहीं करता है, लेकिन मुझे लगता है कि यह आमतौर पर आवश्यक नहीं है। मुझे इस समाधान की सरलता पसंद है।
स्टीफन स्टाइनगर

1

Https://github.com/blindpirate/annotation-magic की जाँच करें , जो एक पुस्तकालय है जिसे मैंने तब विकसित किया था जब मेरे पास एक ही प्रश्न था।

@interface Animal {
    boolean fluffy() default false;

    String name() default "";
}

@Extends(Animal.class)
@Animal(fluffy = true)
@interface Pet {
    String name();
}

@Extends(Pet.class)
@interface Cat {
    @AliasFor("name")
    String value();
}

@Extends(Pet.class)
@interface Dog {
    String name();
}

@interface Rat {
    @AliasFor(target = Animal.class, value = "name")
    String value();
}

@Cat("Tom")
class MyClass {
    @Dog(name = "Spike")
    @Rat("Jerry")
    public void foo() {
    }
}

        Pet petAnnotation = AnnotationMagic.getOneAnnotationOnClassOrNull(MyClass.class, Pet.class);
        assertEquals("Tom", petAnnotation.name());
        assertTrue(AnnotationMagic.instanceOf(petAnnotation, Animal.class));

        Animal animalAnnotation = AnnotationMagic.getOneAnnotationOnClassOrNull(MyClass.class, Animal.class);
        assertTrue(animalAnnotation.fluffy());

        Method fooMethod = MyClass.class.getMethod("foo");
        List<Animal> animalAnnotations = AnnotationMagic.getAnnotationsOnMethod(fooMethod, Animal.class);
        assertEquals(Arrays.asList("Spike", "Jerry"), animalAnnotations.stream().map(Animal::name).collect(toList()));
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.