web-dev-qa-db-fra.com

Meilleure façon d'invoquer getter par réflexion

Je dois obtenir la valeur d'un champ avec une annotation spécifique. Ainsi, avec réflexion, je peux obtenir cet objet de champ. Le problème est que ce champ sera toujours privé bien que je sache d'avance qu'il aura toujours une méthode getter. Je sais que je peux utiliser setAccesible (true) et obtenir sa valeur (lorsqu'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 + nomChamp" (bien que je sache par exemple que les champs booléens sont parfois nommés "is + nomChamp").

Je me demande s’il existe un meilleur moyen d’appeler ce getter (de nombreux frameworks utilisent des accesseurs/setters pour accéder aux attributs, alors peut-être le font-ils d’une autre manière).

Merci

120
Javi

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 des instances BeanInfo ou PropertyDescriptor vous-même, c'est-à-dire sans utiliser Introspector. Cependant, Introspector effectue une mise en cache interne, ce qui est normalement une bonne chose (Good Thing - tm). Si vous êtes heureux sans cache, vous pouvez même aller chercher

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

Cependant, de nombreuses bibliothèques é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 choses utiles. c'est-à-dire une conversion à la volée (objet en chaîne, chaîne en objet) pour simplifier la définition des propriétés à partir d'une entrée utilisateur.

225
sfussenegger

Vous pouvez utiliser le cadre Reflections pour cela

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

La convention de dénomination fait partie de la spécification bien établie JavaBeans et est prise en charge par les classes du package Java.beans .

4
Michael Borgwardt

Vous pouvez invoquer des réflexions et également définir l'ordre de la séquence pour getter pour les valeurs par le biais d'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 après tri

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