Best way of invoking getter by reflection

JavaReflectionGetter

Java Problem Overview


I need to get the value of a field with a specific annotation, So with reflection I am able to get this Field Object. The problem is that this field will be always private though I know in advance it will always have a getter method. I know that I can use setAccesible(true) and get its value (when there is no PermissionManager), though I prefer to invoke its getter method.

I know that I could look for the method by looking for "get+fieldName" (though I know for example for boolean fields are sometimes named as "is+fieldName").

I wonder if there is a better way to invoke this getter (many frameworks use getters/setters to access the attributes so maybe they do in another way).

Thanks

Java Solutions


Solution 1 - Java

I think this should point you towards the right direction:

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

Note that you could create BeanInfo or PropertyDescriptor instances yourself, i.e. without using Introspector. However, Introspector does some caching internally which is normally a Good Thing (tm). If you're happy without a cache, you can even go for

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

However, there are a lot of libraries that extend and simplify the java.beans API. Commons BeanUtils is a well known example. There, you'd simply do:

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

BeanUtils comes with other handy stuff. i.e. on-the-fly value conversion (object to string, string to object) to simplify setting properties from user input.

Solution 2 - Java

You can use Reflections framework for this

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

Solution 3 - Java

The naming convention is part of the well-established JavaBeans specification and is supported by the classes in the java.beans package.

Solution 4 - Java

You can invoke reflections and also, set order of sequence for getter for values through annotations

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 when sorted

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJaviView Question on Stackoverflow
Solution 1 - JavasfusseneggerView Answer on Stackoverflow
Solution 2 - JavaNaveedur RahmanView Answer on Stackoverflow
Solution 3 - JavaMichael BorgwardtView Answer on Stackoverflow
Solution 4 - JavaAnandView Answer on Stackoverflow