因为XmlBeanFactory为BeanFactory的实例,用户需要手工调用registerCustomEditor(Class<?> requiredType, Class<? extends PropertyEditor> propertyEditorClass)方法注册自定义属性编辑器,Spring属性编辑器的注册方式不支持属性的注入,只能通过需要转化的类型和对应的属性编辑器类型,如此便不能往属性编辑器中传递参数了,如何初始化信息?
package org.springframework.beans.factory.xml.support;
import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class DatePropertyEditor extends PropertyEditorSupport {
private List<String> formats;
public void setFormats(List<String> formats) {
this.formats = formats;
}
public DatePropertyEditor(){
formats = new ArrayList<String>();
formats.add("yyyy-MM-dd");
formats.add("yyyy-MM-dd HH:mm:ss");
}
@Override
public void setAsText(String text) throws IllegalArgumentException {
try {
SimpleDateFormat sdf = null;
if(text.length() == 10){
sdf = new SimpleDateFormat((String)formats.get(0));
}else if(text.length() == 19){
sdf = new SimpleDateFormat((String)formats.get(1));
}
Date date = sdf.parse(text); // 获取时间信息
this.setValue(date);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
可以放在默认构造函数中,因为默认Spring会初始化属性编辑器,所以会默认调用.
在Spring初始化XmlBeanFactory的时候,初始化属性编辑器即可
beanFactory.registerCustomEditor(java.util.Date.class, DatePropertyEditor.class);
如此,当遇到对象类型为Date,注入的类型为String的时候,会调用这个方法.
但是使用上面的方法注册进去,参数是不会初始化的,因为其注册是类型.
所以请使用PropertyEditorRegistrars
PropertyEditorRegistrar registrar =new PropertyEditorRegistrar() {
public void registerCustomEditors(PropertyEditorRegistry registry) {
DatePropertyEditor dpe = new DatePropertyEditor();
List<String> formats = new ArrayList<String>();
formats.add("yyyy-MM-dd");
formats.add("yyyy-MM-dd HH:mm:ss");
dpe.setFormats(formats);
registry.registerCustomEditor(Date.class, dpe);
}
};
xct.beanFactory.addPropertyEditorRegistrar(registrar);
这种属性编辑器使用起来比较麻烦[XmlBeanFactory不支持xml注册的方式],而且也不够灵活[输入类型只支持String,而且也很难分享使用,比如我页面等地方的类型转换].
当然Spring对于属性编辑器还是支持的PropertyEditorRegistrySupport,比如BeanWrapperImpl,不过可以指定registerDefaultEditors.[true:引入默认的属性编辑器]
默认的属性编辑器如下:
private void createDefaultEditors() {
this.defaultEditors = new HashMap<Class<?>, PropertyEditor>(64);
// Simple editors, without parameterization capabilities.
// The JDK does not contain a default editor for any of these target types.
this.defaultEditors.put(Charset.class, new CharsetEditor());
this.defaultEditors.put(Class.class, new ClassEditor());
this.defaultEditors.put(Class[].class, new ClassArrayEditor());
this.defaultEditors.put(Currency.class, new CurrencyEditor());
this.defaultEditors.put(File.class, new FileEditor());
this.defaultEditors.put(InputStream.class, new InputStreamEditor());
this.defaultEditors.put(InputSource.class, new InputSourceEditor());
this.defaultEditors.put(Locale.class, new LocaleEditor());
this.defaultEditors.put(Pattern.class, new PatternEditor());
this.defaultEditors.put(Properties.class, new PropertiesEditor());
this.defaultEditors.put(Resource[].class, new ResourceArrayPropertyEditor());
this.defaultEditors.put(TimeZone.class, new TimeZoneEditor());
this.defaultEditors.put(URI.class, new URIEditor());
this.defaultEditors.put(URL.class, new URLEditor());
this.defaultEditors.put(UUID.class, new UUIDEditor());
// Default instances of collection editors.
// Can be overridden by registering custom instances of those as custom editors.
this.defaultEditors.put(Collection.class, new CustomCollectionEditor(Collection.class));
this.defaultEditors.put(Set.class, new CustomCollectionEditor(Set.class));
this.defaultEditors.put(SortedSet.class, new CustomCollectionEditor(SortedSet.class));
this.defaultEditors.put(List.class, new CustomCollectionEditor(List.class));
this.defaultEditors.put(SortedMap.class, new CustomMapEditor(SortedMap.class));
// Default editors for primitive arrays.
this.defaultEditors.put(byte[].class, new ByteArrayPropertyEditor());
this.defaultEditors.put(char[].class, new CharArrayPropertyEditor());
// The JDK does not contain a default editor for char!
this.defaultEditors.put(char.class, new CharacterEditor(false));
this.defaultEditors.put(Character.class, new CharacterEditor(true));
// Spring's CustomBooleanEditor accepts more flag values than the JDK's default editor.
this.defaultEditors.put(boolean.class, new CustomBooleanEditor(false));
this.defaultEditors.put(Boolean.class, new CustomBooleanEditor(true));
// The JDK does not contain default editors for number wrapper types!
// Override JDK primitive number editors with our own CustomNumberEditor.
this.defaultEditors.put(byte.class, new CustomNumberEditor(Byte.class, false));
this.defaultEditors.put(Byte.class, new CustomNumberEditor(Byte.class, true));
this.defaultEditors.put(short.class, new CustomNumberEditor(Short.class, false));
this.defaultEditors.put(Short.class, new CustomNumberEditor(Short.class, true));
this.defaultEditors.put(int.class, new CustomNumberEditor(Integer.class, false));
this.defaultEditors.put(Integer.class, new CustomNumberEditor(Integer.class, true));
this.defaultEditors.put(long.class, new CustomNumberEditor(Long.class, false));
this.defaultEditors.put(Long.class, new CustomNumberEditor(Long.class, true));
this.defaultEditors.put(float.class, new CustomNumberEditor(Float.class, false));
this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true));
this.defaultEditors.put(double.class, new CustomNumberEditor(Double.class, false));
this.defaultEditors.put(Double.class, new CustomNumberEditor(Double.class, true));
this.defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true));
this.defaultEditors.put(BigInteger.class, new CustomNumberEditor(BigInteger.class, true));
// Only register config value editors if explicitly requested.
if (this.configValueEditorsActive) {
StringArrayPropertyEditor sae = new StringArrayPropertyEditor();
this.defaultEditors.put(String[].class, sae);
this.defaultEditors.put(short[].class, sae);
this.defaultEditors.put(int[].class, sae);
this.defaultEditors.put(long[].class, sae);
}
}
属性编辑器基本上支持基本类型(int,long,float,double等).
这是以前Spring的使用方法属性编辑器,Spring3.0之后的版本[我是参阅spring3.0源码].
都是使用Converter,为了兼容以前的版本,属性编辑器也支持使用,spring的逻辑是先属性编辑器,如果没有找到,则会检测类型转换器,类型转化器针对的是全局的。只会注册一次,而属性编辑器会在每一个BeanWrapper中注册.
优先级如下:
if (editor == null && conversionService != null && convertedValue != null && typeDescriptor != null) {
TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
TypeDescriptor targetTypeDesc = typeDescriptor;
if (conversionService.canConvert(sourceTypeDesc, targetTypeDesc)) {
try {
return (T) conversionService.convert(convertedValue, sourceTypeDesc, targetTypeDesc);
}
catch (ConversionFailedException ex) {
// fallback to default conversion logic below
firstAttemptEx = ex;
}
}
}
// Value not of required type?
if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) {
if (requiredType != null && Collection.class.isAssignableFrom(requiredType) && convertedValue instanceof String) {
TypeDescriptor elementType = typeDescriptor.getElementTypeDescriptor();
if (elementType != null && Enum.class.isAssignableFrom(elementType.getType())) {
convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
}
}
if (editor == null) {
editor = findDefaultEditor(requiredType, typeDescriptor);
}
convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor);
}
如果编辑器中没有找到匹配的类型,才会执行convert
如此使用ApplicationContext,则不需要这么麻烦了,只需要xml配置即可
<bean id="customEditorConfigurer"
class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date">
<bean class="org.springframework.beans.factory.xml.support.DatePropertyEditor">
设置时间格式
<property name="formats">
<list>
<value>yyyy-MM-dd</value>
<value>yyyy-MM-dd HH:mm:ss</value>
</list>
</property>
</bean>
</entry>
</map>
</property>
<property name="propertyEditorRegistrars">
<set>
<ref bean="propertyEditorRegistrar" />
</set>
</property>
</bean>
<bean id="propertyEditorRegistrar"
class="org.springframework.context.DDPropertyRegister">
</bean>
我这里定义了两种方式,可以通过Registar注册,也可以直接通过customEditors注册自定义的属性编辑器,但是我不推荐这么做,毕竟属性编辑器会在每一个spring bean的初始化。
所以在spring3.0出了一个叫convert的类型转换器,在属性编辑器不存在的时候,则会调用类型转换器,针对全局的。