Using the Jakarta Commons, Part 3by Vikram Goyal
Jakarta Commons is a Jakarta subproject that creates and maintains independent packages unrelated to any other framework or product. The packages are a collection of components that serve small, useful purposes in their own right, and are usually server-centric.
The first installment of this series divided these components into five categories and described the Web and Trivial categories. The second article covered the XML and Packages categories. This article describes the final category, Utilities. Note that these categorizations are purely for organizational reasons.
The Utilities category contains the BeanUtils, Logging, DBCP, Pool, and Validator components.
Summary: Provides utilities for working with dynamic JavaBeans.
Download the source code for the example application. This .zip file contains:
When: When your application requires dynamic access to JavaBeans without any knowledge of pre-compiled accessors and modifiers. The JavaBeans must conform to the naming design patterns in the JavaBeans specification.
commons-collections.jar in the
In dynamic Java application development environments, it is not always
possible to know ahead in time about the various getter and setter methods for
your JavaBeans. Even when you might know the names of the methods, you may
find it cumbersome to write a
to set or get each and every property of a bean. Consider the case of almost identical beans being transferred from one application layer to
another. Do you call
bean1.setXXX(bean2.getXXX()) for each and
every property? You could, but you don't have to. BeanUtils does it for you!
BeanUtils helps the developer with dynamic JavaBean creation, modification, and
BeanUtils can act on JavaBeans that satisfy the following conditions:
- The JavaBean must provide a no args constructor.
- The JavaBean properties must be accessible and modifiable by
setXXXmethods. For Boolean properties,
setXXXare allowed. These properties can be read/write only, which means that only get or only set for a property is allowed, too.
- If you do decide to name your accessors and modifiers something other than
the traditional "get" and "set," you must declare this in the
BeanInfoclass associated with your JavaBean.
Let us start with a simple example.
To get and set simple properties, use the
PropertyUtils.getSimpleProperty(Object bean, String name) and
PropertyUtils.setSimpleProperty(Object bean, String name, Object value) methods, respectively, as shown below with the help of
AppLayer2Bean.java as our test JavaBeans.
PropertyUtils.setSimpleProperty(app1Bean, "intProp1", new Integer(10)); System.err.println("App1LayerBean, stringProp1: " + PropertyUtils.getSimpleProperty(app1Bean, "stringProp1"));
Why would you use these methods, when you could just as simply get (and set)
the values of these beans by calling the methods directly on the beans
app1Bean.setIntProp1(10))? You may not always know the names of
these properties in advance in your code, and therefore may not know the right
methods to call. These property names might come from variables set by another
process or an external application. So, for example, if you accessed the name
of the property of a bean and stored it in a variable, you could pass the
variable name to
PropertyUtils. This reduces a dependency on the
developer to know the right method names in advance.
What happens when the properties are not simple data types? For example,
your bean might have a collection or a map as a property. In these cases, use
PropertyUtils.getMappedProperty. Indexed properties require you to
pass the index of the value within the collection that you want to get or set.
Mapped properties require you to pass the key of the value you want to get or
set. For example:
PropertyUtils.setIndexedProperty( app1Bean, "listProp1", "New String value 1"); System.err.println("App1LayerBean, listProp1: " + PropertyUtils.getIndexedProperty(app1Bean, "listProp1"));
Notice how, for indexed properties, the value of the index is passed within square brackets. The example above sets the value at index 1 of the list
in the bean
New String value 1, while the
line after that retrieves the same value at index 1. An alternate way of doing
the same thing is to use the methods
PropertyUtils.setIndexedProperty(Object bean, String name, int index,
Object value) and
String name, int index), where the index is passed as a method parameter.
Similar methods exist for mapped properties where you pass the key, not the
index, to get and set mapped values.
Finally, your bean might itself have other beans as properties. What happens
when you want to get or set the property of the bean that is contained as a
property within your primary bean? Use the
PropertyUtils.getNestedProperty(Object bean, String name) and
PropertyUtils.setNestedProperty(Object bean, String name, Object
value) methods, as shown below.
// accessing and setting nested properties PropertyUtils.setNestedProperty( app1Bean, "subBean.stringProp", "Hello from SubBean, set via Nested Property Access"); System.err.println( PropertyUtils.getNestedProperty(app1Bean, "subBean.stringProp"));
As you can see, the contained bean's property is accessed via a dot nomenclature.
You can use a combination of nested, mapped, and indexed properties to any
depths you like. To use a combination of these different property-access methods,
PropertyUtils.getProperty(Object bean, String name) and
PropertyUtils.setProperty(Object bean, String name, Object value).
For example, this would allow you to make method calls such as:
PropertyUtils.setProperty(app1Bean, "subBean.listProp", "Some Value");
This combines nested and indexed property access into one call.
BeanUtils is often used when dynamically accessing the request parameters
for a web-based system. In fact, BeanUtils arose out of a need to transfer the
request parameters dynamically into system JavaBeans in the Struts project. A user-filled form
is transferred into a
Map in code, where the parameter names form
the keys and the parameter values are the values from by the user, and a simple
BeanUtils.populate transfers these values into a system bean.
Finally, BeanUtils provides a one-step method to copy values from one bean into another:
// let's copy app1Bean to app2Bean BeanUtils.copyProperties(app2Bean, app1Bean);
In this package, there are several other useful methods that I have not covered here. BeanUtils is one of the better-documented components. I encourage you to have a look at the Javadocs for this package for descriptions of the rest of the methods.