All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.feilong.lib.beanutils.package-info Maven / Gradle / Ivy

Go to download

feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.

There is a newer version: 4.3.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * 

* The Bean Introspection Utilities component of the Apache Commons * subproject offers low-level utility classes that assist in getting and setting * property values on Java classes that follow the naming design patterns outlined * in the JavaBeans Specification, as well as mechanisms for dynamically defining * and accessing bean properties. *

* *

Table of Contents

* * * * *

1. Overview

* * *

1.1 Background

* *

* The JavaBeans name comes from a * Java API * for a component architecture for the Java language. Writing Java classes that * conform to the JavaBeans design patterns makes it easier for Java developers * to understand the functionality provided by your class, as well as allowing * JavaBeans-aware tools to use Java's introspection capabilities to * learn about the properties and operations provided by your class, and present * them in a visually appealing manner in development tools. *

* *

* The JavaBeans * Specification describes the complete set of characteristics that makes * an arbitrary Java class a JavaBean or not -- and you should consider reading * this document to be an important part of developing your Java programming * skills. However, the required characteristics of JavaBeans that are * important for most development scenarios are listed here: *

*
    *
  • The class must be public, and provide a * public constructor that accepts no arguments. This allows * tools and applications to dynamically create new instances of your bean, * without necessarily knowing what Java class name will be used ahead of * time, like this: * *
     *         String className = ...;
     *         Class beanClass = Class.forName(className);
     *         Object beanInstance = beanClass.newInstance();
     * 
    * *
  • *
  • As a necessary consequence of having a no-arguments constructor, * configuration of your bean's behavior must be accomplished separately * from its instantiation. This is typically done by defining a set of * properties of your bean, which can be used to modify its behavior * or the data that the bean represents. The normal convention for * property names is that they start with a lower case letter, and be * comprised only of characters that are legal in a Java identifier.
  • *
  • Typically, each bean property will have a public getter and * setter method that are used to retrieve or define the property's * value, respectively. The JavaBeans Specification defines a design * pattern for these names, using get or set as the * prefix for the property name with it's first character capitalized. Thus, * you a JavaBean representing an employee might have * (among others) properties named firstName, * lastName, and hireDate, with method signatures * like this: * *
     * public class Employee{
     * 
     *     public Employee(); // Zero-arguments constructor
     * 
     *     public String getFirstName();
     * 
     *     public void setFirstName(String firstName);
     * 
     *     public String getLastName();
     * 
     *     public void setLastName(String lastName);
     * 
     *     public Date getHireDate();
     * 
     *     public void setHireDate(Date hireDate);
     * 
     *     public boolean isManager();
     * 
     *     public void setManager(boolean manager);
     * 
     *     public String getFullName();
     * }
     * 
    * *
  • *
  • As you can see from the above example, there is a special variant allowed * for boolean properties -- you can name the getter method with a * is prefix instead of a get prefix if that makes * for a more understandable method name.
  • *
  • If you have both a getter and a setter method for a * property, the data type returned by the getter must match the * data type accepted by the setter. In addition, it is contrary * to the JavaBeans specification to have more than one setter * with the same name, but different property types.
  • *
  • It is not required that you provide a getter and a * setter for every property. In the example above, the * fullName property is read-only, because there is no * setter method. It is also possible, but less common, to provide * write-only properties.
  • *
  • It is also possible to create a JavaBean where the getter and * setter methods do not match the naming pattern described above. * The standard JavaBeans support classes in the Java language, as well as * all classes in the BeanUtils package, allow you to describe the actual * property method names in a BeanInfo class associated with * your bean class. See the JavaBeans Specification for full details.
  • *
  • The JavaBeans Specification also describes many additional design patterns * for event listeners, wiring JavaBeans together into component hierarchies, * and other useful features that are beyond the scope of the BeanUtils * package.
  • *
* *

* Using standard Java coding techniques, it is very easy to deal with * JavaBeans if you know ahead of time which bean classes you will be using, and * which properties you are interested in: *

* *
 *         Employee employee = ...;
 *         System.out.println("Hello " + employee.getFirstName() + "!");
 * 
* * *

1.2 External Dependencies

* *

* The commons-beanutils package requires that the following * additional packages be available in the application's class path at runtime: *

* * * *

2. Standard JavaBeans

* * *

2.1 Background

* *

* As described above, the standard facilities of the Java programming language * make it easy and natural to access the property values of your beans using * calls to the appropriate getter methods. * But what happens in more sophisticated environments where you do not * necessarily know ahead of time which bean class you are going to be using, * or which property you want to retrieve or modify? The Java language provides * classes like java.beans.Introspector, which can examine a Java * class at runtime and identify for you the names of the property getter and * setter methods, plus the Reflection capabilities to dynamically call * such a method. However, these APIs can be difficult to use, and expose the * application developer to many unnecessary details of the underlying structure * of Java classes. The APIs in the BeanUtils package are intended to simplify * getting and setting bean properties dynamically, where the objects you are * accessing -- and the names of the properties you care about -- are determined * at runtime in your application, rather than as you are writing and compiling * your application's classes. *

* *

* This is the set of needs that are satisfied by the static methods of the * {@link com.feilong.lib.beanutils.PropertyUtils} * class, which are described further in this section. First, however, some * further definitions will prove to be useful: *

* *

* The general set of possible property types supported by a JavaBean can be * broken into three categories -- some of which are supported by the standard * JavaBeans specification, and some of which are uniquely supported by the * BeanUtils package: *

*
    *
  • Simple - Simple, or scalar, properties have a single * value that may be retrieved or modified. The underlying property type * might be a Java language primitive (such as int, a simple * object (such as a java.lang.String), or a more complex * object whose class is defined either by the Java language, by the * application, or by a class library included with the application.
  • *
  • Indexed - An indexed property stores an ordered collection * of objects (all of the same type) that can be individually accessed by an * integer-valued, non-negative index (or subscript). Alternatively, the * entire set of values may be set or retrieved using an array. * As an extension to the JavaBeans specification, the * BeanUtils package considers any property whose underlying data * type is java.util.List (or an implementation of List) to be * indexed as well.
  • *
  • Mapped - As an extension to standard JavaBeans APIs, * the BeanUtils package considers any property whose underlying * value is a java.util.Map to be "mapped". You can set and * retrieve individual values via a String-valued key.
  • *
* *

* A variety of API methods are provided in the * {@link com.feilong.lib.beanutils.PropertyUtils} class to get and set * property values of all of these types. * In the code fragments below, assume that there are two bean classes defined * with the following method signatures: *

* *
 * public class Employee{
 * 
 *     public Address getAddress(String type);
 * 
 *     public void setAddress(String type,Address address);
 * 
 *     public Employee getSubordinate(int index);
 * 
 *     public void setSubordinate(int index,Employee subordinate);
 * 
 *     public String getFirstName();
 * 
 *     public void setFirstName(String firstName);
 * 
 *     public String getLastName();
 * 
 *     public void setLastName(String lastName);
 * }
 * 
* * *

2.2 Basic Property Access

* *

* Getting and setting simple property values is, well, * simple :-). Check out the following API signatures in the Javadocs: *

* *
    *
  • {@link "org.apache.commons.beanutils.PropertyUtils#getSimpleProperty(Object, String)"}
  • *
  • {@link "org.apache.commons.beanutils.PropertyUtils#setSimpleProperty(Object, String, Object)"}
  • *
* *

* Using these methods, you might dynamically manipulate the employee's name * in an application: *

* *
 *     Employee employee = ...;
 *     String firstName = (String)
 *       PropertyUtils.getSimpleProperty(employee, "firstName");
 *     String lastName = (String)
 *       PropertyUtils.getSimpleProperty(employee, "lastName");
 *     ... manipulate the values ...
 *     PropertyUtils.setSimpleProperty(employee, "firstName", firstName);
 *     PropertyUtils.setSimpleProperty(employee, "lastName", lastName);
 * 
* *

* For indexed properties, you have two choices - you can * either build a subscript into the "property name" string, using square * brackets, or you can specify the subscript in a separate argument to the * method call: *

* *
    *
  • {@link com.feilong.lib.beanutils.PropertyUtils#getIndexedProperty(Object, String)}
  • *
  • {@link com.feilong.lib.beanutils.PropertyUtils#getIndexedProperty(Object, String, int)}
  • *
  • {@link com.feilong.lib.beanutils.PropertyUtils#setIndexedProperty(Object, String, Object)}
  • *
  • {@link com.feilong.lib.beanutils.PropertyUtils#setIndexedProperty(Object, String, int, Object)}
  • *
* *

* Only integer constants are allowed when you add a subscript to the property * name. If you need to calculate the index of the entry you wish to retrieve, * you can use String concatenation to assemble the property name expression. * For example, you might do either of the following: *

* *
 *     Employee employee = ...;
 *     int index = ...;
 *     String name = "subordinate[" + index + "]";
 *     Employee subordinate = (Employee)
 *       PropertyUtils.getIndexedProperty(employee, name);
 *
 *     Employee employee = ...;
 *     int index = ...;
 *     Employee subordinate = (Employee)
 *       PropertyUtils.getIndexedProperty(employee, "subordinate", index);
 * 
* *

* In a similar manner, there are two possible method signatures for getting * and setting mapped properties. The difference is that the * extra argument is surrounded by parentheses ("(" and ")") instead of square * brackets, and it is considered to be a String-value key used to get or set * the appropriate value from an underlying map. *

* *
    *
  • {@link com.feilong.lib.beanutils.PropertyUtils#getMappedProperty(Object, String)}
  • *
  • {@link com.feilong.lib.beanutils.PropertyUtils#getMappedProperty(Object, String, String)}
  • *
  • {@link com.feilong.lib.beanutils.PropertyUtils#setMappedProperty(Object, String, Object)}
  • *
  • {@link com.feilong.lib.beanutils.PropertyUtils#setMappedProperty(Object, String, String, Object)}
  • *
* *

* You can, for example, set the employee's home address in either of these * two manners: *

* *
 *     Employee employee = ...;
 *     Address address = ...;
 *     PropertyUtils.setMappedProperty(employee, "address(home)", address);
 *
 *     Employee employee = ...;
 *     Address address = ...;
 *     PropertyUtils.setMappedProperty(employee, "address", "home", address);
 * 
* * *

2.3 Nested Property Access

* *

* In all of the examples above, we have assumed that you wished to retrieve * the value of a property of the bean being passed as the first argument to a * PropertyUtils method. However, what if the property value you retrieve is * really a Java object, and you wish to retrieve a property of that * object instead? *

* *

* For example, assume we really wanted the city property of the * employee's home address. Using standard Java programming techniques for direct * access to the bean properties, we might write: *

* *
 * 
 * String city = employee.getAddress("home").getCity();
 * 
* *

* The equivalent mechanism using the PropertyUtils class is called * nested property access. To use this approach, you concatenate * together the property names of the access path, using "." separators -- very * similar to the way you can perform nested property access in JavaScript. *

* *
    *
  • {@link com.feilong.lib.beanutils.PropertyUtils#getNestedProperty(Object, String)}
  • *
  • {@link com.feilong.lib.beanutils.PropertyUtils#setNestedProperty(Object, String, Object)}
  • *
* *

* The PropertyUtils equivalent to the above Java expression would be: *

* *
 * 
 * String city = (String) PropertyUtils.getNestedProperty(employee, "address(home).city");
 * 
* *

* Finally, for convenience, PropertyUtils provides method signatures that * accept any arbitrary combination of simple, indexed, and mapped property * access, using any arbitrary level of nesting: *

* *
    *
  • {@link com.feilong.lib.beanutils.PropertyUtils#getProperty(Object, String)}
  • *
  • {@link com.feilong.lib.beanutils.PropertyUtils#setProperty(Object, String, Object)}
  • *
* *

* which you might use like this: *

* *
 *     Employee employee = ...;
 *     String city = (String) PropertyUtils.getProperty(employee,
 *       "subordinate[3].address(home).city");
 * 
* * *

2.4 Customizing Introspection

* *

* As was pointed out, BeanUtils relies on conventions defined by the * JavaBeans specification to determine the properties available for * a specific bean class. Thus all classes conforming to these conventions can * be used out of the box. *

* *

* Sometimes an application has to deal with classes using different * conventions. For instance, fluent APIs allowing method chaining are not * compliant to the JavaBeans specification because here set methods * have non-void return values. From version 1.9.0 onwards, BeanUtils supports * customization of its introspection mechanism. This allows an application * to extend or modify the default discovery of bean properties. *

* *

* The key to this extension mechanism is the {@link com.feilong.lib.beanutils.BeanIntrospector} * interface. The purpose of an object implementing this interface is to * process a specific target class and create corresponding * PropertyDescriptor objects for the properties it detects. * Per default, BeanUtils uses a {@link com.feilong.lib.beanutils.DefaultBeanIntrospector} * object which detects properties compatible with the JavaBeans * specification. *

* *

* In order to extend the property discovery mechanism, PropertyUtils * offers the {@link com.feilong.lib.beanutils.PropertyUtils#addBeanIntrospector(BeanIntrospector)} * method. Here a custom BeanIntrospector implementation can be * passed in. During introspection of a class, this custom introspector is * then called, and it can add the properties it has detected to the total * result. As an example of such a custom BeanIntrospector * implementation, BeanUtils ships with the {@link com.feilong.lib.beanutils.FluentPropertyBeanIntrospector} * class. This implementation can detect properties whose set methods have a * non-void return type - thus enabling support for typical properties in a * fluent API. *

* * *

2.5 Suppressing Properties

*

* The mechanism of customizing bean introspection described in the previous * section can also be used to suppress specific properties. There is a * specialized BeanIntrospector implementation that does exactly * this: {@link com.feilong.lib.beanutils.SuppressPropertiesBeanIntrospector}. * When creating an instance, a collection with the names of properties that * should not be accessible on beans has to be provided. These properties will * then be removed if they have been detected by other BeanIntrospector * instances during processing of a bean class. *

* *

* A good use case for suppressing properties is the special class * property which is per default available for all beans; it is generated from the * getClass() method inherited from Object which follows the * naming conventions for property get methods. Exposing this property in an * uncontrolled way can lead to a security vulnerability as it allows access to * the class loader. More information can be found at * * https://issues.apache.org/jira/browse/BEANUTILS-463. *

* *

* Because the class property is undesired in many use cases * there is already an instance of SuppressPropertiesBeanIntrospector * which is configured to suppress this property. It can be obtained via the * SUPPRESS_CLASS constant of * SuppressPropertiesBeanIntrospector. *

* * *

3. Dynamic Beans (DynaBeans)

* * *

3.1 Background

* *

* The {@link com.feilong.lib.beanutils.PropertyUtils} class described in the * preceding section is designed to provide dynamic property access on existing * JavaBean classes, without modifying them in any way. A different use case for * dynamic property access is when you wish to represent a dynamically calculated * set of property values as a JavaBean, but without having to actually * write a Java class to represent these properties. Besides the effort savings * in not having to create and maintain a separate Java class, this ability also * means you can deal with situations where the set of properties you care about * is determined dynamically (think of representing the result set of an SQL * select as a set of JavaBeans ...). *

* *

* To support this use case, the BeanUtils package provides the * {@link org.apache.commons.beanutils.DynaBean} interface, which must be implemented by a * bean class actually implementing the interface's methods, and the associated * {@link com.feilong.lib.beanutils.DynaClass} interface that defines the set of * properties supported by a particular group of DynaBeans, in much the same way * that java.lang.Class defines the set of properties supported by * all instances of a particular JavaBean class. *

* *

* For example, the Employee class used in the examples above * might be implemented as a DynaBean, rather than as a standard JavaBean. You * can access its properties like this: *

* *
 *     DynaBean employee = ...; // Details depend on which
 *                              // DynaBean implementation you use
 *     String firstName = (String) employee.get("firstName");
 *     Address homeAddress = (Address) employee.get("address", "home");
 *     Object subordinate = employee.get("subordinate", 2);
 * 
* *

* One very important convenience feature should be noted: the * PropertyUtils property getter and setter methods understand how to access * properties in DynaBeans. Therefore, if the bean you pass as the first * argument to, say, PropertyUtils.getSimpleProperty() is really a * DynaBean implementation, the call will get converted to the appropriate * DynaBean getter method transparently. Thus, you can base your application's * dynamic property access totally on the PropertyUtils APIs, if you wish, and * use them to access either standard JavaBeans or DynaBeans without having to * care ahead of time how a particular bean is implemented. *

* *

* Because DynaBean and DynaClass are interfaces, they may be implemented * multiple times, in different ways, to address different usage scenarios. The * following subsections describe the implementations that are provided as a part * of the standard BeanUtils package, although you are encouraged to * provide your own custom implementations for cases where the standard * implementations are not sufficient. *

* * *

3.2 BasicDynaBean and BasicDynaClass

* *

* The {@link com.feilong.lib.beanutils.BasicDynaBean} and * {@link com.feilong.lib.beanutils.BasicDynaClass} implementation provides a * basic set of * dynamic property capabilities where you want to dynamically define the * set of properties (described by instances of {@link com.feilong.lib.beanutils.DynaProperty}). * You start by defining the DynaClass that establishes * the set of properties you care about: *

* *
 * 
 * DynaProperty[] props = new DynaProperty[] {
 *                                                 new DynaProperty("address", java.util.Map.class),
 *                                                 new DynaProperty("subordinate", mypackage.Employee[].class),
 *                                                 new DynaProperty("firstName", String.class),
 *                                                 new DynaProperty("lastName", String.class) };
 * 
 * BasicDynaClass dynaClass = new BasicDynaClass("employee", null, props);
 * 
* *

* Note that the 'dynaBeanClass' argument (in the constructor of * BasicDynaClass) can have the value of null. In this * case, the value of dynaClass.getDynaBeanClass will just be the * Class for BasicDynaBean. *

* *

* Next, you use the newInstance() method of this DynaClass to * create new DynaBean instances that conform to this DynaClass, and populate * its initial property values (much as you would instantiate a new standard * JavaBean and then call its property setters): *

* *
 * DynaBean employee = dynaClass.newInstance();
 * employee.set("address", new HashMap());
 * employee.set("subordinate", new mypackage.Employee[0]);
 * employee.set("firstName", "Fred");
 * employee.set("lastName", "Flintstone");
 * 
* *

* Note that the DynaBean class was declared to be * DynaBean instead of BasicDynaBean. In * general, if you are using DynaBeans, you will not want to care about the * actual implementation class that is being used -- you only care about * declaring that it is a DynaBean so that you can use the * DynaBean APIs. *

* *

* As stated above, you can pass a DynaBean instance as the first argument * to a PropertyUtils method that gets and sets properties, and it * will be interpreted as you expect -- the dynamic properties of the DynaBean * will be retrieved or modified, instead of underlying properties on the * actual BasicDynaBean implementation class. *

* * *

3.3 ResultSetDynaClass (Wraps ResultSet in DynaBeans)

* *

* A very common use case for DynaBean APIs is to wrap other collections of * "stuff" that do not normally present themselves as JavaBeans. One of the most * common collections that would be nice to wrap is the * java.sql.ResultSet that is returned when you ask a JDBC driver * to perform a SQL SELECT statement. Commons BeanUtils offers a standard * mechanism for making each row of the result set visible as a DynaBean, * which you can utilize as shown in this example: *

* *
 *   Connection conn = ...;
 *   Statement stmt = conn.createStatement();
 *   ResultSet rs = stmt.executeQuery
 *     ("select account_id, name from customers");
 *   Iterator rows = (new ResultSetDynaClass(rs)).iterator();
 *   while (rows.hasNext()) {
 *     DynaBean row = (DynaBean) rows.next();
 *     System.out.println("Account number is " +
 *                        row.get("account_id") +
 *                        " and name is " + row.get("name"));
 *   }
 *   rs.close();
 *   stmt.close();
 * 
* * * *

3.4 RowSetDynaClass (Disconnected ResultSet as DynaBeans)

*

* Although ResultSetDynaClass is * a very useful technique for representing the results of an SQL query as a * series of DynaBeans, an important problem is that the underlying * ResultSet must remain open throughout the period of time that the * rows are being processed by your application. This hinders the ability to use * ResultSetDynaClass as a means of communicating information from * the model layer to the view layer in a model-view-controller architecture * such as that provided by the Struts * Framework, because there is no easy mechanism to assure that the result set * is finally closed (and the underlying Connection returned to its * connection pool, if you are using one). *

* *

* The RowSetDynaClass class represents a different approach to * this problem. When you construct such an instance, the underlying data is * copied into a set of in-memory DynaBeans that represent the result. * The advantage of this technique, of course, is that you can immediately close * the ResultSet (and the corresponding Statement), normally before you even * process the actual data that was returned. The disadvantage, of course, is * that you must pay the performance and memory costs of copying the result data, * and the result data must fit entirely into available heap memory. For many * environments (particularly in web applications), this tradeoff is usually * quite beneficial. *

* *

* As an additional benefit, the RowSetDynaClass class is defined * to implement java.io.Serializable, so that it (and the * DynaBeans that correspond to each row of the result) can be conveniently * serialized and deserialized (as long as the underlying column values are * also Serializable). Thus, RowSetDynaClass represents a very * convenient way to transmit the results of an SQL query to a remote Java-based * client application (such as an applet). *

* *

* The normal usage pattern for a RowSetDynaClass will look * something like this: *

* *
 *     Connection conn = ...;  // Acquire connection from pool
 *     Statement stmt = conn.createStatement();
 *     ResultSet rs = stmt.executeQuery("SELECT ...");
 *     RowSetDynaClass rsdc = new RowSetDynaClass(rs);
 *     rs.close();
 *     stmt.close();
 *     ...;                    // Return connection to pool
 *     List rows = rsdc.getRows();
 *     ...;                   // Process the rows as desired
 * 
* * * *

3.5 WrapDynaBean and WrapDynaClass

* *

* OK, you've tried the DynaBeans APIs and they are cool -- very simple * get() and set() methods provide easy access to all * of the dynamically defined simple, indexed, and mapped properties of your * DynaBeans. You'd like to use the DynaBean APIs to access all * of your beans, but you've got a bunch of existing standard JavaBeans classes * to deal with as well. This is where the * {@link com.feilong.lib.beanutils.WrapDynaBean} (and its associated * {@link com.feilong.lib.beanutils.WrapDynaClass}) come into play. As the name * implies, a WrapDynaBean is used to "wrap" the DynaBean APIs around an * existing standard JavaBean class. To use it, simply create the wrapper * like this: *

* *
 *     MyBean bean = ...;
 *     DynaBean wrapper = new WrapDynaBean(bean);
 *     String firstName = wrapper.get("firstName");
 * 
* *

* Note that, although appropriate WrapDynaClass instances are * created internally, you never need to deal with them. *

* * *

3.6 Lazy DynaBeans

* *
    *
  • 1. LazyDynaBean - A Lazy * {@link org.apache.commons.beanutils.DynaBean}
  • *
  • 2. LazyDynaMap - A light weight * {@link org.apache.commons.beanutils.DynaBean} facade to a Map * with lazy map/list processing
  • *
  • 3. LazyDynaList - A lazy list * for {@link org.apache.commons.beanutils.DynaBean DynaBean's}, * java.util.Map's or POJO beans.
  • *
  • 4. LazyDynaClass - A * {@link com.feilong.lib.beanutils.MutableDynaClass} implementation.
  • *
* *

* You bought into the DynaBeans because it saves coding all those POJO JavaBeans but * you're here because lazy caught your eye and wondered whats that about? * What makes these flavors of DynaBean lazy are the following features: *

*
    *
  • Lazy property addition - lazy beans use a * {@link com.feilong.lib.beanutils.DynaClass} which implements * the {@link com.feilong.lib.beanutils.MutableDynaClass} * interface. This provides the ability to add and remove a DynaClass's * properties. Lazy beans use this feature to automatically add * a property which doesn't exist to the DynaClass when * the set(name, value) method is called.
  • *
  • Lazy List/Array growth - If an indexed property is not large * enough to accomodate the index being set then the List or * Array is automatically grown so that it is.
  • *
  • Lazy List/Array instantiation - if an indexed * property doesn't exist then calling the {@link org.apache.commons.beanutils.DynaBean DynaBean's} * indexed property getter/setter methods (i.e. get(name, index) or * set(name, index, value)) results in either a new List * or Array being instantiated. If the indexed property has not been * defined in the DynaClass then it is automatically added and a default List * implementation instantiated.
  • *
  • Lazy Map instantiation - if a mapped * property doesn't exist then calling the {@link org.apache.commons.beanutils.DynaBean DynaBean's} * mapped property getter/setter methods (i.e. get(name, key) or * set(name, key, value)) results in a new Map * being instantiated. If the mapped property has not been defined in the DynaClass * then it is automatically added and a default Map implementation * instantiated.
  • *
  • Lazy Bean instantiation - if a property is defined in * the DynaClass as a DynaBean or regular bean and * doesn't exist in the DynaBean then LazyDynaBean wiill * try to instantiate the bean using a default empty constructor.
  • *
* *

* 1. {@link com.feilong.lib.beanutils.LazyDynaBean} is the standard lazy bean * implementation. By default it is associated with a {@link com.feilong.lib.beanutils.LazyDynaClass} * which implements the {@link com.feilong.lib.beanutils.MutableDynaClass} interface - however * it can be used with any MutableDynaClass implementation. The question is how do * I use it? - well it can be as simple as creating a new bean and then calling the getters/setters... *

* *
 * DynaBean dynaBean = new LazyDynaBean();
 *
 * dynaBean.set("foo", "bar"); // simple
 *
 * dynaBean.set("customer", "title", "Mr"); // mapped
 * dynaBean.set("customer", "surname", "Smith"); // mapped
 *
 * dynaBean.set("address", 0, addressLine1); // indexed
 * dynaBean.set("address", 1, addressLine2); // indexed
 * dynaBean.set("address", 2, addressLine3); // indexed
 * 
* *

* 2. {@link com.feilong.lib.beanutils.LazyDynaMap} is a light weight * DynaBean facade to a Map with all the usual lazy features. Its * light weight because it doesn't have an associated DynaClass containing all the properties. * In fact it actually implements the DynaClass interface itself (and MutableDynaClass) * and derives all the DynaClass information from the actual contents of the Map. A * LazyDynaMap can be created around an existing Map or can instantiate its own * Map. After any DynaBean processing has finished the Map can be retrieved * and the DynaBean facade discarded. *

* *

* If you need a new Map then to use.... *

* *
 *     DynaBean dynaBean = new LazyDynaMap();        // create DynaBean
 *
 *     dynaBean.set("foo", "bar");                   // simple
 *     dynaBean.set("customer", "title", "Mr");      // mapped
 *     dynaBean.set("address", 0, addressLine1);     // indexed
 *
 *     Map myMap = dynaBean.getMap()                 // retrieve the Map
 * 
*

* or to use with an existing Map .... *

* *
 *     Map myMap = ....                             // exisitng Map
 *     DynaBean dynaBean = new LazyDynaMap(myMap);  // wrap Map in DynaBean
 *     dynaBean.set("foo", "bar");                  // set properties
 * 
* *

* 3. {@link com.feilong.lib.beanutils.LazyDynaList} * is lazy list for {@link org.apache.commons.beanutils.DynaBean DynaBeans} * java.util.Map's or POJO beans. See the Javadoc * for more details and example usage. *

* *

* 4. {@link com.feilong.lib.beanutils.LazyDynaClass} * extends {@link com.feilong.lib.beanutils.BasicDynaClass} and implements * the MutableDynaClass interface. * It can be used with other DynaBean implementations, but it * is the default DynaClass used by LazyDynaBean. * When using the LazyDynaBean there may be no need to have * anything to do with the DynaClass. However sometimes there * is a requirement to set up the DynaClass first - perhaps to * define the type of array for an indexed property, or if using the DynaBean * in restricted mode (see note below) is required. Doing so is * straight forward... *

* *

* Either create a LazyDynaClass first... * *

 * MutableDynaClass dynaClass = new LazyDynaClass(); // create DynaClass
 *
 * dynaClass.add("amount", java.lang.Integer.class); // add property
 * dynaClass.add("orders", OrderBean[].class); // add indexed property
 * dynaClass.add("orders", java.util.TreeMapp.class); // add mapped property
 *
 * DynaBean dynaBean = new LazyDynaBean(dynaClass); // Create DynaBean with associated DynaClass
 * 
* *

* or create a LazyDynaBean and get the DynaClass... * *

 * DynaBean dynaBean = new LazyDynaBean(); // Create LazyDynaBean
 * MutableDynaClass dynaClass = (MutableDynaClass) dynaBean.getDynaClass(); // get DynaClass
 *
 * dynaClass.add("amount", java.lang.Integer.class); // add property
 * dynaClass.add("myBeans", myPackage.MyBean[].class); // add 'array' indexed property
 * dynaClass.add("myMap", java.util.TreeMapp.class); // add mapped property
 * 
* *

* NOTE: One feature of {@link com.feilong.lib.beanutils.MutableDynaClass} is that it * has a Restricted property. When the DynaClass is restricted no properties can be added * or removed from the DynaClass. Neither the LazyDynaBean or LazyDynaMap * will add properties automatically if the DynaClass is restricted. *

* * * *

4. Data Type Conversions

* * *

4.1 Background

* *

* So far, we've only considered the cases where the data types of the * dynamically accessed properties are known, and where we can use Java casts * to perform type conversions. What happens if you want to automatically * perform type conversions when casting is not possible? The * BeanUtils package provides a variety of APIs and design patterns * for performing this task as well. *

* * *

4.2 BeanUtils and ConvertUtils Conversions

* *

* A very common use case (and the situation that caused the initial creation * of the BeanUtils package) was the desire to convert the set of request * parameters that were included in a * javax.servlet.HttpServletRequest received by a web application * into a set of corresponding property setter calls on an arbitrary JavaBean. * (This is one of the fundamental services provided by the * Struts Framework, which uses * BeanUtils internally to implement this functionality.) *

* *

* In an HTTP request, the set of included parameters is made available as a * series of String (or String array, if there is more than one value for the * same parameter name) instances, which need to be converted to the underlying * data type. The {@link com.feilong.lib.beanutils.BeanUtils} class provides * property setter methods that accept String values, and automatically convert * them to appropriate property types for Java primitives (such as * int or boolean), and property getter methods that * perform the reverse conversion. Finally, a populate() method * is provided that accepts a java.util.Map containing a set of * property values (keyed by property name), and calls all of the appropriate * setters whenever the underlying bean has a property with the same name as * one of the request parameters. So, you can perform the all-in-one property * setting operation like this: *

* *
 *     HttpServletRequest request = ...;
 *     MyBean bean = ...;
 *     HashMap map = new HashMap();
 *     Enumeration names = request.getParameterNames();
 *     while (names.hasMoreElements()) {
 *       String name = (String) names.nextElement();
 *       map.put(name, request.getParameterValues(name));
 *     }
 *     BeanUtils.populate(bean, map);
 * 
* *

* The BeanUtils class relies on conversion methods defined in * the {@link com.feilong.lib.beanutils.ConvertUtils} class to perform the actual * conversions, and these methods are availablve for direct use as well. * WARNING - It is likely that the hard coded use of * ConvertUtils methods will be deprecated in the future, and * replaced with a mechanism that allows you to plug in your own implementations * of the {@link com.feilong.lib.beanutils.Converter} interface instead. Therefore, * new code should not be written with reliance on ConvertUtils. *

* * *

4.3 Defining Your Own Converters

* *

* The ConvertUtils class supports the ability to define and * register your own String --> Object conversions for any given Java class. * Once registered, such converters will be used transparently by all of the * BeanUtils methods (including populate()). To * create and register your own converter, follow these steps: *

*
    *
  • Write a class that implements the {@link com.feilong.lib.beanutils.Converter} * interface. The convert() method should accept the * java.lang.Class object of your application class (i.e. * the class that you want to convert to, and a String representing the * incoming value to be converted.
  • *
  • At application startup time, register an instance of your converter class * by calling the ConvertUtils.register() method.
  • *
* * *

4.4 Locale Aware Conversions

*

* The standard classes in org.apache.commons.beanutils are not * locale aware. This gives them a cleaner interface and makes then easier to use * in situations where the locale is not important. *

*

* Extended, locale-aware analogues can be found in * org.apache.commons.beanutils.locale * . These are built along the same * lines as the basic classes but support localization. *

* * * *

5. Utility Objects And Static Utility Classes

* *

Background

*

* So far, the examples have covered the static utility classes (BeanUtils, * ConvertUtils and PropertyUtils). These are easy to use but are * somewhat inflexible. These all share the same registered converters and the same caches. *

*

* This functionality can also be accessed through utility objects (in fact, the static utility * class use worker instances of these classes). For each static utility class, there is a corresponding * class with the same functionality that can be instantiated: *

*

*

* * * * * * * * * * * * * * * * *
Static Utility ClassUtility Object
BeanUtilsBeanUtilsBean
ConvertUtilsConvertUtilsBean
PropertyUtilsPropertyUtilsBean
*

*

* Creating an instances allow gives guarenteed control of the caching and registration * to the code that creates it. *

* * *

6. Collections

* *

6.1 Comparing Beans

*

* org.apache.commons.beanutils.BeanComparator is a Comparator implementation * that compares beans based on a shared property value. *

* *

6.2 Operating On Collections Of Beans

*

* The Closure interface in commons-collections encapsulates a block of code that * executes on an arbitrary input Object. Commons-collections contains code that allows * Closures to be applied to the contents of a Collection. For more details, see the * commons-collections * documentation. *

*

* BeanPropertyValueChangeClosure is a Closure that sets a specified property * to a particular value. A typical usage is to combine this with commons-collections * so that all the beans in a collection can have a particular property set to a particular value. *

*

* For example, set the activeEmployee property to TRUE for an entire collection: *

 *     // create the closure
 *     BeanPropertyValueChangeClosure closure =
 *         new BeanPropertyValueChangeClosure( "activeEmployee", Boolean.TRUE );
 *
 *     // update the Collection
 *     CollectionUtils.forAllDo( peopleCollection, closure );
 *   
*

* * *

6.3 Querying Or Filtering Collections Of Beans

*

* The Predicate interface in commons-collections encapsulates an evaluation * of an input Object that returns either true or false. Commons-collections contains code * that allows * Predicates to be applied to be used to filter collections. For more details, see the * commons-collections * documentation. *

*

* BeanPropertyValueEqualsPredicate is a Predicate that evaluates a * set property value against a given value. A typical usage is * (in combination with commons-collections) * to filter collections on the basis of a property value. *

*

* For example, to filter a collection to find all beans where active employee is false use: *

 *     BeanPropertyValueEqualsPredicate predicate =
 *         new BeanPropertyValueEqualsPredicate( "activeEmployee", Boolean.FALSE );
 *
 *     // filter the Collection
 *     CollectionUtils.filter( peopleCollection, predicate );
 * 
*

* * *

6.4 Transforming Collections Of Beans

*

* The Transformer interface in commons-collections encapsulates the transformation * of an input Object into an output object. Commons-collections contains code * that allows * Transformers to be applied produce a collection of outputs from a collection of inputs. * For more details, see the * commons-collections * documentation. *

*

* BeanToPropertyTransformer is a Transformer implementation * that transforms a bean into it's property value. *

*

* For example, to find all cities that are contained in the address of each person property of each bean in * a collection: *

 *     // create the transformer
 *     BeanToPropertyValueTransformer transformer = new BeanToPropertyValueTransformer( "person.address.city" );
 *
 *     // transform the Collection
 *     Collection peoplesCities = CollectionUtils.collect( peopleCollection, transformer );
 *     
*

* * *

7. Frequently Asked Questions

* * *

Why Can't BeanUtils Find My Method?

*

* The BeanUtils package relies on introspection rather than * reflection. This means that it will find only * JavaBean * compliant properties. *

*

* There are some subtleties of this specification that can catch out the unwary: *

    *
  • A property can have only one set and one get method. Overloading is not allowed.
  • *
  • The java.beans.Introspector searches widely for a custom BeanInfo * class. If your class has the same name as another with a custom BeanInfo * (typically a java API class) then the Introspector may use that instead of * creating via reflection based on your class. If this happens, the only solution is to * create your own BeanInfo.
  • *
*

* *

How Do I Set The BeanComparator Order To Be Ascending/Descending?

*

* BeanComparator relies on an internal Comparator to perform the actual * comparisions. By default, * org.apache.commons.collections.comparators.ComparableComparator * is used which imposes a natural order. If you want to change the order, * then a custom Comparator should be created and passed into the * appropriate constructor. *

*

* For example: *

*
 *     import org.apache.commons.collections.comparators.ComparableComparator;
 *     import org.apache.commons.collections.comparators.ReverseComparator;
 *     import org.apache.commons.beanutils.BeanComparator;
 *     ...
 *     BeanComparator reversedNaturalOrderBeanComparator
 *         = new BeanComparator("propertyName", new ReverseComparator(new ComparableComparator()));
 *     Collections.sort(myList, reversedNaturalOrderBeanComparator);
 *     ...
 * 
*/ package com.feilong.lib.beanutils;




© 2015 - 2024 Weber Informatics LLC | Privacy Policy