Java

The Magic of Reflection API

 0

 11

By Imran.shaikh

On Mar 20, 2020 at 11:13 am

  

Introduction

Hey! tea lovers. Ever wonder how spring auto wires the fields without using setters or constructors, Lombok generates setters and getters, Hibernate stores column values to the appropriate variable? How are they reading the class’s variables or field? and not only reading but changing or storing the values in them even though they are private? So let me break the mystery. They are using Java’s Reflection API. So 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. You can find the code on github here or the full project here. But before, fill your cup of tea, start sipping and learn.

 

The Magical world of Reflection API

So what is Reflection API? It is something through which java allows us to change the behavior of class data members or methods at run time. You can read or modify them. Reflection API is done through Class <T> object and It can be derived by YourClassName.class or yourObject.getClass().

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 to make users code a lot cleaner. As, Spring, Hibernate or Lombok does. When you want to dynamically change the behavior of the class.

 

Points to be Noted.

If you add Declared after get for getting the Field or Constructor or Method, it will return it even though they are private unlike get which only returns public ones.

I will be using getDeclared<Object I Need> instead get<Object I Need> for not telling you it is private or public in every definition. For example, getDeclaredFields() instead getFields(). Just remove Declared from the word and you are good to go only for the public.

Before doing anything, do

  1. Get its accessibility value using isAccessible() and store it in a variable.
  2. just change their accessibility using setAccessible(true) so that you can access them.
  3. After completion reset the accessibility using stored value by setAccessible(storedIsAccessibleValue).

 

Constructor < T >

You can execute it, read about its parameters type, length and yes you can create an object through this without using new in your code. The Constructor can be retrieved by getConstructor() or you can pass the parameter types for a certain overloaded constructor using getConstructor(Class<?>... parameterTypes)private constructors can also be obtained by getDeclaredConstructor() or provide the parameters types just like the former. Now that you got the Constructor, have the instance of the class using newInstance() or newInstance(Object ...initArgs). Keep in mind that initArgs should be of the same types as the constructor you have obtained via parameterTypes.

Constructor<Customer> customerConstructor = Customer.class.getConstructor();
Customer cu = customerConstructor.newInstance();
System.out.println("No parameterized constructors name will be null: " + cu.getName());
Constructor<Customer> parameterizedConstructor = Customer.class
.getDeclaredConstructor(String.class, int.class);
System.out.println("Count of parameters : " + parameterizedConstructor.getParameterCount());
Customer detialedCustomer = parameterizedConstructor.newInstance("Coders Tea", 1);
System.out.println("Lets here it for the : " + detialedCustomer);

 

Fields

The fields are the data members of a class. Like, name and age in our Customer class. We can have another class as a Field as well, for example, Address, Integer or String. To obtain a Field you have to use getField(String fieldName) or getDeclaredField(String fieldName) for a particular field. You can get it all by getFields() or getDeclaredFields() for only public and all respectively. To read or set the value you have to pass the object to which this Field belongs to (remember the accessibility). You can read its value using get which returns Object which you can cast to your need or read it as getInt()getLong() etc for primitive types. To set the value use set(Object objectOfYourClass, Object valueToSet).

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 Method. It can be reached by getMethod(String methodName) or declared one. You can have 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 as well using invoke(Object obj, Object ...params) (remember accessibility).

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

There are plenty more, but these are basic and easy to understand.

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 which 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.

So that’s it for this tea break. You can find the code on github here or the full project here. See you on your next tea break.

 

   JavaJava8Reflection API

About Contributer

Questions / Comments


Comments

Be the first to comment on this post.