Ist es möglich, den Wert einer Anmerkung in Java zu lesen?


98

Das ist mein Code:

@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;
 }

Ist es möglich, den Wert meiner Anmerkung @Column ( columnName = "xyz123") in einer anderen Klasse zu lesen ?

Antworten:


122

Ja, wenn Ihre Spaltenanmerkung die Laufzeitaufbewahrung aufweist

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

Sie können so etwas tun

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

UPDATE: Um private Felder abzurufen, verwenden Sie

Myclass.class.getDeclaredFields()

1
Ich mag deine Lösung. Wie können wir es generischer machen als anstelle von MyClass? Ich möchte T wie für verwenden (Feld f: T.class.getFields ()) {Column column = f.getAnnotation (Column.class); if (column! = null) System.out.println (column.columnName ()); }
ATHER

1
Genau! Ich habe mich bemüht, das auch herauszufinden. Was ist, wenn ich einen Anmerkungsprozessor haben möchte, der nicht explizit mit einem Klassennamen versehen werden muss? Kann es dazu gebracht werden, es aus dem Kontext aufzunehmen? 'Dies'??
5122014009

Ich bin mir nicht sicher, ob ich verstehe, was Sie beide brauchen. Bitte stellen Sie dies als neue Frage mit einem vollständigen Beispiel. Sie können es hier verlinken, wenn Sie möchten.
Kopffüßer

3
Verwenden Sie Myclass.class.getDeclaredFields(), um private Felder zu erhalten
q0re

Es hat bei mir funktioniert. Vielen Dank. Ich suchte nach privaten Feldern der Superklasse, also benutzte ich clsName.getSuperclass (). GetDeclaredFields ()
Shashank

88

Natürlich ist es das. Hier ist eine Beispielanmerkung:

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

    String testText();
}

Und eine kommentierte Beispielmethode:

class TestClass {

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

Und eine Beispielmethode in einer anderen Klasse, die den Wert des testText druckt:

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());
    }
}

Nicht viel anders für Feldanmerkungen wie Ihre.

Cheerz!


21

Ich habe es noch nie gemacht, aber es sieht so aus, als ob Reflection dies bietet. Fieldist ein AnnotatedElementund so hat es getAnnotation. Diese Seite enthält ein Beispiel (unten kopiert). Ganz einfach, wenn Sie die Klasse der Annotation kennen und wenn die Annotationsrichtlinie die Annotation zur Laufzeit beibehält. Wenn die Aufbewahrungsrichtlinie die Anmerkung zur Laufzeit nicht beibehält, können Sie sie zur Laufzeit natürlich nicht abfragen.

Eine Antwort, die inzwischen gelöscht wurde (?), Bietet einen nützlichen Link zu einem Tutorial zu Anmerkungen , das Sie möglicherweise hilfreich finden. Ich habe den Link hier kopiert, damit die Leute ihn verwenden können.

Beispiel von dieser Seite :

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);
  }
}

6

Wenn Sie auf die Antwort von @Cephalopod eingehen und alle Spaltennamen in einer Liste haben möchten, können Sie diesen Oneliner verwenden:

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());

Objects.nonNull, um Java 8 vollständig zu nutzen :) .filter (f -> nonNull (f.getAnnotation (Column.class)))
Entmenschlichung

4

Während alle bisher gegebenen Antworten vollkommen gültig sind, sollte man auch die Google Reflections-Bibliothek berücksichtigen, um einen allgemeineren und einfacheren Ansatz für das Scannen von Anmerkungen zu erhalten, z

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

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

3

Sie können in meinem Fall auch generische Typen verwenden, wobei Sie alles berücksichtigen, was gesagt wurde, bevor Sie etwas tun können wie:

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();

    }

}

Denken Sie daran, dass dies nicht zu 100% mit SomeClass.class.get (...) () übereinstimmt.

Aber kann den Trick machen ...


3

In der Regel haben Sie privaten Zugriff auf Felder, sodass Sie getFields NICHT in Reflection verwenden können. Stattdessen sollten Sie getDeclaredFields verwenden

Zunächst sollten Sie sich also darüber im Klaren sein, ob Ihre Spaltenanmerkung die Laufzeitaufbewahrung aufweist:

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

Danach können Sie so etwas tun:

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

Natürlich möchten Sie etwas mit dem Feld tun - setzen Sie einen neuen Wert mit dem Anmerkungswert:

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

Der vollständige Code kann also folgendermaßen aussehen:

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()
                )
        );
}

2

Für die wenigen Menschen, die nach einer generischen Methode fragen, sollte dies hilfreich sein (5 Jahre später: p).

In meinem folgenden Beispiel ziehe ich den RequestMapping-URL-Wert aus Methoden mit der RequestMapping-Annotation. Um dies für Felder anzupassen, ändern Sie einfach die

for (Method method: clazz.getMethods())

zu

for (Field field: clazz.getFields())

Tauschen Sie die Verwendung von RequestMapping gegen die Anmerkungen aus, die Sie lesen möchten . Stellen Sie jedoch sicher, dass die Annotation @Retention (RetentionPolicy.RUNTIME) enthält .

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 "";
}

0

eine der Möglichkeiten, wie ich es benutzt habe:

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;
}    
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.