The Magic of Java’s Reflection API

Hey, tea lovers! Ever wonder how Spring auto-wire the fields without using setters or constructors or Hibernate stores column values to the appropriate fields? How are they reading the class’s field? and not only reading but changing or storing the values in them even though they are private? Let me reveal the mystery. They are using Java’s Reflection API.

What kind of magical substance is this? How these libraries are using them? How can we use them? Phew! too many questions to answer. Let just dive into it and find the answers.

But before, fill your cup of tea, start sipping, and code.

The Magical World of Reflection API

What is Reflection API? It is a Java Library through which Java allows us to change the behavior of class’s data members or methods at run time. You can read or modify them. The package it uses is java.lang.reflect.*. This package contains the classes representing the various parts of the Reflection API.

However, all this is done through Class Object. The functions of the Class’s Object is what helps us to get the members of the class you want to work on. And It can be derived by YourClassName.class or yourObject.getClass(). Where YourClassName is the class you want to explore.

See the following code on how to derive Class Object of your class or object.

Class<Customer> viaClassName = Customer.class;
System.out.println("Via class name " + viaClassName.getName());
Class<? extends Customer> viaObject = new Customer().getClass();
System.out.println("Via object " + viaObject.getName());

The Need for this Magic

So where can we use these? what are the applications of these API? Well, it is mostly used in Annotation processing, Spring uses it to auto wiring the dependencies in your class, Lombok generates setters and getters by reading member fields of POJO. This all sums up to one short answer is that, When you want to dynamically change the behavior of the class.

If you have lots of custom validation in the data classes (POJO) of yours and you have lots of if-else, where only the field names are changing, then you can create your own Annotation and carry out the validation with Reflection API. Don’t worry, we will look at the basics of it.

Demo Data for Reflection API work

Following is the Demo class. Customer, we will be using for our Reflection API work. You can find the whole source code on GitHub.

class Customer {
    private String name;
    private int id;

    public Customer(String name, int id) {
        this.name = name;
        this.id = id;
    }
    public Customer() {}
    public void setName(String name) {this.name = name;}
    public void setId(int id) {this.id = id;}
    public String getName() { return name;}
    public int getId() {return id;}
}

Constructor<T>

Let us start with constructors before exploring other parts. With Reflection API, you can read, execute, find out how many parameters does this class’s constructor(s) takes, and yes, create an object with it. The object it uses is Constructor<T>, where T is your class name.

The Constructor can be retrieved by getConstructor() . This will give you the constructor with no parameters if it has any. In case you want a certain overloaded constructor, you have to use getConstructor(Class<?>... parameterTypes). But you have to pass the exact type of of the object it is expecting. You can also get the array of constructors with getConstructors(). The private constructors can also be obtained by getDeclaredConstructor().

All the types has getConstructor() , getField(), getFields() and so on, are for public ones only. In case the desired one is private or public you need to use Declared after get to obtain those. Such as getDeclaredConstructor(), getDeclaredField(), and so on, you get the idea. To Declared it doesn’t matter if it is public or not.

public vs private

Now that you got the Constructor object, have the instance of the class using newInstance() or newInstance(Object ...initArgs). Keep in mind that initArgs should be of the same types and order as the constructor is expecting.

Constructor<Customer> customerConstructor = Customer.class.getConstructor();
Customer cu = customerConstructor.newInstance();

Constructor<Customer> parameterizedConstructor = Customer.class
       .getDeclaredConstructor(String.class, int.class);

System.out.println("Count of parameters : " + parameterizedConstructor.getParameterCount());

Customer detailedCustomer = parameterizedConstructor.newInstance("Coders Tea", 1);
System.out.println("Lets here it for the : " + detailedCustomer);

Field

The fields are the data members of a class. Such as name and age in our Customer class. It can be primitive or some other object as well. For example, Address, Integer or String. This class fileds are handled by Field object. To obtain a Field you have to use getField(String fieldName) or getDeclaredField(String fieldName) for a private+public field. You can get all the fields in a class in an array by getFields() or getDeclaredFields() for only public and private+public respectively.

You can read its value using get which returns Object . You can cast it to your desired type. Or you can read it with getInt(), getLong() etc for primitive types oly. To set the value you will be needing the object of your calss, in our case the object of Customer, then use set(Object objectOfYourClass, Object valueToSet).

But before modifying please make sure you are changing the accessibility of the Field or it will throw an error for private Field. You should first store the current accessibility in a boolean variable isAccessible using isAccessible() or canAccess() if you are using Java 9+. After that set Field accessibility to true using setAccessible(true) and then after you are done with the changes, revert back with setAccessible(isAccessible). This applies to the Method object also.

Customer customer = new Customer("Field", 2);
Field nameField = customer.getClass().getDeclaredField("name");
boolean isNameAccessible = nameField.isAccessible();
nameField.setAccessible(true);

Field idField = customer.getClass().getDeclaredField("id");
boolean isIdAccessible = idField.isAccessible();
idField.setAccessible(true);

System.out.println("Name is : " + nameField.get(customer));
System.out.println("id is " + idField.getInt(customer));
nameField.set(customer, "New Name");
System.out.println("new Name" +
       " is : " + nameField.get(customer));

/*make sure to reset accessibility*/
nameField.setAccessible(isNameAccessible);
idField.setAccessible(isIdAccessible);
/*to access all the fields*/

for (Field field : Customer.class.getDeclaredFields()) {
   boolean isFieldAccessible = field.isAccessible();
   System.out.println("Field being acces is : " + field.getName()" with value : " + field.get(customer));
   field.setAccessible(isFieldAccessible);
}

Method

You can invoke or get details about methods or functions using the Method object. It can be reached by getMethod(String methodName) or with declared one. It also gives the different details about this method such as the parameter’s count, types, return type, access modifier, declared annotations, etc. It is kind enough to allow us to invoke or execute it too, using invoke(Object objOfYourClass, Object ...params). (remember accessibility). Again, you have to be sure about the parameter types and numbers similar to Constructor object.

Customer customer = new Customer();

Method setIdMethod = customer.getClass().getMethod("setId");
setIdMethod.invoke(customer, 2);
System.out.println("Parameters count is " + setIdMethod.getParameterCount());

Method getIdMethod = customer.getClass().getMethod("getId");
int id = (int) getIdMethod.invoke(customer);
System.out.println("id is " + id);

The Fairy and the Witch

Isn’t it magical? yes, it is. But every magical world has a witch. In this case, it is a performance overhead. Read what java doc has to say about it.

Reflection is powerful, but should not be used indiscriminately. If it is possible to perform an operation without using reflection, then it is preferable to avoid using it. The following concerns should be kept in mind when accessing code via reflection.

Performance Overhead

Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts and should be avoided in sections of code which are called frequently in performance-sensitive applications.

Security Restrictions

Reflection requires a runtime permission which may not be present when running under a security manager. This is an important consideration for code that has to run in a restricted security context, such as in an Applet.

Exposure of Internals

Since reflection allows code to perform operations that would be illegal in non-reflective code, such as accessing private fields and methods, the use of reflection can result in unexpected side-effects, which may render code dysfunctional and may destroy portability. Reflective code breaks abstractions and therefore may change behavior with upgrades of the platform.

Conclusion for Reflection API

That’s it for this post. I only showed the basic ones, Constructor, Field, and Method, to get you started. There are plenty of other objects under the reflect library. Along with work we also looked at the drawbacks of it according to the official Java document. I will be writing a post on annotation processing on how we can use it to make our life easier with less repetitive code. You can find the code described here on GitHub or the full project here. See you at your next tea break.

If you have any thing to add or want to suggest any topic, please feel free to engage with us in comments.