Najlepszy sposób na wywołanie gettera poprzez refleksję

127

Muszę uzyskać wartość pola z określoną adnotacją, więc dzięki refleksji mogę uzyskać ten obiekt pola. Problem w tym, że to pole zawsze będzie prywatne, chociaż z góry wiem, że zawsze będzie miało metodę pobierającą. Wiem, że mogę użyć setAccesible (true) i uzyskać jego wartość (gdy nie ma PermissionManager), chociaż wolę wywołać jego metodę pobierającą.

Wiem, że mógłbym poszukać metody, wyszukując „get + fieldName” (chociaż wiem, że na przykład pola typu boolean są czasami nazywane „is + fieldName”).

Zastanawiam się, czy istnieje lepszy sposób wywołania tego gettera (wiele frameworków używa getterów / seterów, aby uzyskać dostęp do atrybutów, więc może robią to w inny sposób).

Dzięki

Javi
źródło

Odpowiedzi:

240

Myślę, że to powinno wskazać ci właściwy kierunek:

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

Zauważ, że możesz samodzielnie stworzyć instancje BeanInfo lub PropertyDescriptor, tj. Bez używania Introspectora. Jednak Introspector wykonuje wewnętrznie pewne buforowanie, co zwykle jest dobrą rzeczą (tm). Jeśli jesteś zadowolony bez pamięci podręcznej, możesz nawet iść

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

Jednak istnieje wiele bibliotek, które rozszerzają i upraszczają interfejs API java.beans. Dobrze znanym przykładem jest Commons BeanUtils. Tam po prostu zrobiłbyś:

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

BeanUtils zawiera inne przydatne rzeczy. tj. konwersja wartości w locie (obiekt na łańcuch, ciąg na obiekt) w celu uproszczenia ustawiania właściwości z danych wejściowych użytkownika.

sfussenegger
źródło
Dziękuję Ci bardzo! To oszczędziło mi manipulacji strunami itp.!
guerda
1
Dobre wezwanie do Apache's BeanUtils. Ułatwia pobieranie / ustawianie właściwości i obsługuje konwersję typów.
Peter Tseng,
Czy istnieje sposób wywoływania metod w kolejności, w jakiej pola są wymienione w pliku Java?
LifeAndHope
Spójrz na moją odpowiedź poniżej @Anand
Anand
Pokochałem to ! Niesamowite.
smilyface
20

Możesz użyć do tego frameworka Reflections

import static org.reflections.ReflectionUtils.*;
Set<Method> getters = ReflectionUtils.getAllMethods(someClass,
      withModifier(Modifier.PUBLIC), withPrefix("get"), withAnnotation(annotation));
Naveedur Rahman
źródło
Pamiętaj, że Reflections nadal nie jest kompatybilna z Javą 9 . Są to linki do lepiej zachowujące ClassIndex (kompilacji) oraz ClassGraph (czas run) alternatywy z Threre.
Wadzim
To rozwiązanie również nie bierze pod uwagę * getterów, w przeciwieństwie do bean Introspector w przyjętej odpowiedzi.
Wadzim
4

Konwencja nazewnictwa jest częścią ugruntowanej specyfikacji JavaBeans i jest obsługiwana przez klasy w pakiecie java.beans .

Michael Borgwardt
źródło
3

Możesz wywołać odbicia, a także ustawić kolejność pobierania wartości za pomocą adnotacji

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

Wyjście po posortowaniu

getId Pos: 1 Value: 001
getName Pos: 2 Value: Anand
getGender Pos: 3 Value: Male
getGrade Pos: 4 Value: A
Anand
źródło