Meilleur moyen d'invoquer getter par réflexion


127

J'ai besoin d'obtenir la valeur d'un champ avec une annotation spécifique, donc avec la réflexion, je suis capable d'obtenir cet objet de champ. Le problème est que ce champ sera toujours privé bien que je sache à l'avance qu'il aura toujours une méthode getter. Je sais que je peux utiliser setAccesible (true) et obtenir sa valeur (quand il n'y a pas de PermissionManager), bien que je préfère invoquer sa méthode getter.

Je sais que je pourrais rechercher la méthode en recherchant "get + fieldName" (bien que je sache par exemple que les champs booléens sont parfois appelés "is + fieldName").

Je me demande s'il existe une meilleure façon d'invoquer ce getter (de nombreux frameworks utilisent des getters / setters pour accéder aux attributs, alors peut-être qu'ils le font d'une autre manière).

Merci

Réponses:


241

Je pense que cela devrait vous orienter dans la bonne direction:

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

Notez que vous pouvez créer vous-même des instances BeanInfo ou PropertyDescriptor, c'est-à-dire sans utiliser Introspector. Cependant, Introspector effectue une certaine mise en cache en interne, ce qui est normalement une bonne chose (tm). Si vous êtes heureux sans cache, vous pouvez même opter pour

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

Cependant, il existe de nombreuses bibliothèques qui étendent et simplifient l'API java.beans. Commons BeanUtils est un exemple bien connu. Là, vous feriez simplement:

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

BeanUtils est livré avec d'autres trucs pratiques. c.-à-d. conversion de valeur à la volée (objet en chaîne, chaîne en objet) pour simplifier la définition des propriétés à partir de l'entrée utilisateur.


Merci beaucoup! Cela m'a épargné les manipulations de cordes, etc.
guerda

1
Bon appel à BeanUtils d'Apache. Facilite l'obtention / la définition des propriétés et gère la conversion de type.
Peter Tseng

Existe-t-il un moyen d'appeler les méthodes dans l'ordre dans lequel les champs sont répertoriés dans le fichier Java?
LifeAndHope

Regardez ma réponse ci-dessous @Anand
Anand

J'ai adoré! Impressionnant.
smilyface

20

Vous pouvez utiliser le framework Reflections pour cela

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

Attention, Reflections n'est toujours pas compatible avec Java 9 . Il existe des liens pour un meilleur comportement des alternatives ClassIndex (au moment de la compilation) et ClassGraph (au moment de l'exécution) de threre.
Vadzim

Cette solution ne prend pas non plus en compte les getters * contrairement au bean Introspector dans la réponse acceptée.
Vadzim


3

Vous pouvez invoquer des réflexions et également définir l'ordre de séquence du getter pour les valeurs via des annotations

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

Sortie une fois triée

getId Pos: 1 Value: 001
getName Pos: 2 Value: Anand
getGender Pos: 3 Value: Male
getGrade Pos: 4 Value: A
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.