The Show tag static LocalStrings ls = LocalStrings.getLocalStrings(BeanUtil.class); public static final Object []sNoParams = new Object[0]; public static Hashtable sGetPropToMethod = new Hashtable(100); public static Object getObjectPropertyValue(Object obj, String propName, Object index) throws InvocationTargetException, IllegalAccessException, IntrospectionException, NoSuchMethodException { Method m = getGetPropertyMethod(obj, b propName, null == index ? null: index.getClass()); if(null == index) { return m.invoke(obj, sNoParams); C } else { Object []params = new Object[1]; D params[0] = index; return m.invoke(obj, params); } } public static Method getGetPropertyMethod(Object obj, String propName, Class paramClass) throws IntrospectionException, NoSuchMethodException { Class oClass = obj.getClass(); MethodKey key = new MethodKey(propName, e oClass, paramClass); Method rc = (Method)sGetPropToMethod.get(key); if(rc != null) { return rc; } BeanInfo info = Introspector.getBeanInfo(oClass); F PropertyDescriptor[] pd = info.getPropertyDescriptors(); if(null != pd) { for(int i = 0; i < pd.length; i++) { if(pd[i] instanceof IndexedPropertyDescriptor) { G if(null == paramClass || !propName.equals(pd[i].getName())) { continue; }
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost JSP Web Hosting services
CHAPTER 8 Using JavaBeans with tags IndexedPropertyDescriptor ipd = h (IndexedPropertyDescriptor)pd[i]; Method m = ipd.getIndexedReadMethod(); if(null == m) { continue; } Class[]params = m.getParameterTypes(); if((1 == params.length) && params[0].equals(paramClass)) { rc = m; break; } } else { if(null != paramClass || I !propName.equals(pd[i].getName())) { continue; } rc = pd[i].getReadMethod(); break; } } } if(null == rc) { StringBuffer methodName = new StringBuffer(); J methodName.append(”get”); methodName.append(propName.substring(0,1).toUpperCase()); methodName.append(propName.substring(1)); if(null == paramClass) { rc = oClass.getMethod(methodName.toString(), new Class[0]); } else { rc = oClass.getMethod(methodName.toString(), new Class[] {paramClass}); } } if(null == rc) { // No such method; throw an exception } sGetPropToMethod.put(key, rc); 1) return rc; } } B Finds the needed method C Invokes a nonindexed property D Invokes an indexed property The utility class exports two methods: The first accepts an object, property name, and index, and returns the desired property value from the object by using introspection. The second method introspects the object s class and retrieves the method required to get the property. The first method is not especially
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost JSP Web Hosting services
CHAPTER 8 Using JavaBeans with tags 8.3.1 Components of the tag The implementation of our new property getter tag included using four Java classes (table 8.5). Table 8.5 The classes comprising the bean getter tag Java class Description BeanUtil A utility class that performs the JavaBeans s introspection. ReflectionTag A tag whose role is to collect all our object and properties attributes and fetch the value pointed by them. This way we can reuse the logic in this class (by making it the base class) in other tags that require object property access through reflection. ShowTag A tag that takes the value fetched by our basic tag and prints it to the user. This is a relatively simple tag since most of the work is done in ReflectionTag from which it inherits. ReflectionTagExtraInfo A TagExtraInfo class to verify the tag s attributes. Since we want the tag to be very flexible, most of the attributes are not mandatory and some are applicable only in the presence of other attributes (for example, a scope attribute is not applicable without an object name attribute). This TagExtraInfo validates this complex attribute syntax. Let s take a close look at the code for each of these components in order to gain a greater understanding of them. BeanUtil The first class we use to compose our Show tag is BeanUtil which is a utility class that will do the introspection and method caching for a bean. Its source is in listing 8.3. Listing 8.3 Source code of JavaBeans utility class package book.util; import java.util.Hashtable; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.beans.IndexedPropertyDescriptor; import java.beans.IntrospectionException; import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; public class BeanUtil {
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Tomcat Web Hosting services
The Show tag which is available online at http://java.sun.com/docs/books/tutorial/reflect/ index.html. Now, to the main event of this chapter: writing our JavaBean tags. 8.3 The Show tag Our first JavaBeans-related tag is going to improve upon the standard tag by providing a JavaBeans property getter tag with the following enhancements: No need for previous bean declaration through a tag (or any other tag). This makes it much easier to use the tag. Accessibility to all types of properties, including indexed properties with possible index type of string and integer. The inability of to access indexed properties cripples the use of the property getters, and string indices are very important in the web arena. Bean object specification either through name and scope or using a runtime expression. We can use this tag with values created within scriptlets. As we have a rather high level of expectation here, our implementation will be rather involved. For example, our tag will let JSP authors specify the JavaBean for the tag to use in two ways: By specifying the bean s name and scope explicitly in an attribute By specifying the bean as a result of a runtime expression. Since our tag must confirm that the JSP author properly uses one of these options, we need to use a TagExtraInfo object to verify the tag s attributes (a technique we saw in chapter 6). We also have the choice of allowing the tag to support indexed properties, which can become particularly tricky when a method is overloaded with different indices (such as a String index and an int index into the same property). In such a case, we do not want one tag attribute to specify the String index and a different one to specify the int index, so we need to design a way to place these two index value types into a single attribute. We ll soon see how we tackle these ambitious features.
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Tomcat Web Hosting services
JavaBeans and reflection Listing 8.2 Source code of a method that uses introspection to find a property setter package book.util; import java.util.Hashtable; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.beans.IndexedPropertyDescriptor; import java.beans.IntrospectionException; import java.lang.reflect.Method; public class BeanUtil { // Snipped some of the code… /* * We are not dealing with indexed properties. */ public static Method getSetPropertyMethod(Class claz, String propName) throws IntrospectionException, NoSuchMethodException { Method rc = null; BeanInfo info = Introspector.getBeanInfo(claz); PropertyDescriptor[] pd = info.getPropertyDescriptors(); b if(null != pd) { for(int i = 0; i < pd.length; i++) { c if(propName.equals(pd[i].getName()) && !(pd[i] instanceof IndexedPropertyDescriptor)) { Method m = pd[i].getWriteMethod(); d if(null == m) { continue; } Class[]params = m.getParameterTypes(); if(1 == params.length) { rc = m; break; } } } } if(null == rc) { e throw new NoSuchMethodException(); } return rc; } }
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Tomcat Web Hosting services
CHAPTER 8 Using JavaBeans with tags B Gets an array of the property descriptors of this class Listing 8.2 shows an elementary example of bean property introspection that covers all the important introspection issues. The first step in getSetPropertyMethod(), as in any method that performs some type of bean introspection, is to get the properties descriptors (or events, depending on what you want to find). To get to properties descriptors we use the built-in bean Introspector in two phases; the first one fetches a BeanInfo for the class, and later obtains the PropertyDescriptor array from BeanInfo. The PropertyDescriptor interface (as its name implies) provides methods to retrieve logical information about JavaBean properties. The obtained array provides information on all the properties as identified by the Introspector, so we can now iterate this array and learn about the bean s properties. C Iterates over all the properties in the class and looks for a property with a nonindexed matching name A simple for statement will suffice; while iterating on the array we can check each of the properties as represented by a PropertyDescriptor object. NOTE There are two PropertyDescriptor types: the one that provides information on nonindexed properties, and IndexedPropertyDescriptor that extends PropertyDescriptor to provide information on indexed properties. The main difference between them is that IndexedPropertyDescriptor also provides a method informing us of the index variable s type. Since (in this example) we are only looking for a specific named, nonindexed property, we will ignore all other properties and look only at simple properties. d Found a property, performs a sanity check over the mehod. Do we have a method (meaning, is this property writable)? Does the method accept only a single parameter (the value to set)? When we find a property of the type we want, we need to verify that the method we are seeking exists (maybe the property is read-only?). Thus we get the setter method from PropertyDescriptor and check it out. (We did not have to check the number of method arguments.) E We could not find a matching property The method we were looking for does not exist. We should notify the user by throwing an exception. We have outlined some of the basics of reflection, and more specifically, JavaBean introspection. We ll see more code examples of introspection as we develop our tags in the next section. If, at this point you feel less than entirely comfortable with the topic of introspection and reflection, that s all right. Only the most rudimentary grasp is required to comprehend our custom tags. If you are, however, interested in learning more about reflection, take a look at JavaSoft s tutorial on the subject
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Tomcat Web Hosting services
CHAPTER 8 Using JavaBeans with tags Another way is by having setter and getter methods that take an index parameter (e.g., the next code fragment shows a setter/getter pair with an integer index). public Bar getFoo(int index); public void setFoo(int index, Bar foo); Either of these index property coding conventions will suffice to inform an introspecting program of the existence of an indexed property of type Bar[] and with the name foo. BeanInfo interface This coding convention approach provides an easy way to inform the system of the existence of properties and their methods. But what happens if we want to provide more explicit property information? In this case, the bean author provides an implementation of the BeanInfo interface. A BeanInfo object allows the JavaBean author to provide additional information about a bean, ranging from the icon that represents it to the properties and events it exposes. If a JavaBean author opts not to create a BeanInfo object for a bean and uses the coding convention approach instead, a BeanInfo is automatically created for the class during the introspection and holds on the information that is accessible from the coding conventions. In fact, as we will soon see in code, the BeanInfo interface is a crucial component of the introspection process and, therefore, will be used by our custom tags to learn about the Beans with which they are interacting. How introspection works The introspection process is provided through a class called java.beans.Introspector whose methods provide control over the introspection process as well as methods to obtain BeanInfo objects for any JavaBean. The tags in this chapter will be constructed to use an Introspector to get a BeanInfo object for a particular JavaBean, in order to learn about and manipulate its properties. To reach the crux of this long story, let s look at getSetPropertyMethod() (listing 8.2), whose job it is to find the setter method of a property in a certain JavaBean (for simplicity, the method does not work on indexed properties).
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Tomcat Web Hosting services
JavaBeans and reflection 8.2.3 JavaBeans introspection Recall that introspection is the process by which a JavaBean is analyzed, typically by a development tool, through reflection, for the purpose of determining its properties and events. The available properties as well as their setter and getter methods are discoverable by using introspection as defined in the JavaBeans specification. Introspection requires cooperation between the bean developer, who provides properties information, and the JavaBeans introspector, that reads this information and presents it to the user in a programmatic manner. 8.2.4 Properties and introspection The simplest way for a developer to specify properties and their associated methods is to use the special JavaBean properties method naming conventions and parameter signatures in his or her JavaBeans. Simple properties (nonindexed) According to the JavaBean specification, either of the following methods can identify a simple property named age of type int: public int getAge(); public void setAge(int age); Note that to conform to the JavaBeans standard, we ve defined methods whose names are getProperty() and setProperty() wherein property is the name of the property to manipulate; the first character constructing the property name is capitalized (in this case, age becomes Age). The presence of getAge() means that the property called age is readable, while the presence of setAge() means that age is writable. This naming convention applies when the property is of any data type whatsoever, except boolean. In such a case, the setter/getter method looks like the following public boolean isFoo(); public void setFoo(boolean foo); The getter method name was changed to reflect the fact that we are making a query on a value that can have only true or false values (by changing get to is). Indexed properties Indexed properties are specifiable in one of two ways. One way is by having an array type as the input and output to the setter and getter, respectively. This approach is presented in the following code fragment. public Bar[] getFoo(); public void setFoo(Bar[] foo);
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Tomcat Web Hosting services
CHAPTER 8 Using JavaBeans with tags When we look into these properties we may see differences between them. Some properties such as the user s password are read-write, meaning we can read their value as well as modify them. The user s state, however, is a read-only property; there is no meaning to set the value of this property since it represents something beyond our control (user logged in or logged out). The groups property is an array, since a user may belong to several groups, and we can access the different groups via an index. Our other properties are single values that do not need an index. The JavaBeans specification differentiates between read-only, write-only, and read-write properties, as well as indexed and nonindexed properties. The differences between read-only, write-only, and read-write properties are manifested in our Java code through the types of methods we use for each. Each property can have a property setter method, getter method, or both. A property with only a getter method is said to be read-only, a property with only a setter method is said to be write-only, and a property with both methods is read-write. NOTE The state property has only a getter method. This means that the state is read-only. Indexed properties are handled by providing getter and setter methods that accept an index parameter. In this way the bean user accesses discrete values of the property by using their index within the property array. The bean may also provide array-based setters and getters to allow the bean user to set the whole property array. NOTE The group property implements the indexed access with an integer as an index. One can consider using types other than an integer to index a property (for example, a string) but the JavaBeans specification is vague in the issue of property indexing using noninteger values. We also provide a means for the bean user to get the groups array in a single method call. Both method patterns (array getter/setter and indexed getter/setter) are permitted by the JavaBeans specification. This clarifies properties and how the user of the JavaBean manipulates the bean s properties using setters and getters. However, how can the bean user find out about the different properties or their methods? As helpful as the beans might be, we cannot use them without knowing what methods to use to access the different properties. We answer this in our next section.
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost JSP Web Hosting services
JavaBeans and reflection wishes to expose. The code that uses the bean takes advantage of the properties (reads them or modifies them) by calling some of the bean s methods. Imagine that you want to represent the data you have about a computer user in a bean, so that an administration program will be able to manipulate these users. Table 8.4 lists attributes each user might have. Table 8.4 Sample User attributes and related properties User Attribute Description JavaBean property Name The user s name name Family name The user s family name family Password The password that the user needs to enter when it logs into the computer pass Username The user s login name username Groups An array of user groups in which the user is a member groups User state Specifies whether or not a user is logged in state To follow the JavaBean standard, each of the attributes described in table 8.4 will map into a bean property, and the methods that expose these properties in our UserBean would resemble the following code fragment. public class UserBean implements java.io.Serializable { public String getName() { … } public void setName(String name) { … } public String getFamily() { … } public void setFamily(String family) { … } public String getPassword() { … } public void setPassword(String pass) { … } public String getUsername() { … } public void setUsername(String name) { … } public String getGroups(int index) { … } public String []getGroups() { … } public void setGroups(int index, String group) { … } public void setGroups(String []groups) { … } public int getState() { … } };
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost JSP Web Hosting services