Menukar Parameter Anotasi Pada Masa Jalan

1. Gambaran keseluruhan

Anotasi , bentuk metadata yang boleh anda tambahkan ke kod Java. Ini anotasi boleh diproses pada masa kompil dan terbenam pada fail kelas atau boleh disimpan dan diakses pada masa berjalan menggunakan Reflection .

Dalam artikel ini, kita akan membincangkan cara mengubah nilai anotasi semasa menjalankan menggunakan Refleksi . Kami akan menggunakan anotasi peringkat kelas untuk contoh ini.

2. Anotasi

Java membolehkan membuat anotasi baru menggunakan yang sudah ada. Dalam bentuk paling mudah, anotasi dilambangkan sebagai simbol @ diikuti dengan nama anotasi:

@Override

Mari buat anotasi Greeter kami sendiri :

@Retention(RetentionPolicy.RUNTIME) public @interface Greeter { public String greet() default ""; }

Sekarang, kami akan membuat Salam kelas Java yang menggunakan anotasi peringkat kelas :

@Greeter(greet="Good morning") public class Greetings {} 

Sekarang, kita akan mengakses nilai anotasi menggunakan pantulan. Kelas kelas Java menyediakan kaedah getAnnotation untuk mengakses anotasi kelas:

Greeter greetings = Greetings.class.getAnnotation(Greeter.class); System.out.println("Hello there, " + greetings.greet() + " !!");

3. Perubahan Anotasi

Kelas kelas Java mengekalkan peta untuk menguruskan anotasi - Kelas anotasi sebagai kunci dan objek Anotasi sebagai nilai:

Map
    
      map;
    

Kami akan mengemas kini peta ini untuk mengubah anotasi semasa menjalankan. Pendekatan untuk mengakses peta ini berbeza dalam pelbagai pelaksanaan JDK. Kami akan membincangkannya untuk JDK7 dan JDK8.

3.1. Pelaksanaan JDK 7

Kelas kelas Java mempunyai anotasi lapangan . Oleh kerana ini adalah medan peribadi, untuk mengaksesnya, kita harus menetapkan aksesibilitas bidang menjadi benar . Java menyediakan kaedah getDeclaredField untuk mengakses bidang apa pun dengan namanya:

Field annotations = Class.class.getDeclaredField(ANNOTATIONS); annotations.setAccessible(true); 

Sekarang, mari dapatkan akses ke peta anotasi untuk kelas Greeter :

 Map
    
      map = annotations.get(targetClass);
    

Sekarang, ini adalah peta yang mengandungi maklumat tentang semua anotasi dan objek nilai mereka. Kami ingin mengubah nilai anotasi Greeter yang dapat kami capai dengan mengemas kini objek anotasi kelas Greeter :

map.put(targetAnnotation, targetValue);

3.2. Pelaksanaan JDK 8

Implementasi Java 8 menyimpan maklumat anotasi di dalam AnnotationData kelas . Kita boleh mengakses objek ini menggunakan kaedah annotationData . Kami akan menetapkan kebolehcapaian untuk kaedah annotationData menjadi benar kerana ia adalah kaedah peribadi:

Method method = Class.class.getDeclaredMethod(ANNOTATION_METHOD, null); method.setAccessible(true);

Sekarang, kita dapat mengakses medan anotasi . Oleh kerana bidang ini juga merupakan bidang persendirian, kami akan menetapkan aksesibilitas menjadi benar :

Field annotations = annotationData.getClass().getDeclaredField(ANNOTATIONS); annotations.setAccessible(true);

Medan ini mempunyai peta cache anotasi yang menyimpan kelas anotasi dan objek nilai. Mari ubah:

Map
    
      map = annotations.get(annotationData); map.put(targetAnnotation, targetValue);
    

4. Permohonan

Mari kita ambil contoh ini:

Greeter greetings = Greetings.class.getAnnotation(Greeter.class); System.err.println("Hello there, " + greetings.greet() + " !!");

Ini akan memberi ucapan "Selamat pagi" kerana itulah nilai yang kami berikan untuk penjelasan.

Sekarang, kami akan membuat satu lagi objek jenis Greeter dengan nilai sebagai "Selamat petang":

Greeter targetValue = new DynamicGreeter("Good evening"); 

Mari kemas kini peta anotasi dengan nilai baru:

alterAnnotationValueJDK8(Greetings.class, Greeter.class, targetValue);

Mari kita periksa nilai ucapan sekali lagi:

greetings = Greetings.class.getAnnotation(Greeter.class); System.err.println("Hello there, " + greetings.greet() + " !!");

Ia akan disambut sebagai "Selamat petang".

5. Kesimpulan

Implementasi Java menggunakan dua bidang data untuk menyimpan data anotasi : anotasi , dinyatakanAnotasi . Perbezaan antara kedua-duanya: anotasi kedai pertama dari kelas induk juga dan satu kedai hanya untuk kelas semasa.

Oleh kerana pelaksanaan getAnnotation berbeza dalam JDK 7 dan JDK 8, kami menggunakan peta medan anotasi di sini untuk kesederhanaan.

Dan, seperti biasa, kod sumber pelaksanaan tersedia di Github.