Il modo migliore per invocare il getter mediante la riflessione


127

Ho bisogno di ottenere il valore di un campo con un'annotazione specifica, quindi con la riflessione sono in grado di ottenere questo oggetto campo. Il problema è che questo campo sarà sempre privato anche se so in anticipo che avrà sempre un metodo migliore. So che posso usare setAccesible (true) e ottenere il suo valore (quando non c'è PermissionManager), anche se preferisco invocare il suo metodo getter.

So che potrei cercare il metodo cercando "get + fieldName" (anche se so per esempio che i campi booleani sono talvolta chiamati come "is + fieldName").

Mi chiedo se esiste un modo migliore per invocare questo getter (molti framework usano getter / setter per accedere agli attributi, quindi forse lo fanno in un altro modo).

Grazie

Risposte:


241

Penso che questo dovrebbe indirizzarti verso la giusta direzione:

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

Si noti che è possibile creare istanze BeanInfo o PropertyDescriptor, ad esempio senza utilizzare Introspector. Tuttavia, Introspector esegue internamente la memorizzazione nella cache, che normalmente è una buona cosa (tm). Se sei felice senza cache, puoi anche provare

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

Tuttavia, ci sono molte librerie che estendono e semplificano l'API java.beans. Commons BeanUtils è un esempio ben noto. Lì, faresti semplicemente:

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

BeanUtils viene fornito con altre cose utili. vale a dire conversione al volo (oggetto in stringa, stringa in oggetto) per semplificare l'impostazione delle proprietà dall'input dell'utente.


Grazie mille! Questo mi ha risparmiato dalle manipolazioni delle stringhe ecc.!
guerda,

1
Buona chiamata su BeanUtils di Apache. Semplifica il recupero / impostazione delle proprietà e gestisce la conversione dei tipi.
Peter Tseng,

C'è un modo per invocare i metodi nell'ordine in cui i campi sono elencati nel file Java?
LifeAndHope,

Guarda la mia risposta qui sotto @Anand
Anand

Lo amo ! Eccezionale.
smilyface,

20

È possibile utilizzare il framework Reflections per questo

import static org.reflections.ReflectionUtils.*;
Set<Method> getters = ReflectionUtils.getAllMethods(someClass,
      withModifier(Modifier.PUBLIC), withPrefix("get"), withAnnotation(annotation));

Attenzione che Reflections non è ancora compatibile con Java 9 . Ci sono collegamenti per le migliori alternative ClassIndex (tempo di compilazione) e ClassGraph (tempo di esecuzione) da tre.
Vadzim,

Questa soluzione inoltre non tiene conto del fatto che * getters diversamente dal bean Introspector nella risposta accettata.
Vadzim,


3

È possibile richiamare le riflessioni e, inoltre, impostare l'ordine di sequenza per getter per i valori tramite annotazioni

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

Uscita quando ordinato

getId Pos: 1 Value: 001
getName Pos: 2 Value: Anand
getGender Pos: 3 Value: Male
getGrade Pos: 4 Value: A
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.