Put the Java Reflection API to work in your apps

The Java Reflection API enables you to take advantage of a variety of programming techniques. We'll show you how to inspect objects and work with arrays in the context of this API.

The Java Reflection API is a fundamental part of the Java Platform. It forms the basis of services like JavaBeans and Object Serialization and allows the development of sophisticated applications such as object inspectors and class browsers. It is not restricted to special utilities and tools, however, and common applications can also benefit from its capabilities.

In the first part of this series, I presented the most important classes and methods that make up the Reflection API. Now I will discuss some useful techniques based on the API, which you can incorporate in your own applications.

Inspecting objects
Despite the modern tools available to debug applications, outputting the contents of objects and variables at key points of a program is still the most used technique to find and fix errors. This is especially true in production environments or a situation in which running the application under a debugger is not possible or feasible.

The problem, however, is that fields of a class usually are not declared as public, according to good object-oriented design, and fields intended for internal use don’t have even accessor methods. This means that the code to inspect an object must be part of the class itself, since code outside the class doesn’t have access to its contents.

That leaves you the options of incorporating the code as part of the class, meaning more code to write and maintain, or adding it as needed during testing and removing it later from the production version. I don’t particularly like either option.

What if you could inspect any object, whether you have access to its fields or not, without the need to change its class in any way or insert special code? The Reflection API allows you to do exactly that, and what's better, it takes just a little bit of code.

Listing A shows a method that dumps the contents of a given object. It returns a list of its fields (name and value) as a string.

Notice that the method outputs just the fields declared by the class. Fields declared by superclasses or implemented interfaces are not dumped. That is not a problem for interfaces, since they can declare only public constants. However, sometimes, it is interesting to dump the superclasses also. Listing B shows an improved version that dumps all fields declared by the object’s class and all superclasses.

Working with arrays
The methods presented so far used the method toString() to format the value of fields. Since all fields, whether primitive or not, are returned as objects by the Reflection API, using toString() is straightforward. Besides that, toString() is meant to return a textual, human-readable representation of the object, so it is adequate for most classes.

That does not work for arrays. Although arrays have a particular syntax, they are also objects and have correspondent classes. The difference is that you don’t declare array classes, since they are automatically created by the Java Virtual Machine.

That means you can’t override the method toString() and, consequently, arrays inherit that method from java.lang.Object, which returns a string equivalent to:
getClass().getName() + '@' + Integer.toHexString(hashCode())

That's not too useful, so a special handling is needed for arrays. Fortunately, the Reflection API provides everything you need to manipulate arrays. All you need to do is test whether the object is an array. If it is, use the Reflection API to access its elements.

Listing C shows the same method presented in Listing B, except that it handles arrays as a special case. Arrays are returned as a bracketed list containing their elements. Whenever the value of a field is an array, the method is called recursively to format the array.

The same is true when an array element is also an array, so that multidimensional arrays are correctly formatted. This sidebar shows the method output when applied to an instance of the classjava.util.ArrayList containing 10 elements.

Calling methods
I regularly used the Reflection API to call methods. This is useful whenever you don’t know at compile time the name and/or signatures of the methods you are going to call.

Recently, I wrote a generic class that dispatches HTTP requests to a specific method of a servlet so that I don’t need to figure out which method to call from the servlet’s doXXX methods or write a separate servlet to handle each request that is part of the same application or service.

Since the number of requests a servlet is going to handle is not known in advance, it's impossible to define an interface that the servlet needs to implement so that the methods can be called. The answer is the Reflection API.

Listing D shows a simplified version of my generic class (Dispatcher). Using it is simple: First, the servlet must construct an instance of the Dispatcher class, passing itself (the servlet object) as the parameter. Next, it must call the method mapRequest to configure the method to call to handle each request.

The request is specified as a string and the method is identified by its name (also as a string). The method must be a member of the servlet object (passed as parameter to the Dispatcher constructor). It receives, as parameters, the request (String), the HTTP request object (HttpServletRequest), and the HTTP response object (HttpServletResponse), so the method's signature must reflect this.

After configuring the methods to call, the servlet just has to call the dispatch method from its doXXX methods, passing the request and response objects. The request must specify a parameter, _reqid, that identifies it, so that dispatch knows which method to call.

The Java Reflection API is a powerful tool that has a number of uses. In this article, we've looked at some basic techniques you can incorporate in your applications.

But don’t overuse the Reflection API. Programs that use it are more difficult to understand and maintain. In addition, accessing fields and calling methods through the Reflection API is slower than using them in the “normal” way, so use reflection only when it is really necessary.

Editor's Picks