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 * <bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
43 * <property name="propertyEditorRegistrars">
44 * <list>
45 * <bean class="mypackage.MyCustomDateEditorRegistrar"/>
46 * <bean class="mypackage.MyObjectEditorRegistrar"/>
47 * </list>
48 * </property>
49 * </bean>
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 * <bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
59 * <property name="customEditors">
60 * <map>
61 * <entry key="java.util.Date" value="mypackage.MyCustomDateEditor"/>
62 * <entry key="mypackage.MyObject" value="mypackage.MyObjectEditor"/>
63 * </map>
64 * </property>
65 * </bean>
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 }