001/*
002 * Copyright 2002-2018 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.lang.Nullable;
029import org.springframework.util.ClassUtils;
030
031/**
032 * {@link BeanFactoryPostProcessor} implementation that allows for convenient
033 * registration of custom {@link PropertyEditor property editors}.
034 *
035 * <p>In case you want to register {@link PropertyEditor} instances,
036 * the recommended usage as of Spring 2.0 is to use custom
037 * {@link PropertyEditorRegistrar} implementations that in turn register any
038 * desired editor instances on a given
039 * {@link org.springframework.beans.PropertyEditorRegistry registry}. Each
040 * PropertyEditorRegistrar can register any number of custom editors.
041 *
042 * <pre class="code">
043 * &lt;bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer"&gt;
044 *   &lt;property name="propertyEditorRegistrars"&gt;
045 *     &lt;list&gt;
046 *       &lt;bean class="mypackage.MyCustomDateEditorRegistrar"/&gt;
047 *       &lt;bean class="mypackage.MyObjectEditorRegistrar"/&gt;
048 *     &lt;/list&gt;
049 *   &lt;/property&gt;
050 * &lt;/bean&gt;
051 * </pre>
052 *
053 * <p>
054 * It's perfectly fine to register {@link PropertyEditor} <em>classes</em> via
055 * the {@code customEditors} property. Spring will create fresh instances of
056 * them for each editing attempt then:
057 *
058 * <pre class="code">
059 * &lt;bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer"&gt;
060 *   &lt;property name="customEditors"&gt;
061 *     &lt;map&gt;
062 *       &lt;entry key="java.util.Date" value="mypackage.MyCustomDateEditor"/&gt;
063 *       &lt;entry key="mypackage.MyObject" value="mypackage.MyObjectEditor"/&gt;
064 *     &lt;/map&gt;
065 *   &lt;/property&gt;
066 * &lt;/bean&gt;
067 * </pre>
068 *
069 * <p>
070 * Note, that you shouldn't register {@link PropertyEditor} bean instances via
071 * the {@code customEditors} property as {@link PropertyEditor PropertyEditors} are stateful
072 * and the instances will then have to be synchronized for every editing
073 * attempt. In case you need control over the instantiation process of
074 * {@link PropertyEditor PropertyEditors}, use a {@link PropertyEditorRegistrar} to register
075 * them.
076 *
077 * <p>
078 * Also supports "java.lang.String[]"-style array class names and primitive
079 * class names (e.g. "boolean"). Delegates to {@link ClassUtils} for actual
080 * class name resolution.
081 *
082 * <p><b>NOTE:</b> Custom property editors registered with this configurer do
083 * <i>not</i> apply to data binding. Custom editors for data binding need to
084 * be registered on the {@link org.springframework.validation.DataBinder}:
085 * Use a common base class or delegate to common PropertyEditorRegistrar
086 * implementations to reuse editor registration there.
087 *
088 * @author Juergen Hoeller
089 * @since 27.02.2004
090 * @see java.beans.PropertyEditor
091 * @see org.springframework.beans.PropertyEditorRegistrar
092 * @see ConfigurableBeanFactory#addPropertyEditorRegistrar
093 * @see ConfigurableBeanFactory#registerCustomEditor
094 * @see org.springframework.validation.DataBinder#registerCustomEditor
095 */
096public class CustomEditorConfigurer implements BeanFactoryPostProcessor, Ordered {
097
098        protected final Log logger = LogFactory.getLog(getClass());
099
100        private int order = Ordered.LOWEST_PRECEDENCE;  // default: same as non-Ordered
101
102        @Nullable
103        private PropertyEditorRegistrar[] propertyEditorRegistrars;
104
105        @Nullable
106        private Map<Class<?>, Class<? extends PropertyEditor>> customEditors;
107
108
109        public void setOrder(int order) {
110                this.order = order;
111        }
112
113        @Override
114        public int getOrder() {
115                return this.order;
116        }
117
118        /**
119         * Specify the {@link PropertyEditorRegistrar PropertyEditorRegistrars}
120         * to apply to beans defined within the current application context.
121         * <p>This allows for sharing {@code PropertyEditorRegistrars} with
122         * {@link org.springframework.validation.DataBinder DataBinders}, etc.
123         * Furthermore, it avoids the need for synchronization on custom editors:
124         * A {@code PropertyEditorRegistrar} will always create fresh editor
125         * instances for each bean creation attempt.
126         * @see ConfigurableListableBeanFactory#addPropertyEditorRegistrar
127         */
128        public void setPropertyEditorRegistrars(PropertyEditorRegistrar[] propertyEditorRegistrars) {
129                this.propertyEditorRegistrars = propertyEditorRegistrars;
130        }
131
132        /**
133         * Specify the custom editors to register via a {@link Map}, using the
134         * class name of the required type as the key and the class name of the
135         * associated {@link PropertyEditor} as value.
136         * @see ConfigurableListableBeanFactory#registerCustomEditor
137         */
138        public void setCustomEditors(Map<Class<?>, Class<? extends PropertyEditor>> customEditors) {
139                this.customEditors = customEditors;
140        }
141
142
143        @Override
144        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
145                if (this.propertyEditorRegistrars != null) {
146                        for (PropertyEditorRegistrar propertyEditorRegistrar : this.propertyEditorRegistrars) {
147                                beanFactory.addPropertyEditorRegistrar(propertyEditorRegistrar);
148                        }
149                }
150                if (this.customEditors != null) {
151                        this.customEditors.forEach(beanFactory::registerCustomEditor);
152                }
153        }
154
155}