Home » Java Reflection API: The Magical World of Java

Java Reflection API: The Magical World of Java

by Imran Shaikh
736 views
The magic of reflection API

Hey, tea lovers! Ever wonder how Spring auto-wires the fields without using setters or constructors or Hibernate stores column values to the appropriate fields? or Gson converting your POJO to JSON? 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 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 lean this magic.


You can follow me on social @coderstea on TwitterLinkedinFacebook, or Instagram. We also share high-quality videos about programming on our Youtube channel. You can also publish your own post on CodersTea.com, just share your thought on Contact Us or let us know in the comments.


The Magical World of Java Reflection API

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

However, all this is done through Class Object. The functions of the Class Object are what helps us to get the members of the class that we 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 of Java Reflection API

So where can we use these? what are the applications of these APIs? It is used wherever we want to change the behavior of the class at runtime such as Annotation Processing or injecting value. The examples for Java Reflection API can be, Spring uses it to auto wiring the dependencies in your class, or Gson converts your object to JSON, hibernate injects table data to your Entity class, and so on.

If you have lots of custom validation in the data class (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 Java Reflection API. Don’t worry, we will look at the basics of it.

Demo Data for Java Reflection API Work

Following is the Demo class Customer. I will be using it for Java 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;
   }
 }

Magical Charm of the Constructor<T> Reflection API

Let us start with constructors before exploring other parts. With Java 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 and number of objects it is expecting. You can also get the array of constructors with getConstructors(). The private constructors can also be obtained by getDeclaredConstructor().

All methods for grabbing different parts of the class such as getConstructor() , getField(), getFields() among others, are for public ones only. Meaning if they are declared public. In case the one you want is private (or public) you need to add Declared after get to obtain those. Such as getDeclaredConstructor() instead of getContructor(), getDeclaredField() instead of getField(), 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);

Magical Spell of the Java Reflection API using Field

The fields are the data members of a class. Such asname and age in our Customer class. It can be primitive or some other object as well. For example, Address, Integer or String. These class fields are handled by Field object.

To obtain a Field you have to use getField(String fieldName) or getDeclaredField(String fieldName) for a private (or public) field. You can get all the fields in a class in an array by getFields() or getDeclaredFields() for only public and private (or public) respectively.

You can read its value using get() which returns Object. And then can cast it to its original declared type. Or you can read it with getInt(), getLong() etc for primitive types only. To set the value you will be needing the object of your class, 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 to Cast a Spell Upon Class Methods

You can invoke or get details about methods or functions using the Method. It can be derived by getMethod(String methodName) or with declared one. It also gives various details about the method, such as the parameter’s count, types, return type, access modifier, declared annotations, etc. Method is kind enough to allow us to invoke or execute it using invoke(Object objOfYourClass, Object ...params) and remember accessibility. Again, you have to be sure about the parameter types and numbers as we did in Contructor<T>.

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. We should keep in mind the following concerns.

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 Java 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 their 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.

See you in the next post.

HAKUNA MATATA!!!

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Accept Read More

Privacy & Cookies Policy