Mengapa tidak mungkin memperpanjang anotasi di Jawa?

227

Saya tidak mengerti mengapa tidak ada warisan dalam penjelasan Java, sama seperti kelas Java. Saya pikir itu akan sangat berguna.

Sebagai contoh: Saya ingin tahu apakah anotasi yang diberikan adalah validator. Dengan pewarisan, saya secara refleks dapat menavigasi melalui kacamata super untuk mengetahui apakah anotasi ini meluas a ValidatorAnnotation. Kalau tidak, bagaimana saya bisa mencapai ini?

Jadi, adakah yang bisa memberi saya alasan untuk keputusan desain ini?

sinuhepop
sumber
2
Perhatikan, BTW, bahwa semua anotasi diperluas java.lang.annotation.Annotation, yaitu anotasi apa pun instanceofitu meskipun fakta ini tidak secara eksplisit dinyatakan.
Tomáš Záluský

Jawaban:

166

Tentang alasan mengapa itu tidak dirancang sedemikian rupa Anda dapat menemukan jawabannya di FAQ Desain JSR 175 , di mana katanya:

Mengapa Anda tidak mendukung subtipe anotasi (di mana satu jenis anotasi meluas yang lain)?

Ini menyulitkan sistem jenis anotasi, dan membuatnya jauh lebih sulit untuk menulis "Alat Khusus".

...

"Alat Tertentu" - Program yang menanyakan jenis penjelasan yang diketahui dari program eksternal yang arbitrer. Generator rintisan, misalnya, termasuk dalam kategori ini. Program-program ini akan membaca kelas beranotasi tanpa memuatnya ke mesin virtual, tetapi akan memuat antarmuka anotasi.

Jadi, ya saya kira, alasannya hanya CIUMAN. Bagaimanapun, sepertinya masalah ini (bersama dengan banyak yang lain) sedang dipertimbangkan sebagai bagian dari JSR 308 , dan Anda bahkan dapat menemukan kompiler alternatif dengan fungsi ini yang sudah dikembangkan oleh Mathias Ricken .

pedromarce
sumber
67
Yah, mungkin saya bodoh, tapi saya rasa sayang sekali tidak bisa memperpanjang anotasi hanya untuk "tetap sederhana". Setidaknya, Jawa desainer tidak berpikir sama tentang warisan kelas: P
sinuhepop
2
Java 8 M7, tampaknya tidak mendukung anotasi sub-klasifikasi. Sayang sekali.
Ceki
2
@assylias JEP 104 bukan tentang membuatnya mungkin untuk subkelas anotasi. JEP 104 diimplementasikan di Java 8, tetapi masih tidak mungkin untuk mensubclot anotasi (membuat satu anotasi memperpanjang anotasi lain).
Jesper
71

Anotasi yang diperluas dapat secara efektif menambah beban menentukan dan memelihara sistem tipe lain. Dan ini akan menjadi sistem tipe yang cukup unik, jadi Anda tidak bisa begitu saja menerapkan paradigma tipe OO.

Pikirkan semua masalah saat Anda memperkenalkan polimorfisme dan pewarisan ke anotasi (mis. Apa yang terjadi ketika sub-anotasi mengubah spesifikasi meta-anotasi seperti retensi?)

Dan semua ini menambah kompleksitas untuk kasus penggunaan apa?

Anda ingin tahu apakah anotasi yang diberikan termasuk dalam kategori?

Coba ini:

@Target(ElementType.ANNOTATION_TYPE)
public @interface Category {
    String category();
}

@Category(category="validator")
public @interface MyFooBarValidator {

}

Seperti yang Anda lihat, Anda dapat dengan mudah mengelompokkan dan mengelompokkan anotasi tanpa rasa sakit yang tidak perlu menggunakan fasilitas yang disediakan.

Jadi, KISS adalah alasan untuk tidak memperkenalkan sistem tipe meta-type ke bahasa Java.

[ps edit]

Saya menggunakan String hanya untuk demonstrasi dan mengingat penjelasan meta terbuka berakhir. Untuk proyek Anda sendiri, Anda jelas dapat menggunakan enum tipe kategori dan menentukan beberapa kategori ("multiple inheritance") untuk anotasi yang diberikan. Perhatikan bahwa nilainya sepenuhnya palsu dan hanya untuk tujuan demonstrasi:

@Target(ElementType.ANNOTATION_TYPE)
public @interface Category {
    AnnotationCategory[] category();
}
public enum AnnotationCategory {
    GENERAL,
    SEMANTICS,
    VALIDATION,
    ETC
}

@Category(category={AnnotationCategory.GENERAL, AnnotationCategory.SEMANTICS})
public @interface FooBarAnnotation {

}

alphazero
sumber
Tidak Bekerja akan mencetak false:@Target(ElementType.ANNOTATION_TYPE) @Retention(RetentionPolicy.RUNTIME) @interface C {}; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @C public @interface F {} class a{ @F public void S() {} } @Test public void blahTest() throws NoSuchMethodException { Method m = a.class.getMethod("S"); System.out.println(m.isAnnotationPresent(C.class)); }
user1615664
Kami memberi anotasi pada anotasi. a # S memiliki anotasi F. F sendiri dianotasi oleh C. Coba itu.
alphazero
Ya itu benar. Tetapi apakah ada cara untuk melakukannya dengan lebih bersih daripada membaca proxy Annotation?
user1615664
12

Dalam arti Anda sudah memilikinya dengan Anotasi - meta Anotasi. Jika Anda memberikan anotasi dengan informasi meta, itu dalam banyak hal setara dengan memperluas antarmuka tambahan. Anotasi adalah antarmuka, sehingga polimorfisme tidak benar-benar berperan, dan karena sifatnya statis, tidak mungkin ada pengiriman dinamis runtime.

Dalam contoh validator Anda, Anda bisa saja pada anotasi mendapatkan tipe yang dianotasi dan melihat apakah ana tersebut memiliki meta-anotasi validator.

Satu-satunya use case yang saya dapat lihat bahwa pewarisan akan membantu adalah jika Anda ingin bisa mendapatkan anotasi dengan tipe super, tetapi itu akan menambah kerumitan, karena metode atau tipe yang diberikan mungkin memiliki dua anotasi seperti itu, artinya sebuah array harus dikembalikan, bukan hanya satu objek.

Jadi saya pikir jawaban akhirnya adalah bahwa use case bersifat esoterik dan memperumit case use yang lebih standar sehingga tidak layak.

Yishai
sumber
5

Para perancang dukungan anotasi Java membuat sejumlah "penyederhanaan" yang merugikan komunitas Jawa.

  1. Tidak ada subtipe anotasi yang membuat banyak anotasi kompleks menjadi jelek. Seseorang tidak bisa hanya memiliki atribut dalam anotasi yang dapat menampung satu dari tiga hal. Seseorang perlu memiliki tiga atribut terpisah, yang membingungkan pengembang dan memerlukan validasi runtime untuk memastikan bahwa hanya satu dari tiga yang digunakan.

  2. Hanya satu anotasi dari jenis yang diberikan per situs. Hal ini menyebabkan pola anotasi koleksi yang sama sekali tidak perlu. @Validation dan @Validations, @Image dan @Images, dll.

Yang kedua sedang diperbaiki di Jawa 8, tetapi sudah terlambat. Banyak kerangka kerja telah ditulis berdasarkan apa yang mungkin di Java 5 dan sekarang kutil API ini ada di sini untuk waktu yang lama.

Konstantin Komissarchik
sumber
1
Tidak hanya itu, itu juga membuat tidak mungkin untuk mendefinisikan properti yang memiliki atribut bersarang secara rekursif - yang didukung oleh skema XML. Ini membuat anotasi benar-benar kurang kuat daripada XML
user2833557
3

Saya mungkin terlambat tiga tahun dalam menanggapi pertanyaan ini, tetapi saya menemukan itu menarik karena saya menemukan diri saya di tempat yang sama. Inilah pendapat saya. Anda dapat melihat anotasi sebagai Enums. Mereka menyediakan jenis informasi satu arah - gunakan atau hilangkan.

Saya memiliki situasi di mana saya ingin mensimulasikan GET, POST, PUT dan DELETE dalam aplikasi web. Saya sangat ingin memiliki anotasi "super" yang disebut "HTTP_METHOD". Kemudian saya sadar bahwa itu tidak masalah. Yah, saya harus puas dengan menggunakan bidang tersembunyi dalam bentuk HTML untuk mengidentifikasi DELETE dan PUT (karena POST dan GET tersedia juga).

Di sisi server, saya mencari parameter permintaan tersembunyi dengan nama, "_method". Jika nilainya PUT atau DELETE, maka nilai tersebut melampaui metode permintaan HTTP terkait. Karena itu, tidak masalah apakah saya perlu memperpanjang anotasi untuk menyelesaikan pekerjaan. Semua penjelasan tampak sama, tetapi mereka diperlakukan secara berbeda di sisi server.

Jadi dalam kasus Anda, jatuhkan gatal untuk memperpanjang anotasi. Perlakukan mereka sebagai 'spidol'. Mereka "mewakili" beberapa informasi, dan tidak harus "memanipulasi" beberapa informasi.

mainas
sumber
2

Satu hal yang bisa saya pikirkan adalah kemungkinan memiliki banyak anotasi. Jadi, Anda dapat menambahkan validator dan anotasi yang lebih spesifik di tempat yang sama. Tapi saya bisa saja salah :)

Janusz
sumber
2

Tidak pernah memikirkan hal itu tetapi ... sepertinya Anda benar, tidak ada masalah dengan fasilitas pewarisan anotasi (setidaknya saya tidak melihat masalah dengan itu).

Tentang contoh Anda dengan anotasi 'validator' - Anda dapat mengeksploitasi pendekatan 'meta-annotation' . Yaitu Anda menerapkan meta-anotasi khusus untuk seluruh antarmuka anotasi.

denis.zhdanov
sumber
Saya mungkin terlambat tiga tahun dalam menanggapi pertanyaan ini, tetapi saya menemukan itu menarik karena saya menemukan diri saya di tempat yang sama.
mainas
1

masalah yang sama yang saya miliki. Tidak bisa. Saya 'mendisiplinkan' diri saya sendiri untuk menulis properti dalam anotasi untuk menghormati beberapa standar, jadi di luar ketika Anda mendapatkan anotasi, Anda dapat 'mengendus' jenis anotasi apa itu menurut properti yang dimilikinya.

ante.sabo
sumber