Beste Art, Getter durch Reflexion aufzurufen

127

Ich muss den Wert eines Feldes mit einer bestimmten Anmerkung erhalten. Mit Reflexion kann ich dieses Feldobjekt erhalten. Das Problem ist, dass dieses Feld immer privat sein wird, obwohl ich im Voraus weiß, dass es immer eine Getter-Methode haben wird. Ich weiß, dass ich setAccesible (true) verwenden und seinen Wert abrufen kann (wenn es keinen PermissionManager gibt), obwohl ich es vorziehe, seine Getter-Methode aufzurufen.

Ich weiß, dass ich nach der Methode suchen könnte, indem ich nach "get + fieldName" suche (obwohl ich zum Beispiel weiß, dass boolesche Felder manchmal als "is + fieldName" bezeichnet werden).

Ich frage mich, ob es einen besseren Weg gibt, diesen Getter aufzurufen (viele Frameworks verwenden Getter / Setter, um auf die Attribute zuzugreifen, also tun sie dies möglicherweise auf andere Weise).

Vielen Dank

Javi
quelle

Antworten:

240

Ich denke, das sollte Sie in die richtige Richtung weisen:

import java.beans.*

for (PropertyDescriptor pd : Introspector.getBeanInfo(Foo.class).getPropertyDescriptors()) {
  if (pd.getReadMethod() != null && !"class".equals(pd.getName()))
    System.out.println(pd.getReadMethod().invoke(foo));
}

Beachten Sie, dass Sie BeanInfo- oder PropertyDescriptor-Instanzen selbst erstellen können, dh ohne Introspector zu verwenden. Introspector führt jedoch intern ein Caching durch, was normalerweise eine gute Sache (tm) ist. Wenn Sie ohne Cache glücklich sind, können Sie sogar gehen

// TODO check for non-existing readMethod
Object value = new PropertyDescriptor("name", Person.class).getReadMethod().invoke(person);

Es gibt jedoch viele Bibliotheken, die die java.beans-API erweitern und vereinfachen. Commons BeanUtils ist ein bekanntes Beispiel. Dort würden Sie einfach tun:

Object value = PropertyUtils.getProperty(person, "name");

BeanUtils kommt mit anderen praktischen Sachen. dh sofortige Konvertierung von Werten (Objekt zu Zeichenfolge, Zeichenfolge zu Objekt), um die Einstellungseigenschaften aus Benutzereingaben zu vereinfachen.

sfussenegger
quelle
Vielen Dank! Das hat mich von Saitenmanipulationen usw. verschont!
Guerda
1
Guter Anruf bei Apaches BeanUtils. Erleichtert das Abrufen / Festlegen von Eigenschaften und übernimmt die Typkonvertierung.
Peter Tseng
Gibt es eine Möglichkeit, die Methoden in der Reihenfolge aufzurufen, in der die Felder in der Java-Datei aufgeführt sind?
LifeAndHope
Schauen Sie sich meine Antwort unten an @Anand
Anand
Liebte es! Genial.
Smilyface
20

Sie können hierfür das Reflections- Framework verwenden

import static org.reflections.ReflectionUtils.*;
Set<Method> getters = ReflectionUtils.getAllMethods(someClass,
      withModifier(Modifier.PUBLIC), withPrefix("get"), withAnnotation(annotation));
Naveedur Rahman
quelle
Beachten Sie, dass Reflections immer noch nicht mit Java 9 kompatibel ist . Es gibt Links für ein besseres Verhalten von ClassIndex- (Kompilierungszeit) und ClassGraph- (Laufzeit) Alternativen von threre.
Vadzim
Diese Lösung berücksichtigt auch nicht * Getter im Gegensatz zu Bean Introspector in der akzeptierten Antwort.
Vadzim
3

Sie können Reflexionen aufrufen und durch Annotationen die Reihenfolge für den Getter für Werte festlegen

public class Student {

    private String grade;

    private String name;

    private String id;

    private String gender;

    private Method[] methods;

    @Retention(RetentionPolicy.RUNTIME)
    public @interface Order {
        int value();
    }

    /**
     * Sort methods as per Order Annotations
     * 
     * @return
     */
    private void sortMethods() {

        methods = Student.class.getMethods();

        Arrays.sort(methods, new Comparator<Method>() {
            public int compare(Method o1, Method o2) {
                Order or1 = o1.getAnnotation(Order.class);
                Order or2 = o2.getAnnotation(Order.class);
                if (or1 != null && or2 != null) {
                    return or1.value() - or2.value();
                }
                else if (or1 != null && or2 == null) {
                    return -1;
                }
                else if (or1 == null && or2 != null) {
                    return 1;
                }
                return o1.getName().compareTo(o2.getName());
            }
        });
    }

    /**
     * Read Elements
     * 
     * @return
     */
    public void readElements() {
        int pos = 0;
        /**
         * Sort Methods
         */
        if (methods == null) {
            sortMethods();
        }
        for (Method method : methods) {
            String name = method.getName();
            if (name.startsWith("get") && !name.equalsIgnoreCase("getClass")) {
                pos++;
                String value = "";
                try {
                    value = (String) method.invoke(this);
                }
                catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                    e.printStackTrace();
                }
                System.out.println(name + " Pos: " + pos + " Value: " + value);
            }
        }
    }

    // /////////////////////// Getter and Setter Methods

    /**
     * @param grade
     * @param name
     * @param id
     * @param gender
     */
    public Student(String grade, String name, String id, String gender) {
        super();
        this.grade = grade;
        this.name = name;
        this.id = id;
        this.gender = gender;
    }

    /**
     * @return the grade
     */
    @Order(value = 4)
    public String getGrade() {
        return grade;
    }

    /**
     * @param grade the grade to set
     */
    public void setGrade(String grade) {
        this.grade = grade;
    }

    /**
     * @return the name
     */
    @Order(value = 2)
    public String getName() {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @return the id
     */
    @Order(value = 1)
    public String getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(String id) {
        this.id = id;
    }

    /**
     * @return the gender
     */
    @Order(value = 3)
    public String getGender() {
        return gender;
    }

    /**
     * @param gender the gender to set
     */
    public void setGender(String gender) {
        this.gender = gender;
    }

    /**
     * Main
     * 
     * @param args
     * @throws IOException
     * @throws SQLException
     * @throws InvocationTargetException
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     */
    public static void main(String args[]) throws IOException, SQLException, IllegalAccessException,
            IllegalArgumentException, InvocationTargetException {
        Student student = new Student("A", "Anand", "001", "Male");
        student.readElements();
    }
  }

Ausgabe beim Sortieren

getId Pos: 1 Value: 001
getName Pos: 2 Value: Anand
getGender Pos: 3 Value: Male
getGrade Pos: 4 Value: A
Anand
quelle