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