(java 往日的翻译) commons-beanutils用法 第四章至结尾

发布时间: 2008-05-06 02:57:00

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.

目前为止,我们考虑的仅仅是这样的情况:要动态访问的属性类型都是已知的,而且我们可以使用java cast进行类型转换。但是如果我们想在无法cast时进行自动的类型转换呢?为了解决这个问题,BeanUtils包也提供了多种API和设计模式。

4.2 BeanUtils and ConvertUtils Conversions
4.2 BeanUtils和ConvertUtils的转换

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.)
有这样一个常见的情景(这也是BeanUtils包产生的初衷):希望在WEB应用中,把 javax.servlet.HttpServletRequest中包含的参数转化成对应的JavaBean中的属性。(这也是Struts框架提供的一个基本的服务,它使用了BeanUtils作为实现)

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 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:

在一个HTTP request中包含的参数的值是字符串(如果有多个同名的参数,那么这些参数的值就是字符串数组),我们需要把它们进行类型转换。BeanUtils类提供的setter方法接受string类型的值,并自动把它转换成合适的java基本类型(例如int或boolean),BeanUtils类的 getter方法提供与之相反的转换。最后,可以使用populate()方法来接收一个包含了属性值(以属性名作为key的) java.util.Map,只要底层的bean中含有request参数中的同名属性,该方法会调用所有对应的setter方法。所以,我们可以这样执行一步到位(all-in-one)的属性操作:

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 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 Converter interface instead. Therefore, new code should not be written with reliance on ConvertUtils.
BeanUtils类依赖于定义在ConvertUtils类中的转换方法,来执行实际的转换,这些方法也是可以直接使用的。警告 - 以硬编码的方式使用ConvertUtils的方法将很快不赞成使用,取而代之的是允许我们使用可以自定制实现类的插件。因此,请在写新的代码时不要依赖 ConverUtils。

4.3 Defining Your Own Converters 定义自己的Converter

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:
ConvertUtils类对任何Java类都支持定义和注册我们自己的String --> Object的转换。一旦注册了,这些Converter对于所有的BeanUtils的方法(包括populate())都是可见的。想建立并注册我们自己的Converter,有以下几步:

* Write a class that implements the 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.
写一个Converter接口的实现类。convert()方法应该接收java.lang.Class 类型的对象作为参数。(也就是说,一个参数代表我们想转换的类,另一个String参数代表将要被转换的输入值)
* At application startup time, register an instance of your converter class by calling the ConvertUtils.register() method.

4.4 Locale Aware Conversions 本地化Aware转换

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.
org.apache.commons.beanutils包提供的标准类不是locale aware. 这是为了让这些接口更简洁,在本地化不重要的情况下更易于使用。

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.
另外,locale-ware 的同样功能的类也可以在org.apache.commons.beanutils.locale中找到。它们跟包中的基本类地位一样(along the same lines),只是支持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.
目前,上面的例子包括了静态工具类的使用(BeanUtils, ConvertUtils和PropertyUtils)。它们用着很简单,但是扩展性稍微差点。 它们共用同样的converter和换存。

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 Class Utility Object
BeanUtils BeanUtilsBean
ConvertUtils ConvertUtilsBean
PropertyUtils PropertyUtilsBean

Creating an instances allow gives guarenteed control of the caching and registration to the code that creates it.
建立这些实例使得 建立缓存和注册的代码得到了控制权。(?) guarenteed 应该写成:guaranteed.

6. Collections 集合
6.1 Comparing Beans 比较Bean

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 对bean集合的操作

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.
BeanPropertyValueChangeClosure 是可以对某个属性设置特定值的一个Closure实现。一个典型的用法是跟common-collections结合使用,让某个集合的所有bean的特定属性具有特定的值。

For example, set the activeEmployee property to TRUE for an entire collection:
例如,对整个集合中的(所有对象的) 所有activeEmployee属性设置成TRUE:

// 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 对集合中的Bean进行查询或过滤

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.

commons-collections中的Predicate接口封装了这样的操作:对一个输入的对象进行判断,返回true或false。 该接口可以对commons-collections包中的类进行使用。

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.
BeanPropertyValueEqualsPredicate是Predicate的一个实现,它可以根据某个已知值与一组属性值进行比较。一个典型的用法是与 commons-collections结合使用,来根据某个属性值对一组集合进行过滤。

For example, to filter a collection to find all beans where active employee is false use:
例如,想对一组集合过滤,找出active employee是false的bean的用法:

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.
commons-collections中的Transformer接口封装了这样的操作:把一个输入对象转换成一个输出对象。commons -collections允许该接口把一个集合作为输入,转换后输出一个集合。更多细节,请看 commons-collections文档。

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:
(意译:某个集合由多个bean组成,每个bean都有一个person 属性,每个person属性都有 address属性,现在想找出该集合中address里出现过的所有city):

// create the transformer
BeanToPropertyValueTransformer transformer = new BeanToPropertyValueTransformer( "" );

// 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.
(译注:也就是说,某个属性相对应的getter/setter方法肯定可以找到。而没有属性对应的方法,例如 myToString() 就找不到。因为自省找不到这个方法对应的property)

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.
java.beans.Instrospactor会查询自定义的BeanInfo.如果你的class与别的class使用了同一个自定义的 BeanInfo(例如java API类)那么 Instrospector就会使用那个BeanInfo,而不是通过你的类的反射建立新的BeanInfo. 唯一的解决办法是:建立你的自定义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.
BeanComparator在执行比较时,依赖于一个内部的Comparator。默认情况下,使用提供了自然顺序(译注:natural order, 对数字,字符串一般是ascending)的 org.apache.commons.collections.comparators.ComparableComparator。如果你想改变它的顺序,就请建立一个自定义的Comparator然后调用适当的(BeanComparator的)构造函数。

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);