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 * &lt;bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer"&gt;
043 *   &lt;property name="propertyEditorRegistrars"&gt;
044 *     &lt;list&gt;
045 *       &lt;bean class="mypackage.MyCustomDateEditorRegistrar"/&gt;
046 *       &lt;bean class="mypackage.MyObjectEditorRegistrar"/&gt;
047 *     &lt;/list&gt;
048 *   &lt;/property&gt;
049 * &lt;/bean&gt;
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 * &lt;bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer"&gt;
059 *   &lt;property name="customEditors"&gt;
060 *     &lt;map&gt;
061 *       &lt;entry key="java.util.Date" value="mypackage.MyCustomDateEditor"/&gt;
062 *       &lt;entry key="mypackage.MyObject" value="mypackage.MyObjectEditor"/&gt;
063 *     &lt;/map&gt;
064 *   &lt;/property&gt;
065 * &lt;/bean&gt;
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}