Apakah mungkin untuk membaca nilai anotasi di java?

99

ini kode saya:

@Column(columnName="firstname")


private String firstName;

 @Column(columnName="lastname")
 private String lastName;

 public String getFirstName() {
  return firstName;
 }

 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }

 public String getLastName() {
  return lastName;
 }

 public void setLastName(String lastName) {
  this.lastName = lastName;
 }

apakah mungkin untuk membaca nilai dari penjelasan saya @column ( columnName = "XYZ123") di kelas lain?

BeeS
sumber

Jawaban:

122

Ya, jika anotasi Kolom Anda memiliki retensi waktu proses

@Retention(RetentionPolicy.RUNTIME)
@interface Column {
    ....
}

Anda bisa melakukan sesuatu seperti ini

for (Field f: MyClass.class.getFields()) {
   Column column = f.getAnnotation(Column.class);
   if (column != null)
       System.out.println(column.columnName());
}

UPDATE: Untuk menggunakan bidang pribadi

Myclass.class.getDeclaredFields()
Cephalopoda
sumber
1
Saya suka solusi Anda. Bagaimana kita bisa membuatnya lebih generik seperti daripada MyClass saya ingin menggunakan T seperti untuk (Field f: T.class.getFields ()) {Column column = f.getAnnotation (Column.class); jika (kolom! = null) System.out.println (column.columnName ()); }
SEBELUM
1
Persis! Saya telah berjuang untuk mencari tahu juga. Bagaimana jika saya ingin memiliki prosesor anotasi yang tidak perlu diberikan nama kelas secara eksplisit? Bisakah itu dibuat untuk mengambilnya dari konteksnya; 'ini'??
5122014009
Saya tidak yakin saya mengerti apa yang Anda berdua butuhkan. Silakan tanyakan itu sebagai pertanyaan baru dengan contoh lengkap. Anda dapat menautkannya di sini jika mau.
Cephalopoda
3
Gunakan Myclass.class.getDeclaredFields()untuk mendapatkan bidang pribadi
q0re
Itu berhasil untuk saya. Terima kasih. Saya mencari bidang privat superclass jadi saya menggunakan clsName.getSuperclass (). GetDeclaredFields ()
Shashank
88

Tentu saja. Berikut ini contoh anotasi:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {

    String testText();
}

Dan contoh metode beranotasi:

class TestClass {

    @TestAnnotation(testText="zyx")
    public void doSomething() {}
}

Dan metode sampel di kelas lain yang mencetak nilai testText:

Method[] methods = TestClass.class.getMethods();
for (Method m : methods) {
    if (m.isAnnotationPresent(TestAnnotation.class)) {
        TestAnnotation ta = m.getAnnotation(TestAnnotation.class);
        System.out.println(ta.testText());
    }
}

Tidak jauh berbeda untuk anotasi bidang seperti milik Anda.

Cheerz!

Lachezar Balev
sumber
21

Saya belum pernah melakukannya, tetapi sepertinya Refleksi menyediakan ini. Fieldadalah AnnotatedElementdan begitulah adanya getAnnotation. Halaman ini memiliki contoh (disalin di bawah); cukup mudah jika Anda mengetahui kelas anotasi dan jika kebijakan anotasi mempertahankan anotasi pada waktu proses. Biasanya jika kebijakan penyimpanan tidak menyimpan anotasi pada waktu proses, Anda tidak akan dapat menanyakannya pada waktu proses.

Jawaban yang telah dihapus (?) Memberikan tautan yang berguna ke tutorial anotasi yang mungkin berguna bagi Anda; Saya telah menyalin tautan di sini sehingga orang dapat menggunakannya.

Contoh dari halaman ini :

import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno {
  String str();

  int val();
}

class Meta {
  @MyAnno(str = "Two Parameters", val = 19)
  public static void myMeth(String str, int i) {
    Meta ob = new Meta();

    try {
      Class c = ob.getClass();

      Method m = c.getMethod("myMeth", String.class, int.class);

      MyAnno anno = m.getAnnotation(MyAnno.class);

      System.out.println(anno.str() + " " + anno.val());
    } catch (NoSuchMethodException exc) {
      System.out.println("Method Not Found.");
    }
  }

  public static void main(String args[]) {
    myMeth("test", 10);
  }
}
TJ Crowder
sumber
6

Menguraikan jawaban @Cephalopod, jika Anda ingin semua nama kolom dalam daftar, Anda dapat menggunakan oneliner ini:

List<String> columns = 
        Arrays.asList(MyClass.class.getFields())
              .stream()
              .filter(f -> f.getAnnotation(Column.class)!=null)
              .map(f -> f.getAnnotation(Column.class).columnName())
              .collect(Collectors.toList());
Simon Baars
sumber
Objects.nonNull untuk sepenuhnya merangkul Java 8 :) .filter (f -> nonNull (f.getAnnotation (Column.class)))
dehumanizer
4

Sementara semua jawaban yang diberikan sejauh ini benar-benar valid, kita juga harus mengingat perpustakaan refleksi google untuk pendekatan yang lebih umum dan mudah untuk pemindaian anotasi, mis.

 Reflections reflections = new Reflections("my.project.prefix");

 Set<Field> ids = reflections.getFieldsAnnotatedWith(javax.persistence.Id.class);
Fritz Duchardt
sumber
3

Anda juga dapat menggunakan tipe generik, dalam kasus saya, dengan mempertimbangkan semua yang dikatakan sebelum Anda dapat melakukan sesuatu seperti:

public class SomeTypeManager<T> {

    public SomeTypeManager(T someGeneric) {

        //That's how you can achieve all previously said, with generic types.
        Annotation[] an = someGeneric.getClass().getAnnotations();

    }

}

Ingat, bahwa ini tidak akan setara 100% dengan SomeClass.class.get (...) ();

Tapi bisa melakukan trik ...

SigmaSoldier
sumber
3

Dalam kasus umum, Anda memiliki akses pribadi untuk bidang, jadi Anda TIDAK DAPAT menggunakan getFields dalam refleksi. Sebagai gantinya, Anda harus menggunakan getDeclaredFields

Jadi, pertama-tama, Anda harus waspada jika anotasi Kolom Anda memiliki retensi waktu proses:

@Retention(RetentionPolicy.RUNTIME)
@interface Column {
}

Setelah itu Anda bisa melakukan sesuatu seperti ini:

for (Field f: MyClass.class.getDeclaredFields()) {
   Column column = f.getAnnotation(Column.class);
       // ...
}

Jelas, Anda ingin melakukan sesuatu dengan bidang - setel nilai baru menggunakan nilai anotasi:

Column annotation = f.getAnnotation(Column.class);
if (annotation != null) {
    new PropertyDescriptor(f.getName(), Column.class).getWriteMethod().invoke(
        object,
        myCoolProcessing(
            annotation.value()
        )
    );
}

Jadi, kode lengkapnya bisa terlihat seperti ini:

for (Field f : MyClass.class.getDeclaredFields()) {
    Column annotation = f.getAnnotation(Column.class);
    if (annotation != null)
        new PropertyDescriptor(f.getName(), Column.class).getWriteMethod().invoke(
                object,
                myCoolProcessing(
                        annotation.value()
                )
        );
}
Oleg Poltoratskii
sumber
2

Untuk beberapa orang yang meminta metode umum, ini akan membantu Anda (5 tahun kemudian: p).

Untuk contoh saya di bawah ini, saya menarik nilai URL RequestMapping dari metode yang memiliki anotasi RequestMapping. Untuk menyesuaikan ini untuk bidang, cukup ubah

for (Method method: clazz.getMethods())

untuk

for (Field field: clazz.getFields())

Dan tukar penggunaan RequestMapping dengan anotasi apa pun yang ingin Anda baca. Namun pastikan anotasi tersebut memiliki @Retention (RetentionPolicy.RUNTIME) .

public static String getRequestMappingUrl(final Class<?> clazz, final String methodName)
{
    // Only continue if the method name is not empty.
    if ((methodName != null) && (methodName.trim().length() > 0))
    {
        RequestMapping tmpRequestMapping;
        String[] tmpValues;

        // Loop over all methods in the class.
        for (Method method: clazz.getMethods())
        {
            // If the current method name matches the expected method name, then keep going.
            if (methodName.equalsIgnoreCase(method.getName()))
            {
                // Try to extract the RequestMapping annotation from the current method.
                tmpRequestMapping = method.getAnnotation(RequestMapping.class);

                // Only continue if the current method has the RequestMapping annotation.
                if (tmpRequestMapping != null)
                {
                    // Extract the values from the RequestMapping annotation.
                    tmpValues = tmpRequestMapping.value();

                    // Only continue if there are values.
                    if ((tmpValues != null) && (tmpValues.length > 0))
                    {
                        // Return the 1st value.
                        return tmpValues[0];
                    }
                }
            }
        }
    }

    // Since no value was returned, log it and return an empty string.
    logger.error("Failed to find RequestMapping annotation value for method: " + methodName);

    return "";
}
MattWeiler
sumber
0

salah satu cara saya menggunakannya:

protected List<Field> getFieldsWithJsonView(Class sourceClass, Class jsonViewName){
    List<Field> fields = new ArrayList<>();
    for (Field field : sourceClass.getDeclaredFields()) {
        JsonView jsonViewAnnotation = field.getDeclaredAnnotation(JsonView.class);
        if(jsonViewAnnotation!=null){
            boolean jsonViewPresent = false;
            Class[] viewNames = jsonViewAnnotation.value();
            if(jsonViewName!=null && Arrays.asList(viewNames).contains(jsonViewName) ){
                fields.add(field);
            }
        }
    }
    return fields;
}    
RK Punjal
sumber