View Javadoc
1   /*
2    * Copyright 2002-2013 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.beans.factory.config;
18  
19  import java.beans.PropertyEditor;
20  import java.util.Map;
21  
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  
25  import org.springframework.beans.BeansException;
26  import org.springframework.beans.PropertyEditorRegistrar;
27  import org.springframework.core.Ordered;
28  import org.springframework.util.ClassUtils;
29  
30  /**
31   * {@link BeanFactoryPostProcessor} implementation that allows for convenient
32   * registration of custom {@link PropertyEditor property editors}.
33   *
34   * <p>In case you want to register {@link PropertyEditor} instances,
35   * the recommended usage as of Spring 2.0 is to use custom
36   * {@link PropertyEditorRegistrar} implementations that in turn register any
37   * desired editor instances on a given
38   * {@link org.springframework.beans.PropertyEditorRegistry registry}. Each
39   * PropertyEditorRegistrar can register any number of custom editors.
40   *
41   * <pre class="code">
42   * &lt;bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer"&gt;
43   *   &lt;property name="propertyEditorRegistrars"&gt;
44   *     &lt;list&gt;
45   *       &lt;bean class="mypackage.MyCustomDateEditorRegistrar"/&gt;
46   *       &lt;bean class="mypackage.MyObjectEditorRegistrar"/&gt;
47   *     &lt;/list&gt;
48   *   &lt;/property&gt;
49   * &lt;/bean&gt;
50   * </pre>
51   *
52   * <p>
53   * It's perfectly fine to register {@link PropertyEditor} <em>classes</em> via
54   * the {@code customEditors} property. Spring will create fresh instances of
55   * them for each editing attempt then:
56   *
57   * <pre class="code">
58   * &lt;bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer"&gt;
59   *   &lt;property name="customEditors"&gt;
60   *     &lt;map&gt;
61   *       &lt;entry key="java.util.Date" value="mypackage.MyCustomDateEditor"/&gt;
62   *       &lt;entry key="mypackage.MyObject" value="mypackage.MyObjectEditor"/&gt;
63   *     &lt;/map&gt;
64   *   &lt;/property&gt;
65   * &lt;/bean&gt;
66   * </pre>
67   *
68   * <p>
69   * Note, that you shouldn't register {@link PropertyEditor} bean instances via
70   * the {@code customEditors} property as {@link PropertyEditor}s are stateful
71   * and the instances will then have to be synchronized for every editing
72   * attempt. In case you need control over the instantiation process of
73   * {@link PropertyEditor}s, use a {@link PropertyEditorRegistrar} to register
74   * them.
75   *
76   * <p>
77   * Also supports "java.lang.String[]"-style array class names and primitive
78   * class names (e.g. "boolean"). Delegates to {@link ClassUtils} for actual
79   * class name resolution.
80   *
81   * <p><b>NOTE:</b> Custom property editors registered with this configurer do
82   * <i>not</i> apply to data binding. Custom editors for data binding need to
83   * be registered on the {@link org.springframework.validation.DataBinder}:
84   * Use a common base class or delegate to common PropertyEditorRegistrar
85   * implementations to reuse editor registration there.
86   *
87   * @author Juergen Hoeller
88   * @since 27.02.2004
89   * @see java.beans.PropertyEditor
90   * @see org.springframework.beans.PropertyEditorRegistrar
91   * @see ConfigurableBeanFactory#addPropertyEditorRegistrar
92   * @see ConfigurableBeanFactory#registerCustomEditor
93   * @see org.springframework.validation.DataBinder#registerCustomEditor
94   */
95  public class CustomEditorConfigurer implements BeanFactoryPostProcessor, Ordered {
96  
97  	protected final Log logger = LogFactory.getLog(getClass());
98  
99  	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 }