มีบางอย่างเช่น Annotation Inheritance ใน java หรือไม่?


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
การสืบทอดคำอธิบายประกอบดูเหมือนจะเป็นสิ่งที่ต้องมีสำหรับการสร้าง DSL ตามคำอธิบายประกอบ น่าเสียดายที่ไม่รองรับการสืบทอดคำอธิบายประกอบ
Ceki

2
ฉันเห็นด้วยดูเหมือนเป็นเรื่องธรรมดาที่ต้องทำ โดยเฉพาะอย่างยิ่งหลังจากเข้าใจการสืบทอดบน Java คุณคาดหวังว่ามันจะนำไปใช้กับทุกสิ่ง
javydreamercsw

คำตอบ:


76

น่าเสียดายที่ไม่มี เห็นได้ชัดว่ามีบางอย่างเกี่ยวข้องกับโปรแกรมที่อ่านคำอธิบายประกอบในชั้นเรียนโดยไม่ต้องโหลดเลย ดูเหตุใดจึงไม่สามารถขยายคำอธิบายประกอบใน Java ได้

อย่างไรก็ตามประเภทจะได้รับมรดกคำอธิบายประกอบของ superclass @Inheritedของพวกเขาหากผู้ที่มีคำอธิบายประกอบ

นอกจากนี้หากคุณไม่ต้องการวิธีการเหล่านั้นในการโต้ตอบคุณสามารถซ้อนคำอธิบายประกอบในชั้นเรียนของคุณได้:

@Move
@Page
public class myAwesomeClass {}

มีเหตุผลบางอย่างที่ไม่เหมาะกับคุณหรือไม่?


1
นั่นคือสิ่งที่ฉันคิด แต่ฉันพยายามทำให้สิ่งต่างๆง่ายขึ้น บางทีการใช้ Common หนึ่งกับคลาสนามธรรมอาจทำเคล็ดลับ ...
javydreamercsw

1
ใช่มันดูฉลาดเกินไป โชคดี!
andronikus

67

คุณสามารถใส่คำอธิบายประกอบของคุณด้วยคำอธิบายประกอบพื้นฐานแทนการสืบทอด นี้จะนำมาใช้ในกรอบฤดูใบไม้ผลิ

เพื่อเป็นตัวอย่าง

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

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

@Car
class Foo {
}

จากนั้นคุณสามารถตรวจสอบว่าคลาสถูกใส่คำอธิบายประกอบVehicleโดยใช้Spring's AnnotationUtils หรือไม่ :

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นอกจากนี้ยังมีวิธีการเพิ่มเติมสำหรับการค้นหาคำอธิบายประกอบเกี่ยวกับวิธีการและองค์ประกอบคำอธิบายประกอบอื่น ๆ คลาส Spring ยังมีประสิทธิภาพมากพอที่จะค้นหาด้วยวิธีการเชื่อมต่อพร็อกซีและกรณีมุมอื่น ๆ โดยเฉพาะอย่างยิ่งที่พบใน Spring


13
โปรดใส่คำอธิบายวิธีดำเนินการกับคำอธิบายประกอบดังกล่าว
Aleksandr Dubinsky

1
คุณสามารถใช้ AnnotationUtils.findAnnotation ของ Spring (.. ) ได้ที่: docs.spring.io/spring/docs/current/javadoc-api/org/…
rgrebski

2
เมื่อคำอธิบายประกอบ A ถูกใส่คำอธิบายประกอบด้วยคำอธิบายประกอบ B อื่นและเราใส่คำอธิบายประกอบคลาส C ด้วย A คลาส C จะได้รับการปฏิบัติราวกับว่ามีการใส่คำอธิบายประกอบด้วยทั้ง A และ B นี่คือลักษณะการทำงานเฉพาะของ Spring framework - AnnotationUtils.findAnnotation ทำเวทมนตร์ ที่นี่และใช้เพื่อสำรวจเพื่อค้นหาคำอธิบายประกอบของคำอธิบายประกอบ ดังนั้นอย่าเข้าใจผิดว่านี่เป็นพฤติกรรมเริ่มต้นของ Java ที่เกี่ยวข้องกับการจัดการคำอธิบายประกอบ
qartal

นี้เป็นไปได้เฉพาะในกรณีที่คำอธิบายประกอบที่คุณต้องการในการเขียนมีเป้าหมายของการหรือTYPE ANNOTATION_TYPE
OrangeDog

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 เปิดใช้งานเช่นกันเพื่อให้สามารถใช้งานได้


สิ่งนี้แตกต่างจากคำตอบของ Grygoriy อย่างไร?
Aleksandr Dubinsky

@AleksandrDubinsky: เป็นการใช้งานที่ง่ายกว่ามากโดยไม่ต้องใช้ Spring ไม่พบคำอธิบายประกอบที่มีคำอธิบายประกอบซ้ำ ๆ แต่ฉันเดาว่าโดยปกติแล้วไม่จำเป็นต้องใช้ ฉันชอบความเรียบง่ายของโซลูชันนี้
Stefan Steinegger

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()));
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.