Understanding BeanUtils in Apache Jakarta Commons
- Understanding BeanUtils
- Using BeanUtils to Generate Forms
- Summary
One of the most popular patterns in Java is the JavaBeans component model (http://java.sun.com/products/javabeans/). Originally designed to allow visual design tools to generate AWT user interfaces, the JavaBeans specification provides additional guidelines on top of the basic contracts implied by a given Java class.
The JavaBeans specification provides mechanisms for methods of a Java class to be visible to a builder tool, organized into properties, methods, and events. A property is available via accessor methods, such as String getFirstName() and void setFirstName(). Methods are ordinary Java methods. Events define standard methods for allowing one component to notify one or more components of an arbitrary event. Visual development tools use these various systems to enable visual construction of user interfaces: a button is dragged onto a panel, the properties are set (such as the label and size), and events are wired (for example, clicking on the button closes the window).
For server-side development, the most popular aspects of the JavaBeans specification are the constructor and property patterns. Specifically, a standard JavaBean must have a no-argument constructor and get/set accessor methods corresponding to the various properties. For example, the simple JavaBean shown in Listing 7-1 has two String properties (first name, last name) and a single int property (clearance).
Listing 7-1 Simple JavaBean
package com.cascadetg.ch07; public class User { // Private variables private String firstName; private String lastName; private int clearance; // Accessor methods public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public int getClearance() { return clearance; } public void setClearance(int clearance) { this.clearance = clearance; } }
While the JavaBeans specification describes rules for how components should be written and the expected behavior of the tools, no implementation is provided. Generally speaking, it is assumed that the low-level java.lang.reflect.* package will be used to obtain information about the Java classes, and the tool will generate code as needed.
Over time, it has become clear that frameworks, not just visual design tools, can take advantage of the JavaBeans patterns. For example, the object/relational bridge framework Hibernate uses JavaBean patterns to help work with relational databases in a more natural fashion.
Hibernate and FormBean
Hibernate, an object/relational database integration technology, uses the JavaBeans component model as its key foundation. By combining JavaBeans with XML mapping files, a Java developer can work with complex relational databases quickly and easily. The inspiration for this chapter came from the idea that the JavaBeans model can be leveraged not just for persistence, but also for automation of user interface generation.
For more information on the object/relational framework Hibernate, see my book, Hibernate: A J2EE Developer's Guide to Database Integration (ISBN: 0321268199, Addison-Wesley Professional).
While it is possible to use the low-level reflection package to deal with JavaBeans, it is easier to use the Jakarta Commons BeanUtils package.
For anyone given to thinking in terms of broader architectural design and framework development, it is easy to think of other areas in which the BeanUtils package may be useful. Obviously, this package would be of interest to anyone interested in building visual development tools. Similarly, dependency injection, dynamic configuration, and runtime binding of application elements such as the user interface and other systems are all potentially of interest.
In this chapter we will look at how to use the Jakarta Commons BeanUtils package to build a simple framework for converting objects based on the JavaBeans standard to HTML forms and back.
Understanding BeanUtils
In many ways, BeanUtils can be considered a metadata wrapper that makes it as easy to work with a JavaBean as a Map. The properties are the keys, and property values can be set by simply setting the property as a value. For example:
myUser.setName("Bob"); . . . can instead be written: BeanUtils.setProperty(myUser, "name", "Bob"); Similarly, an array of the properties available for myUser can be simply retrieved: DynaProperty[] properties = WrapDynaClass.
createDynaClass(myUser.class).getDynaProperties();
This offers two key advantages: it allows you to decouple components of your application, and it allows you to build frameworks and tools to take advantage of the JavaBeans framework.
As shown in Figure 7-1, the BeanUtils package draws a distinction between a DynaClass, which describes a class, and a DynaBean, which describes a particular object instance. This notion can actually be extended a bita DynaClass can be used as a wrapper for a JDBC ResultSet, for example (in which the properties correspond to the returned results), and individual records can be returned as DynaBeans.
Figure 7-1 BeanUtils class diagram.
One aspect of the BeanUtils package worth calling out is the notion of a Converter. This provides a generic way to retrieve and set values across a suite of properties using String values, regardless of the type of the property. For example, you may want to set a property with a type of int using a String such as "2". The Converter package takes care of these details for you.
The following types are supported by built-in converters:
BigDecimal
BigInteger
Boolean
Byte
Character
Class
Double
File
Float
Integer
Long
Short
SqlDate
SqlTime
SqlTimestamp
String
URL
Abstract array
Boolean array
Byte array
Character array
Double array
Float array
Integer array
Long array
Short array
String array