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 converts 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’s just dive into it and find the answers.
But before, fill your cup of tea, start sipping, and lean into this magic.
I would be happy to connect with you guys on social media. It’s @coderstea on Twitter, Linkedin, Facebook, Instagram, and YouTube.
Please Subscribe to the newsletter to know about the latest posts from CodersTea.
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 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
Objects are what help 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
An 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());
Code language: HTML, XML (xml)
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, 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) yours and you have lots of if-else, where only the field names are changing, then you can create your 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;
}
}
Code language: JavaScript (javascript)
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 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 several 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
public vs privateDeclared
afterget
to obtain those. Such as getDeclaredConstructor() instead of getContructor(), getDeclaredField() instead of getField(), and so on, you get the idea. ToDeclared
it doesn’t matter if it is public or not.
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 type 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);
Code language: JavaScript (javascript)
Magical Spell of the Java Reflection API using Field
The fields are the data members of a class. Such asname
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
objects.
To obtain 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 the 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 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));
/ /<em>make sure to reset accessibility</em>
nameField.setAccessible(isNameAccessible);
idField.setAccessible(isIdAccessible);
//<em>to access all the fields</em>
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);
}
Code language: JavaScript (javascript)
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 remembering 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);
Code language: JavaScript (javascript)
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 the java doc has to say about it.
Reflection is powerful, but should not be used indiscriminately. If it is possible to operate 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 that are called frequently in performance-sensitive applications.
Security Restrictions
Reflection requires 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 its 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. See you at your next tea break.
If you have anything to add or want to suggest any topic, please feel free to engage with us in the comments.
See you in the next post.
HAKUNA MATATA!!!
I would be happy to connect with you guys on social media. It’s @coderstea on Twitter, Linkedin, Facebook, Instagram, and YouTube.
Please Subscribe to the newsletter to know about the latest posts from CodersTea.