Reflection and Greater Reflection

The tools available to a reflection programmer are not limited to the java.lang.reflect package, as you may expect. In fact, they are spread all over the core of the JDK. All the tools used in reflection are often referred to as greater reflection. In this section, you will address each of the relevant packages and the tools within those packages and assemble an arsenal of reflection tools that will improve your programming.

Screenshot

Although this tutorial isn't intended as a reference manual explaining how to use the individual methods on the reflection tools, there are several examples in the oracle.hcj.reflection package. These examples demonstrate many of the methods and basic techniques of reflection.


Package java.lang

This package contains the core functionality of reflection as well as the JDK itself. Since all classes ultimately inherit from java.lang.Object, the java.lang package plays a pivotal role in obtaining information about classes and objects.

Class java.lang.Class

This class contains information about the object's class, such as which fields and methods it contains, and which package it is in. You used it before to obtain information about the methods in a class. See Example 9-2.

Class java.lang.Object

From this class, you can get the Class instance for any object. Also, since the Object class is the basis for all constructed types in Java, it is used to pass parameters or get results from reflexively invoked methods and fields.

Class java.lang.Package

This class encapsulates the runtime manifestation of a package. However, Package is not a particularly useful class because you can't ask it for all of the classes in a package. I rarely use this class in my reflection programming.

Package java.lang.reflect

This package contains utilities for dynamic invocation of methods and for dynamic assignment and retrieval of fields. When you get catalogs of fields and methods from Class, they will be returned to you as instances of classes within java.lang.reflect. This package is one of the critical tools in building dynamic code, and it is used often in reflection code.

Class java.lang.reflect.Field

This class contains a description of a field and the means to access the field. With this class, you can dynamically set or retrieve field values.

Class java.lang.reflect.Method

This class contains a description of a method and the means to dynamically invoke it. You can use instances of this class to dynamically invoke methods. See Example 9-3.

Class java.lang.reflect.Modifier

This class is used to decode the bit field modifiers of a class, field, or method. Using Modifier, you can determine whether a field is public, private, static, transient, and so on. The modifiers are set by the native reflection code in the virtual machine that examines the actual Java byte code. These modifiers are read-only.

Class java.lang.reflect.Proxy

This class is used to create dynamic proxy classes, which are then used to create objects that implement specific interfaces. Usually, these classes are used to hide pieces of the implementation of a class from a user. For example, you could create a Proxy to the data object that presents an immutable interface to the object.

Class java.lang.reflect.AccessibleObject

This is the base class from which Method, Field, and the other descriptors inherit. It allows you to bypass class access constraints such as "private," which allows you to execute methods and set fields that would normally be blocked by visibility specifiers. Serialization often uses this class because it must have access to private fields to serialize an object. In EJB, this class is off-limits. Although this class can be useful, I caution against using it unless you have no other choice. Forcibly breaking the encapsulation on an object can lead to enormously confusing code that is difficult to debug.

Package java.beans

The java.beans package was designed to allow developers to build GUIs using visual tools. However, there are many classes within this package that can be used with reflection. This package has classes that provide convenient access to various parts of reflection that you would otherwise have to search for in several places. Although this package contains some powerful tools, it is quite old. Most of the classes in this package were introduced long before the collections framework of Java Foundation Classes (JFC) were finalized. Therefore, this package deals with arrays and not with the superior collection classes in the java.util package.

Screenshot

This package has much more functionality than is covered in this chapter. Most of the JavaBeans coding paradigm is outside the scope of this tutorial, so I don't delve into the world of customizers and other JavaBeans-specific concepts. Instead, I focus on the aspects of the java.beans package that are applicable to reflection as a whole and not just JavaBeans, which is one app of reflection.


Class java.beans.Introspector

This is a singleton class that can be used to obtain property information about a class declared with the JavaBeans naming specification. One important benefit of this class is that it caches the lookup of class information, which significantly speeds up the reflection process. Although Introspector is useful, it does have some significant drawbacks. First, it does not detect polymorphic properties. Consider the following property:

public void setValue(final int value);
public int getValue( );


This property is declared using the JavaBeans naming specification. However, it can also be expressed using polymorphic notation:

public void value(final int value);
public int value( );


This notation uses the context of the method to determine whether the method is a getter or setter. The syntax is much cleaner since a field does not need to be capitalized. These properties are often used in products such as the Simple Widget Toolkit (SWT), which is used to build the Eclipse GUI. To detect polymorphic properties, you can try to extend Introspector. However, if you do this, you encounter the second major disadvantage of this class. The Introspector class is implicitly private (see ), which means that you cannot extend its functionality. Although it isn't declared as a final class, all of its constructors are private instead of protected, which means you can't extend it.

Screenshot

Introspector is a good example of why you should use protected methods instead of secured methods, and use private attributes instead of secured attributes. You never know when someone will want to extend your class, so you should give them as many options as possible. Therefore, make a method private only if there is an important reason why it shouldn't be available to subclasses.


Class java.beans.PropertyDescriptor

This class encapsulates the field, setter, and getter of a property all in one location. Essentially, it is a package where you get all of the information about a property in one place instead of having to look it up using Class. Unfortunately, neither this class nor any of its subclasses support collection properties with add and remove methods. The PropertyDescriptor class is used to provide a convenient interface to properties of a class. Most reflection tools use this class often. One problem with PropertyDescriptor is that it allows the user to set the read and write methods for a property manually. Although this appears to be a good idea, it can lead to some confusing results if multiple methods and classes are using the same property descriptor. For example, consider a GUI that views an object that is also being viewed in another panel showing a tree view of the object's structure. If one panel changes the accessor methods, the other panel would access the old method and could be corrupted. This is a good example of an object that should be immutable.

Class java.beans.IndexedPropertyDescriptor

This class is similar to PropertyDescriptor but has extra functionality to handle properties that are arrays (also referred to as indexed properties). Here is a simple example of an indexed property:

package oracle.hcj.reflection;
public class SomeClass {
 private String[] values = new String[0];
 public void setValues(String[] values) {
 this.values = values;
 }
 public void setValues(final String value, final int index) {
 this.values[index] = value;
 }
 public String[] getValues( ) {
 return values;
 }
 public String getValues(final int index) {
 return values[index];
 }
}


In this case, the values property is an indexed property because it is an array and has methods to set or get individual values in the array. The IndexedPropertyDescriptor class will allow you to access the get and set methods of the property and the indexed get and set methods of the property.

Classes MethodDescriptor and ParameterDescriptor

These classes encapsulate information on methods and their parameters. The MethodDescriptor class allows you to retrieve the information about a method in a class, and ParameterDescriptor allows you to get information about the method's parameters. These classes are useful for beans coding because they contain display information about the method and its parameters. However, for reflection, they don't provide any significant functionality above java.lang.reflect.Method. Therefore, these classes are rarely used in mainstream reflection programming.

Interface java.beans.BeanInfo

This class holds all of the information about a particular JavaBean. It provides a convenient place from which you can look up various descriptors and other information about the class. The Introspector is used to look up and cache BeanInfo instances. However, the one major problem with the BeanInfo class is that it doesn't provide access to the property descriptors by name. Unfortunately, extending this class isn't possible because the Introspector is implicitly private. To get an Introspector to find your extended BeanInfo class, you would either have to define the objects manually on every class (which would defeat the point of reflection) or reimplement the Introspector from the ground up (which is not a small task).

      
Comments