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

98

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

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

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

Спасибо

Теги:
reflection
getter

4 ответа

200
Лучший ответ

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

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 поставляется с другими удобными материалами. то есть преобразование значения "на лету" (объект в строку, строку в объект), чтобы упростить настройку свойств из пользовательского ввода.

  • 2
    +1 просто верно ... совершенно верно;)
  • 0
    Большое спасибо! Это избавило меня от струнных манипуляций и т.д!
Показать ещё 3 комментария
13

Вы можете использовать Reflections для этого

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

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

3

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню