(重拾)Spring之属性编辑器

因为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的类型转换器,在属性编辑器不存在的时候,则会调用类型转换器,针对全局的。

你可能感兴趣的:(spring)