即日起在codingBlog上分享您的技术经验即可获得积分,积分可兑换现金哦。

Part III. 核心技术-9. 验证,数据绑定与类型转换-9.4 Bean操作与BeanWrapper

编程语言 dreamsunday 16℃ 0评论
本文目录
[隐藏]

下面你会发现一些使用BeanWrapper来获取和设置属性的例子。

(如果您不打算直接使用BeanWrapper,下一节对您来说并不重要,如果您只是使用DataBinderBeanFactory及其即时实施,您应该跳过
关于PropertyEditors的部分)

考虑以下两个类:

public class Company {



private String name;

private Employee managingDirector;



public String getName() {

return this.name;

}



public void setName(String name) {

this.name = name;

}



public Employee getManagingDirector() {

return this.managingDirector;

}



public void setManagingDirector(Employee managingDirector) {

this.managingDirector = managingDirector;

}

}

public class Employee {



private String name;



private float salary;



public String getName() {

return this.name;

}



public void setName(String name) {

this.name = name;

}



public float getSalary() {

return salary;

}



public void setSalary(float salary) {

this.salary = salary;

}

}

以下代码片段显示了如何检索和操作实例化Companies 和 Employees的某些属性的示例:

BeanWrapper company = new BeanWrapperImpl(new Company());

// setting the company name..

company.setPropertyValue("name", "Some Company Inc.");

// ... can also be done like this:

PropertyValue value = new PropertyValue("name", "Some Company Inc.");

company.setPropertyValue(value);



// ok, let's create the director and tie it to the company:

BeanWrapper jim = new BeanWrapperImpl(new Employee());

jim.setPropertyValue("name", "Jim Stravinsky");

company.setPropertyValue("managingDirector", jim.getWrappedInstance());



// retrieving the salary of the managingDirector through the company

Float salary = (Float) company.getPropertyValue("managingDirector.salary");

1. 9.4.2 内置PropertyEditor实现

Spring使用PropertyEditors的概念来实现ObjectString之间的转换。
如果您考虑到这一点,有时可能会以与对象本身不同的方式表示属性。 例如,Date可以用人类可读的方式表示(作为String’2007-14-09’),而我们仍然可以将人类可读的形式转换回原始日期(或者更好的是:转换任何
日期以人类可读的形式输入,返回到Date对象)。 可以通过注册类型为java.beans.PropertyEditor的自定义编辑器来实现此行为。 在BeanWrapper或者在上一章中提到的特定IoC容器中注册自定义编辑器,可以了解如何将属性转换为所需类型。
在Oracle提供的java.beans包的javadoc中阅读有关PropertyEditors的更多信息。

Spring中使用了一些属性编辑的例子:

  • 在bean上设置属性是使用PropertyEditor完成的。 当提到java.lang.String作为您在XML文件中声明的某个bean的属性的值时,Spring将(如果相应属性的setter具有Class参数),则使用ClassEditor尝试将参数解析为
    一个Class对象。

  • 在Spring的MVC框架中解析HTTP请求参数是使用可以在CommandController的所有子类中手动绑定的各种PropertyEditor完成的。

Spring有一些内置的PropertyEditor,使生活变得轻松。 其中的每个都列在下面,它们都位于org.springframework.beans.propertyeditors包中。
大多数但不是全部(如下所示),默认情况下由BeanWrapperImpl注册。 在某些方面,属性编辑器可以配置,您当然可以注册自己的变体来覆盖默认的变体:

Class Explanation
ByteArrayPropertyEditor 字节数组编辑器 字符串将简单地转换为相应的字节表示。 由BeanWrapperImpl默认注册。
ClassEditor 解析表示classes到实际classes的方式,而另一种方式。 当找不到类时,将抛出IllegalArgumentException。 由BeanWrapperImpl默认注册。
CustomBooleanEditor Boolean属性的可定制属性编辑器。 由BeanWrapperImpl默认注册,但可以通过将其自定义实例注册为自定义编辑器来覆盖。
CustomCollectionEditor 集合的属性编辑器,将任何源集合转换为给定的目标集合类型。
CustomDateEditor 可定制的java.util.Date属性编辑器,支持自定义日期格式。 默认情况下未注册。 必须使用适当格式的用户注册。
CustomNumberEditor 任何Number子类的可定制属性编辑器,如IntegerLongFloatDouble
BeanWrapperImpl默认注册,但可以通过将其自定义实例注册为自定义编辑器来覆盖。
FileEditor 能够将字符串解析为java.io.File对象。 由BeanWrapperImpl默认注册。
InputStreamEditor 单向属性编辑器,能够获取文本字符串并生成(通过中间的ResourceEditorResourceInputStream,因此InputStream属性可以直接设置为字符串。
请注意,默认使用情况不会关闭InputStream! 由BeanWrapperImpl默认注册。
LocaleEditor 能够将字符串解析为Locale对象,反之亦然(String格式为[country] [variant],这与Locale提供的toString()方法相同)。
BeanWrapperImpl默认注册。
PatternEditor 能够将字符串解析为java.util.regex.Pattern对象,反之亦然。
PropertiesEditor 能够转换字符串(使用java.util.Properties类的javadocs中定义的格式格式化)为Properties对象。
BeanWrapperImpl默认注册。
StringTrimmerEditor 编辑字符串的属性编辑器。 可以允许将空字符串转换为空值。 默认情况下未注册; 必须根据需要进行用户注册。
URLEditor 能够将URL的String表示形式解析为实际的URL对象。
BeanWrapperImpl默认注册。

Spring使用java.beans.PropertyEditorManager设置可能需要的属性编辑器的搜索路径。 搜索路径还包括sun.bean.editors,其中包括用于诸如FontColor和大多数原始类型之类的PropertyEditor实现。
还要注意的是,标准的JavaBeans基础设施会自动发现PropertyEditor类(如果不需要明确地注册它们),如果它们处于与他们处理的类在同一个包中,并且具有与该类相同的名称,并附加“Editor”例如,可以具有以下类和包结构,这足以使FooEditor类被识别并用作Foo类型属性的PropertyEditor

com

chank

pop

Foo

FooEditor // the PropertyEditor for the Foo class

请注意,您也可以在这里使用标准的BeanInfo JavaBeans机制(在这里不详细的描述)。 在下面的一个示例中,使用BeanInfo机制来显式注册一个或多个具有关联类的属性的PropertyEditor实例。

com

chank

pop

Foo

FooBeanInfo // the BeanInfo for the Foo class

以下是引用的FooBeanInfo类的Java源代码。 这将关联一个CustomNumberEditorFoo类的age属性。

public class FooBeanInfo extends SimpleBeanInfo {



public PropertyDescriptor[] getPropertyDescriptors() {

try {

final PropertyEditor numberPE = new CustomNumberEditor(Integer.class, true);

PropertyDescriptor ageDescriptor = new PropertyDescriptor("age", Foo.class) {

public PropertyEditor createPropertyEditor(Object bean) {

return numberPE;

};

};

return new PropertyDescriptor[] { ageDescriptor };

}

catch (IntrospectionException ex) {

throw new Error(ex.toString());

}

}

}

1.1. 注册其他自定义PropertyEditor

将bean属性设置为字符串值时,Spring IoC容器最终将使用标准的JavaBeans PropertyEditors将这些字符串转换为该属性的复杂类型。 Spring预先注册了一些自定义的PropertyEditor(例如,将一个表达为一个字符串的类名转换为一个真正的Class对象)。另外,Java的标准JavaBeans PropertyEditor查找机制允许一个类的PropertyEditor简单地被适当地命名,并且被放置在与它提供的类相同的包中,以便被自动找到。

如果需要注册其他自定义PropertyEditor,则可以使用多种机制。假设您有一个BeanFactory引用,那么通常不方便或推荐最方便的方法是简单地使用ConfigurableBeanFactory接口的registerCustomEditor()方法。另一个稍微更方便的机制就是使用一个名为CustomEditorConfigurer的特殊bean工厂后处理器。虽然Bean
Factory
后处理器可以与BeanFactory实现一起使用,但CustomEditorConfigurer具有嵌套属性设置,因此强烈建议将其与ApplicationContext一起使用,可以以类似的方式部署到任何其他bean,并自动检测并应用。

请注意,所有bean工厂和应用程序上下文都会自动使用一些内置的属性编辑器,通过使用一些名为BeanWrapper的东西来处理属性转换。 BeanWrapper注册的标准属性编辑器在上一节中列出。此外,ApplicationContexts还会以适合特定应用程序上下文类型的方式覆盖或添加附加数量的编辑器来处理资源查找。

标准JavaBeans PropertyEditor实例用于将表示为字符串的属性值转换为属性的实际复杂类型。一个bean工厂后处理器的CustomEditorConfigurer可以用来方便地向ApplicationContext添加额外的PropertyEditor实例。

考虑一个用户类ExoticType,另一个类DependsOnExoticType需要ExoticType设置为一个属性:

package example;



public class ExoticType {



private String name;



public ExoticType(String name) {

this.name = name;

}

}



public class DependsOnExoticType {



private ExoticType type;



public void setType(ExoticType type) {

this.type = type;

}

}

当正确设置时,我们希望能够将type属性分配为字符串,PropertyEditor将在后台转换为实际的ExoticType实例:

<bean id="sample" class="example.DependsOnExoticType">

<property name="type" value="aNameForExoticType"/>

bean>

PropertyEditor实现可能类似于:

// converts string representation to ExoticType object

package example;



public class ExoticTypeEditor extends PropertyEditorSupport {



public void setAsText(String text) {

setValue(new ExoticType(text.toUpperCase()));

}

}

最后,我们使用CustomEditorConfigurerApplicationContext注册新的PropertyEditor,然后可以根据需要使用它:

<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">

<property name="customEditors">

<map>

<entry key="example.ExoticType" value="example.ExoticTypeEditor"/>

map>

property>

bean>

1.2. 使用PropertyEditorRegistrars

使用Spring容器注册属性编辑器的另一种机制是创建并使用PropertyEditorRegistrar。当您需要在几种不同的情况下使用同一组属性编辑器时,此接口特别有用:在每种情况下写入相应的注册器并重新使用。 PropertyEditorRegistrars与名为PropertyEditorRegistry的接口配合使用,该接口由Spring BeanWrapper(和DataBinder)实现。当与CustomEditorConfigurer(这里介绍)一起使用时,PropertyEditorRegistrars特别方便,它显示了一个名为setPropertyEditorRegistrars(..)的属性:以这种方式添加到CustomEditorConfigurer中的PropertyEditorRegistrars可以轻松地与DataBinder和Spring
MVC控制器共享。此外,它避免了在自定义编辑器上同步的需要:PropertyEditorRegistrar预期为每个创建bean创建新的PropertyEditor实例。

使用PropertyEditorRegistrar或许可以通过一个例子来说明。首先,你需要创建自己的PropertyEditorRegistrar实现:

package com.foo.editors.spring;



public final class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {



public void registerCustomEditors(PropertyEditorRegistry registry) {



// it is expected that new PropertyEditor instances are created

registry.registerCustomEditor(ExoticType.class, new ExoticTypeEditor());



// you could register as many custom property editors as are required here...

}

}

另请参见org.springframework.beans.support.ResourceEditorRegistrar一个示例PropertyEditorRegistrar实现。
注意如何在registerCustomEditors(..)方法的实现中创建每个属性编辑器的新实例。

接下来,我们配置一个CustomEditorConfigurer并将我们的CustomPropertyEditorRegistrar的一个实例注入它:

<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">

<property name="propertyEditorRegistrars">

<list>

<ref bean="customPropertyEditorRegistrar"/>

list>

property>

bean>



<bean id="customPropertyEditorRegistrar"

class="com.foo.editors.spring.CustomPropertyEditorRegistrar"/>


最后,与本章重点有所偏离,对于那些使用Spring MVC Web框架的用户,使用PropertyEditorRegistrars与数据绑定控件(如SimpleFormController)可以非常方便。
在下面的一个示例中,使用PropertyEditorRegistrar实现一个initBinder(..)方法:

public final class RegisterUserController extends SimpleFormController {



private final PropertyEditorRegistrar customPropertyEditorRegistrar;



public RegisterUserController(PropertyEditorRegistrar propertyEditorRegistrar) {

this.customPropertyEditorRegistrar = propertyEditorRegistrar;

}



protected void initBinder(HttpServletRequest request,

ServletRequestDataBinder binder)
throws Exception
{

this.customPropertyEditorRegistrar.registerCustomEditors(binder);

}



// other methods to do with registering a User

}

PropertyEditor注册的这种风格可以导致简洁的代码(initBinder(..)的实现只是一行!),并允许常见的PropertyEditor注册码封装在一个类中,然后根据需要在多个控制器之间共享。

转载请注明:CodingBlog » Part III. 核心技术-9. 验证,数据绑定与类型转换-9.4 Bean操作与BeanWrapper

喜欢 (0)or分享 (0)
发表我的评论
取消评论

*

表情