One of the essential properties of object oriented programming is the encapsulation of an object state. The most important side effect of this encapsulation is that an objects' state is exposed through its methods. These methods allows for various guarantees, such as class invariants and method invariants.

One of the classic examples of the Liskov substitution principle, is when using object inheritance with a Shape, Rectangle and Square. The classic mistake is to extend the Square from the Rectangle. This quickly violates the contract of the Rectangle. A modification of the Height of a Square modifies its Width, clearly a violation of the contract of the Height method of the Rectangle, this should specify that only the Height is modified, the Width should clearly be left alone. A much better solution is to give the Square it's own contract and use the Rectangle in Composition. Because of encapsulation, Each class has the responsibility to solve this problem on it's own. Take away the encapsulation, and there is no way to guarantee that invariants are held.

But one might ask, what is the relationship of this and reflection. It's quite simple, reflection allows this encapsulation to be eroded away. Improper use of reflection allows class invariants to be broken. A field might be directly updated or a field value might be directly manipulated without using the outlying layers. This is (at the very least, can be) very harmfull. When using reflection, you have to be aware of this. It's essential that, when using reflection to modify a value on an object, to (at the very least) find the proper accessors and mutators. Preferably, fail if you can't!

What some people fail to realize, is that Java has a complete security model. I've yet to find someone applying it (properly), but it's there. Since reflection breaks some rules that are put in place in the language itself, it requires the developer to be aware of this security model. At first, in an isolated application, it may seeem that there is little harm in ignoring the security model. Knowing the exact development and deployment environment makes this a quick judgement call. Any code, preferably bad code, has a tendency to live a lot longer than the developer intended. The (bad) code might end up in a library, copy-pasted to other application (this is a sin in itself) or the deployment environment could change. All these possibilities are not only equally likely, there's a high chance either one of those three scenarios occur. As such, being aware of the security model and properly developing for it is hard but very important. Any taken shortcuts might backfire spectacularly. To be fair, it's not always clear which steps to take to achieve this.

Frameworks use reflection to analze models. When a model defines collections, these collections are generally easy to analyze, a List or Set just has one generic parameter. But what happens when a complexer collection is found, one with multiple generic parameters. For example, someone decides to extend the Map interface to combine it with a List interface. This may require a complex analysis of the model. This part of the reflection API is not very transparent, there are many gotchas that might confuse your efforts. For example, a generic parameter of a class alone can come from the following (recursive) sources:

  • Declaring class (for inner classes),
  • Super class,
  • Interface,
  • A concrete declaration elsewhere.
This does not even cover bounds, which add an extra level of complexity. All in all, the Reflection API is not easy and it requires detailed knowledge of the inner workings of Java. One has to decide if this is worth it. As a developer one might have no problems with using Reflection, your colleague taking over your work might!

Rules of reflection:

  • To modify a value on an object, (at the very least) find the proper accessors and mutators. Preferably, fail if you can't,
  • Being aware of the security model and properly developing is important. Any taken shortcuts might backfire spectacularly,
  • The Reflection API is not easy and it requires detailed knowledge of the inner workings of Java. You might find it ok, the person taking over your work might not.
These rules might sound restrictive, they don't do the API justice.

The Reflection API is a very powerfull API that allows a lot of developer headaches to be solved in a generic manner. It's a very powerfull mechanism that lies at the very foundation of many frameworks in Java. It allows meta-model modifications at run time. It's at the foundation of many remoting techniques of Java from the very early days on. What makes the Reflection API function properly is the completeness. It doesn't just allow a method of inspecting the model, it allows modifications. All using the proper rules that apply to Java.

When trying to work with the rules of the API, there are simple ways to work with the mentioned rules. For accessors and mutators, it's often enough to inspect the public methods to find either. These public methods should contain the mutators and accessors representing the various properties of a class. Keeping this in mind, finding all methods of a class also means inspecting the entire hierarchy. A single class does not automatically contain the methods of it's super class. Be aware of the various paths you can take to get anywhere. Make utilities to solve these problems. Also, a static method is also just a method. The same way a final field is just a field. When updating the value of a field (as a rule we shouldn't, but if you feel you must), verify that the field is mutable.

As mentioned, detailed knowledge of the inner workings is required. Most, if not all, work with reflections should be put in either abstractions or utilities. These utilities and abstractions should in turn ensure the proper rules are followed. For example, security checks. At least the following will trigger security:

  • Classloaders - Retrieving a classloader will trigger Security,
  • Non-Public Methods - Either finding or calling non-public methods will trigger Security.

Keeping these things in mind should make most work with the Reflection API no problem whatsoever. In conclusion, the Reflection API is generally in the field of frameworks. It should stay there. Not every developer may understand or apply it correctly, it requires experienced developers who are very aware of what they are doing.