Previous Next |
Reflection and Greater ReflectionThe 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.
Package java.langThis 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.ClassThis 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.ObjectFrom 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.PackageThis 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.reflectThis 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.FieldThis 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.MethodThis 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.ModifierThis 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.ProxyThis 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.AccessibleObjectThis 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.beansThe 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.
Class java.beans.IntrospectorThis 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.
Class java.beans.PropertyDescriptorThis 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.IndexedPropertyDescriptorThis 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 ParameterDescriptorThese 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.BeanInfoThis 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). |
Previous Next |