001/* 002 * Copyright 2002-2013 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.beans.factory.config; 018 019import java.beans.PropertyEditor; 020import java.util.Map; 021 022import org.apache.commons.logging.Log; 023import org.apache.commons.logging.LogFactory; 024 025import org.springframework.beans.BeansException; 026import org.springframework.beans.PropertyEditorRegistrar; 027import org.springframework.core.Ordered; 028import org.springframework.util.ClassUtils; 029 030/** 031 * {@link BeanFactoryPostProcessor} implementation that allows for convenient 032 * registration of custom {@link PropertyEditor property editors}. 033 * 034 * <p>In case you want to register {@link PropertyEditor} instances, 035 * the recommended usage as of Spring 2.0 is to use custom 036 * {@link PropertyEditorRegistrar} implementations that in turn register any 037 * desired editor instances on a given 038 * {@link org.springframework.beans.PropertyEditorRegistry registry}. Each 039 * PropertyEditorRegistrar can register any number of custom editors. 040 * 041 * <pre class="code"> 042 * <bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer"> 043 * <property name="propertyEditorRegistrars"> 044 * <list> 045 * <bean class="mypackage.MyCustomDateEditorRegistrar"/> 046 * <bean class="mypackage.MyObjectEditorRegistrar"/> 047 * </list> 048 * </property> 049 * </bean> 050 * </pre> 051 * 052 * <p> 053 * It's perfectly fine to register {@link PropertyEditor} <em>classes</em> via 054 * the {@code customEditors} property. Spring will create fresh instances of 055 * them for each editing attempt then: 056 * 057 * <pre class="code"> 058 * <bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer"> 059 * <property name="customEditors"> 060 * <map> 061 * <entry key="java.util.Date" value="mypackage.MyCustomDateEditor"/> 062 * <entry key="mypackage.MyObject" value="mypackage.MyObjectEditor"/> 063 * </map> 064 * </property> 065 * </bean> 066 * </pre> 067 * 068 * <p> 069 * Note, that you shouldn't register {@link PropertyEditor} bean instances via 070 * the {@code customEditors} property as {@link PropertyEditor}s are stateful 071 * and the instances will then have to be synchronized for every editing 072 * attempt. In case you need control over the instantiation process of 073 * {@link PropertyEditor}s, use a {@link PropertyEditorRegistrar} to register 074 * them. 075 * 076 * <p> 077 * Also supports "java.lang.String[]"-style array class names and primitive 078 * class names (e.g. "boolean"). Delegates to {@link ClassUtils} for actual 079 * class name resolution. 080 * 081 * <p><b>NOTE:</b> Custom property editors registered with this configurer do 082 * <i>not</i> apply to data binding. Custom editors for data binding need to 083 * be registered on the {@link org.springframework.validation.DataBinder}: 084 * Use a common base class or delegate to common PropertyEditorRegistrar 085 * implementations to reuse editor registration there. 086 * 087 * @author Juergen Hoeller 088 * @since 27.02.2004 089 * @see java.beans.PropertyEditor 090 * @see org.springframework.beans.PropertyEditorRegistrar 091 * @see ConfigurableBeanFactory#addPropertyEditorRegistrar 092 * @see ConfigurableBeanFactory#registerCustomEditor 093 * @see org.springframework.validation.DataBinder#registerCustomEditor 094 */ 095public class CustomEditorConfigurer implements BeanFactoryPostProcessor, Ordered { 096 097 protected final Log logger = LogFactory.getLog(getClass()); 098 099 private int order = Ordered.LOWEST_PRECEDENCE; // default: same as non-Ordered 100 101 private PropertyEditorRegistrar[] propertyEditorRegistrars; 102 103 private Map<Class<?>, Class<? extends PropertyEditor>> customEditors; 104 105 106 public void setOrder(int order) { 107 this.order = order; 108 } 109 110 @Override 111 public int getOrder() { 112 return this.order; 113 } 114 115 /** 116 * Specify the {@link PropertyEditorRegistrar PropertyEditorRegistrars} 117 * to apply to beans defined within the current application context. 118 * <p>This allows for sharing {@code PropertyEditorRegistrars} with 119 * {@link org.springframework.validation.DataBinder DataBinders}, etc. 120 * Furthermore, it avoids the need for synchronization on custom editors: 121 * A {@code PropertyEditorRegistrar} will always create fresh editor 122 * instances for each bean creation attempt. 123 * @see ConfigurableListableBeanFactory#addPropertyEditorRegistrar 124 */ 125 public void setPropertyEditorRegistrars(PropertyEditorRegistrar[] propertyEditorRegistrars) { 126 this.propertyEditorRegistrars = propertyEditorRegistrars; 127 } 128 129 /** 130 * Specify the custom editors to register via a {@link Map}, using the 131 * class name of the required type as the key and the class name of the 132 * associated {@link PropertyEditor} as value. 133 * @see ConfigurableListableBeanFactory#registerCustomEditor 134 */ 135 public void setCustomEditors(Map<Class<?>, Class<? extends PropertyEditor>> customEditors) { 136 this.customEditors = customEditors; 137 } 138 139 140 @Override 141 public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { 142 if (this.propertyEditorRegistrars != null) { 143 for (PropertyEditorRegistrar propertyEditorRegistrar : this.propertyEditorRegistrars) { 144 beanFactory.addPropertyEditorRegistrar(propertyEditorRegistrar); 145 } 146 } 147 if (this.customEditors != null) { 148 for (Map.Entry<Class<?>, Class<? extends PropertyEditor>> entry : this.customEditors.entrySet()) { 149 Class<?> requiredType = entry.getKey(); 150 Class<? extends PropertyEditor> propertyEditorClass = entry.getValue(); 151 beanFactory.registerCustomEditor(requiredType, propertyEditorClass); 152 } 153 } 154 } 155 156}