Лучший способ вызвать геттер с помощью отражения

Мне нужно получить значение поля с определенной аннотацией, поэтому с отражением я могу получить этот объект поля. Проблема в том, что это поле всегда будет приватным, хотя я заранее знаю, что у него всегда будет метод получения. Я знаю, что могу использовать setAccesible (true) и получить его значение (когда нет PermissionManager), хотя я предпочитаю вызывать его метод получения.

Я знаю, что могу найти метод, выполнив поиск «get + fieldName» (хотя я знаю, например, что логические поля иногда называются «is + fieldName»).

Интересно, есть ли лучший способ вызвать этот геттер (многие фреймворки используют геттеры / сеттеры для доступа к атрибутам, поэтому, возможно, они делают по-другому).

Спасибо


person Javi    schedule 14.04.2010    source источник


Ответы (4)


Я думаю, это должно указать вам правильное направление:

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

Обратите внимание, что вы можете создавать экземпляры BeanInfo или PropertyDescriptor самостоятельно, то есть без использования Introspector. Однако Introspector выполняет внутреннее кэширование, что обычно является хорошей вещью (tm). Если вы счастливы без кеша, вы можете даже пойти на

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

Однако существует множество библиотек, расширяющих и упрощающих API java.beans. Commons BeanUtils - хорошо известный пример. Там вы просто сделаете:

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

BeanUtils поставляется с другими полезными вещами. то есть преобразование значений на лету (объект в строку, строка в объект) для упрощения настройки свойств из пользовательского ввода.

person sfussenegger    schedule 14.04.2010
comment
Большое спасибо! Это избавило меня от манипуляций со струнами и т. Д.! - person guerda; 06.12.2012
comment
Хороший вызов Apache BeanUtils. Упрощает получение / настройку свойств и обрабатывает преобразование типов. - person Peter Tseng; 18.12.2012
comment
Есть ли способ вызвать методы в том порядке, в котором поля перечислены в файле Java? - person LifeAndHope; 21.06.2015
comment
Посмотрите мой ответ ниже @Anand - person Anand; 30.07.2015
comment
Очень понравилось! Потрясающие. - person smilyface; 24.06.2019
comment
Обычно я ненавижу зависеть от зависимостей, но этот вариант хорош в ряде ситуаций, когда у вас есть общие данные, передаваемые в - person DGoiko; 23.07.2019
comment
проблема с PropertyDescriptor заключается в том, что он требует наличия получателя и установщика этого свойства, и возможно, что вы не захотите иметь некоторые из них. - person Lucke; 21.09.2020

Для этого можно использовать структуру Reflections

import static org.reflections.ReflectionUtils.*;
Set<Method> getters = ReflectionUtils.getAllMethods(someClass,
      withModifier(Modifier.PUBLIC), withPrefix("get"), withAnnotation(annotation));
person Naveedur Rahman    schedule 02.12.2013
comment
Помните, что Reflections по-прежнему несовместима с Java 9. Есть ссылки для улучшения работы ClassIndex (время компиляции) и ClassGraph (время выполнения) альтернативы от трех. - person Vadzim; 23.05.2019
comment
Это решение также не принимает во внимание методы получения * в отличие от bean Introspector в принятом ответе. - person Vadzim; 24.05.2019

Соглашение об именах является частью хорошо зарекомендовавшего себя JavaBeans спецификации и поддерживается классами в java. фасоль.

person Michael Borgwardt    schedule 14.04.2010

Вы можете вызывать отражения, а также устанавливать порядок последовательности для получателя значений с помощью аннотаций.

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

Вывод при сортировке

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