반사에 의해 게터를 호출하는 가장 좋은 방법


127

특정 주석이있는 필드의 값을 가져와야하므로 반사를 통해이 Field Object를 얻을 수 있습니다. 문제는이 필드가 항상 비공개이지만 항상 getter 메소드가 있음을 알고 있습니다. getAc 메소드를 호출하는 것을 선호하지만 setAccesible (true)을 사용하고 값을 가져올 수 있다는 것을 알고 있습니다 (PermissionManager가 없을 때).

"get + fieldName"을 검색하여 메소드를 찾을 수 있음을 알고 있습니다 (예를 들어 부울 필드의 경우 "is + fieldName"이라고도 함).

이 getter를 호출하는 더 좋은 방법이 있는지 궁금합니다 (많은 프레임 워크가 getters / setter를 사용하여 다른 방식으로 속성에 액세스합니다).

감사

답변:


240

이것이 올바른 방향으로 당신을 가리켜 야한다고 생각합니다.

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

Introspector를 사용하지 않고 BeanInfo 또는 PropertyDescriptor 인스턴스를 직접 작성할 수 있습니다. 그러나 Introspector는 일반적으로 Good Thing (tm) 인 내부에서 일부 캐싱을 수행합니다. 캐시 없이도 행복하다면

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

그러나 java.beans API를 확장하고 단순화하는 많은 라이브러리가 있습니다. Commons BeanUtils는 잘 알려진 예입니다. 거기서 간단하게 할 수 있습니다.

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

BeanUtils는 다른 편리한 것들과 함께 제공됩니다. 즉, 사용자 입력에서 속성 설정을 단순화하기 위해 즉석 값 변환 (객체에서 문자열로, 문자열에서 객체로).


대단히 감사합니다! 이것은 문자열 조작 등을 피했습니다.
guerda

1
Apache의 BeanUtils를 잘 호출하십시오. 속성을 쉽게 가져오고 설정하고 형식 변환을 처리합니다.
Peter Tseng

Java 파일에 필드가 나열된 순서대로 메소드를 호출하는 방법이 있습니까?
LifeAndHope

@Anand
Anand

그것을 사랑 ! 대박.
smilyface 2016 년

20

이를 위해 Reflections 프레임 워크를 사용할 수 있습니다

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

Reflections는 여전히 Java 9와 호환되지 않습니다 . 더 나은 동작을위한 ClassIndex (컴파일 시간) 및 ClassGraph (런타임) 대안에 대한 링크가 있습니다.
Vadzim

이 솔루션은 허용 된 답변의 bean Introspector와 달리 getters를 고려하지 않았습니다.
Vadzim


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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.