Mengapa kelas java tidak mewarisi anotasi dari antarmuka yang diimplementasikan?

108

Saya telah menggunakan AOP Guice untuk mencegat beberapa panggilan metode. Kelas saya mengimplementasikan antarmuka dan saya ingin memberi anotasi pada metode antarmuka sehingga Guice dapat memilih metode yang tepat. Bahkan jika penjelasan jenis ini dijelaskan dengan warisan penjelasan menerapkan kelas tidak mewarisi penjelasan sebagaimana tercantum dalam warisan ini doc java:

Perhatikan juga bahwa meta-annotation ini hanya menyebabkan anotasi diwarisi dari superclass; penjelasan pada antarmuka yang diterapkan tidak berpengaruh.

Apa alasannya? Mengenal semua antarmuka yang diterapkan kelas objek saat runtime bukanlah hal yang sulit untuk dilakukan, jadi harus ada alasan bagus di balik keputusan ini.

Boris Pavlović
sumber

Jawaban:

130

Saya akan mengatakan alasannya adalah bahwa jika tidak, masalah warisan berganda akan terjadi.

Contoh:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Inherited
public @interface Baz { String value(); }

public interface Foo{
    @Baz("baz") void doStuff();
}

public interface Bar{
    @Baz("phleem") void doStuff();
}

public class Flipp{
    @Baz("flopp") public void doStuff(){}
}

public class MyClass extends Flipp implements Foo, Bar{}

Jika saya melakukan ini:

MyClass.class.getMethod("doStuff").getAnnotation(Baz.class).value()

apa hasilnya nanti? 'baz', 'phleem' atau 'flopp'?


Karena alasan ini, anotasi pada antarmuka jarang berguna.

Sean Patrick Floyd
sumber
9
anotasi pada antarmuka hanya berguna jika Anda memiliki kerangka kerja yang mendukungnya. BTW dalam contoh ini getAnnotation () mengembalikan null;)
Peter Lawrey
6
Saya tidak tahu, orang. Dalam kasus ini (jika salah ketik tidak ada), saya mengharapkan The field value is ambiguous.kesalahan kompiler -seperti halnya dengan dua antarmuka yang menyatakan konstanta yang sama dengan nilai yang berbeda. Saya tahu ini bukan kolom, tetapi nilai anotasi diselesaikan pada waktu kompilasi, bukan? Fitur yang kami lewatkan di sini akan sangat membantu dalam banyak kasus. Maaf tentang menghidupkan kembali posting lama, omong-omong :).
Petr Janeček
7
@Slanec melihat cara sumber Musim Semi untuk melihat bagaimana orang Musim Semi mengatasi masalah ini. Lihat AnnotationUtils.findAnnotation (method, annotationType)
Sean Patrick Floyd
1
Saya sedang mempertimbangkan untuk menulis sesuatu yang mirip dengan ini. Dengan semacam cache sederhana, ini sepertinya cara yang tepat bagi saya. Terima kasih! Dalam contoh di atas, ia akan menemukan Fooanotasi ( MyClasstidak ada, kemudian Antarmuka dicari dan diambil dalam urutan setelahnya implements) dan oleh karena itu mencetak "baz". Keren.
Petr Janeček
2
@WChargin benar, hanya butuh 2 tahun bagi seseorang untuk melihat kesalahan ketik itu :-)
Sean Patrick Floyd
35

Dari Javadoc untuk @Inherited:

Menunjukkan bahwa jenis anotasi secara otomatis diwarisi. Jika anotasi meta yang diwarisi ada pada deklarasi jenis anotasi, dan pengguna menanyakan jenis anotasi pada deklarasi kelas, dan deklarasi kelas tidak memiliki anotasi untuk jenis ini, maka kelas super kelas secara otomatis akan ditanyai untuk jenis anotasi tersebut. Proses ini akan diulangi hingga anotasi untuk jenis ini ditemukan, atau puncak hierarki kelas (Objek) tercapai. Jika tidak ada superclass yang memiliki anotasi untuk tipe ini, maka kueri akan menunjukkan bahwa kelas tersebut tidak memiliki anotasi seperti itu. Perhatikan bahwa jenis anotasi meta ini tidak berpengaruh jika jenis anotasi digunakan untuk membuat anotasi selain kelas. Perhatikan juga bahwa meta-annotation ini hanya menyebabkan anotasi diwarisi dari superclass;

Di sisi lain, validator JSR 305 melakukan semacam pencarian warisan. Jika Anda memiliki hierarki kelas:

//Person.java
@Nonnull
 public Integer getAge() {...}

//Student.java (inherits from Person)
@Min(5)
public Integer getAge() {...}

Kemudian validasi efektif pada Student.getAge()are @Nonnull @Min(5). @Nonnulltidak memiliki @Inheritedmeta-annotation.

Eric Jablow
sumber
4
Yang ini harus menjadi jawaban yang dipilih
Andrzej Purtak
3
contoh Anda bertentangan dengan jawaban Anda, yang mengatakan itu @Inheritedtidak berpengaruh pada apa pun selain kelas
Oleg Mikheev
@Diwarisi hanya berfungsi saat Anda menggunakan anotasi di Kelas
Carlos Parker