Cara terbaik untuk meminta rajin merenung dengan refleksi

127

Saya perlu mendapatkan nilai bidang dengan anotasi tertentu, Jadi dengan refleksi saya bisa mendapatkan Obyek Bidang ini. Masalahnya adalah bahwa bidang ini akan selalu pribadi meskipun saya tahu sebelumnya akan selalu memiliki metode pengambil. Saya tahu bahwa saya dapat menggunakan setAccesible (true) dan mendapatkan nilainya (ketika tidak ada PermissionManager), meskipun saya lebih suka menggunakan metode pengambil.

Saya tahu bahwa saya bisa mencari metode dengan mencari "get + fieldName" (meskipun saya tahu misalnya untuk bidang boolean kadang-kadang disebut sebagai "is + fieldName").

Saya bertanya-tanya apakah ada cara yang lebih baik untuk memanggil pengambil ini (banyak kerangka kerja menggunakan getter / setter untuk mengakses atribut jadi mungkin mereka melakukannya dengan cara lain).

Terima kasih

Javi
sumber

Jawaban:

240

Saya pikir ini harus mengarahkan Anda ke arah yang benar:

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

Perhatikan bahwa Anda dapat membuat instance BeanInfo atau PropertyDescriptor sendiri, yaitu tanpa menggunakan Introspektor. Namun, Introspector melakukan beberapa caching secara internal yang biasanya merupakan Good Thing (tm). Jika Anda senang tanpa cache, Anda bahkan bisa menggunakannya

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

Namun, ada banyak perpustakaan yang memperluas dan menyederhanakan API java.beans. Commons BeanUtils adalah contoh terkenal. Di sana, Anda cukup melakukan:

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

BeanUtils hadir dengan hal-hal praktis lainnya. yaitu konversi nilai on-the-fly (objek ke string, string ke objek) untuk menyederhanakan pengaturan properti dari input pengguna.

sfussenegger
sumber
Terima kasih banyak! Ini menyelamatkan saya dari manipulasi string dll!
guerda
1
Panggilan bagus di BeanUtils Apache. Membuat mendapatkan / mengatur properti lebih mudah, dan menangani konversi tipe.
Peter Tseng
Apakah ada cara untuk memanggil metode dalam urutan bidang mana yang terdaftar dalam file Java?
LifeAndHope
Lihatlah jawaban saya di bawah @Anand
Anand
Menyukainya ! Luar biasa.
smilyface
20

Anda dapat menggunakan kerangka kerja Refleksi untuk ini

import static org.reflections.ReflectionUtils.*;
Set<Method> getters = ReflectionUtils.getAllMethods(someClass,
      withModifier(Modifier.PUBLIC), withPrefix("get"), withAnnotation(annotation));
Naveedur Rahman
sumber
Waspadalah bahwa Refleksi masih tidak kompatibel dengan Java 9 . Ada tautan untuk alternatif ClassIndex (waktu kompilasi) dan ClassGraph (run time) yang berperilaku lebih baik dari threre.
Vadzim
Solusi ini juga tidak diperhitungkan adalah * getter tidak seperti bean Introspector dalam jawaban yang diterima.
Vadzim
3

Anda dapat memohon refleksi dan juga, mengatur urutan urutan untuk pengambil untuk nilai melalui anotasi

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

Output saat diurutkan

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