Mirror-gazing: a closer look at the good and bad sides of Java Reflection
I was working on an app that was heavily dependent on a third party library, which forced you to use Reflection. The problem with this was that the library was used in lots of places, meaning a lot of Reflection was going on in the app. I was always told that using Reflection was a bad idea for Android programming. I was curious and wanted to know why Reflection was considered bad practice, and if so, why was it put in Java? This blog post is to report my findings on Reflection in Java.
What is Reflection?
Reflection is an API that is used to examine or modify the behaviour of methods, classes and interfaces at runtime. The required packages for Reflection, the “java.lang.reflect” package, allows us to invoke methods at runtime irrespective of the access modifier.
Not many programming languages have this feature; although some would argue that this is a good thing for those programming languages and a bad thing for Java. It allows Java developers to examine what is in a program. Reflection is the ultimate “hacker tool”, as I call it.
The beauty of Reflection is that it allows developers to inspect a class, interface, the class structure, methods and fields without knowing the names of the classes at compile time. What makes it even more special is that we can manipulate fields, invoke methods and also instantiate new objects.
This can be useful for Android developers who like using hidden Google API’s. A good example of this that I found is that you can use Reflection to disable or enable mobile data on a user’s phone. Of course you should not do this, but it shows the power of Reflection in Android.
We can also use Reflection for debugging purposes in Android, for example:
What triggered me to write this blog was one of the disadvantages to Reflection that I came across. Put simply, when you change the method name in the code, where the method name is being used by Reflection won’t update because it has to be written as string for it to work with Reflection. This means you have to update the method name in the code and where it’s being used for Reflection.
To illustrate this, I will give you an example. I will not be using the actual code for the app that I was working on, but will use dummy methods that represent the sort of method that was in the code.
Look at the following code sample:
The sample code method will be passed to a third party app. The third party will use this method to update the User’s data. The UserData class just contains useful user information needed for the app, such as the User’s id, subscription status etc.
Below illustrates how we call the method through our third party library:
The third party library does what it says on the tin; it will provide us with the Notify object through the addObserver method, which we can then use to update our local user data. This example is fine, simple and the third party app does a lot of the heavy work, which means less code to write.
The problem here was that there were a lot of methods in the app that relied on the third party library. One of the issues I faced was that I like to clean up the code base when adding features, fixing bugs or refactoring in my spare time. When there is a variable called mUserName I change it to userName or if there is a method called getData(), again, I will rename it to provideUserData() to sound meaningful and helpful to developers. This is not a problem, but sometimes I see code is not in use or the IDE is complaining that the code is not in use, as seen in the code sample below:
This can be irritating when you see this all over the code base. In these cases, my instinct is to discover where the method is being used and ask “what is the purpose of that code?”, before I delete the method. Android Studio and IntelliJ both provide ways to see where you can find the methods declaration and Implementation. If you get the “… is never used”, as seen in the screenshot, you are left with the “find in path”, which is “cmd + shift + F” on Mac, as your last resort to find where it is being called. It was here that I saw it was being passed as parameter through Reflection.
You can remove the warning using @SuppressWarnings(“unused”)” — this will help disable the compiler warning but still will not tell you that this method is being used through Reflection.
My curiosity persuaded me to look inside the library and it was there that I came to see the power of Reflection. You mean at runtime I can invoke methods private or public at anytime? Upon understanding this at the time, I liked how the library was using Reflection, it was something new, like a new toy I needed to play with.
We will use the below code sample:
The code sample was called by the library like this:
I will describe in high level what was going on inside the library when the above method was called:
It was good to understand how Reflection was being used with the third party app, but as mentioned, I think it was used too much. It is well documented that when Reflection is used a lot, it can cause performance issues. The performance issues stem from looking and scanning for the classpath to load the class, which is a pain when dealing with a huge project. Another annoying problem was maintaining the code; this was hard, as you can see the methods not being used, meaning that you had to spend extra time looking for where it was being used before you could safely take action. There are security issues you could face because you have access to private fields and methods that are private for a good reason, which creates a risk of breaking your app.
There are good points to Reflection. It is not all bad when used correctly; it allows us to leverage APIs within Android and also Java. This will allow developers to be even more creative with our apps. There are libraries and frameworks that use Reflection; a perfectly good example is JUnit. JUnit uses Reflection to parse “@Test” annotation to get test annotation to then invoke it.
If you delve into your favourite Android or Java library, the chances are they are using Reflection, while another one to do so is the GSON library. GSON, Jackson and boon use Reflection to map properties in Json files to getter/setter methods to our lovely POJO classes.
Reflection is a powerful tool that can and should be used in Java — although to quote a famous phrase: “with great power comes great responsibility”. It has its drawbacks, which I have hopefully explained above, and because of these, I would recommend that you use it sparingly and wisely in your project.
Thanks for reading and please leave a comment if you have any to make.