001: /*
002: * Copyright 2002-2007 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: * http://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:
017: package org.springframework.beans.factory.config;
018:
019: import java.beans.PropertyEditor;
020: import java.util.Iterator;
021: import java.util.Map;
022:
023: import org.springframework.beans.BeansException;
024: import org.springframework.beans.PropertyEditorRegistrar;
025: import org.springframework.beans.factory.BeanClassLoaderAware;
026: import org.springframework.core.Ordered;
027: import org.springframework.util.ClassUtils;
028:
029: /**
030: * {@link BeanFactoryPostProcessor} implementation that allows for convenient
031: * registration of custom {@link PropertyEditor property editors}.
032: *
033: * <p>As of Spring 2.0, the recommended usage is to use custom
034: * {@link PropertyEditorRegistrar} implementations that in turn register
035: * any desired editors on a given
036: * {@link org.springframework.beans.PropertyEditorRegistry registry}.
037: * Each PropertyEditorRegistrar can register any number of custom editors.
038: *
039: * <pre class="code">
040: * <bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
041: * <property name="propertyEditorRegistrars">
042: * <list>
043: * <bean class="mypackage.MyCustomDateEditorRegistrar"/>
044: * <bean class="mypackage.MyObjectEditorRegistrar"/>
045: * </list>
046: * </property>
047: * </bean></pre>
048: *
049: * <p>Alternative configuration example with custom editor instances,
050: * assuming inner beans for <code>PropertyEditor</code> instances:
051: *
052: * <pre class="code">
053: * <bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
054: * <property name="customEditors">
055: * <map>
056: * <entry key="java.util.Date">
057: * <bean class="mypackage.MyCustomDateEditor"/>
058: * </entry>
059: * <entry key="mypackage.MyObject">
060: * <bean id="myEditor" class="mypackage.MyObjectEditor">
061: * <property name="myParam"><value>myValue</value></property>
062: * </bean>
063: * </entry>
064: * </map>
065: * </property>
066: * </bean></pre>
067: *
068: * <p>Also supports "java.lang.String[]"-style array class names and primitive
069: * class names (e.g. "boolean"). Delegates to {@link ClassUtils} for actual
070: * class name resolution.
071: *
072: * <p><b>NOTE:</b> Custom property editors registered with this configurer do
073: * <i>not</i> apply to data binding. Custom editors for data binding need to
074: * be registered on the {@link org.springframework.validation.DataBinder}:
075: * Use a common base class or delegate to common PropertyEditorRegistrar
076: * implementations to reuse editor registration there.
077: *
078: * @author Juergen Hoeller
079: * @since 27.02.2004
080: * @see java.beans.PropertyEditor
081: * @see org.springframework.beans.PropertyEditorRegistrar
082: * @see ConfigurableBeanFactory#addPropertyEditorRegistrar
083: * @see ConfigurableBeanFactory#registerCustomEditor
084: * @see org.springframework.validation.DataBinder#registerCustomEditor
085: * @see org.springframework.web.servlet.mvc.BaseCommandController#setPropertyEditorRegistrars
086: * @see org.springframework.web.servlet.mvc.BaseCommandController#initBinder
087: */
088: public class CustomEditorConfigurer implements
089: BeanFactoryPostProcessor, BeanClassLoaderAware, Ordered {
090:
091: private int order = Ordered.LOWEST_PRECEDENCE; // default: same as non-Ordered
092:
093: private PropertyEditorRegistrar[] propertyEditorRegistrars;
094:
095: private Map customEditors;
096:
097: private ClassLoader beanClassLoader = ClassUtils
098: .getDefaultClassLoader();
099:
100: public void setOrder(int order) {
101: this .order = order;
102: }
103:
104: public int getOrder() {
105: return this .order;
106: }
107:
108: /**
109: * Specify the {@link PropertyEditorRegistrar PropertyEditorRegistrars}
110: * to apply to beans defined within the current application context.
111: * <p>This allows for sharing <code>PropertyEditorRegistrars</code> with
112: * {@link org.springframework.validation.DataBinder DataBinders}, etc.
113: * Furthermore, it avoids the need for synchronization on custom editors:
114: * A <code>PropertyEditorRegistrar</code> will always create fresh editor
115: * instances for each bean creation attempt.
116: * @see ConfigurableListableBeanFactory#addPropertyEditorRegistrar
117: */
118: public void setPropertyEditorRegistrars(
119: PropertyEditorRegistrar[] propertyEditorRegistrars) {
120: this .propertyEditorRegistrars = propertyEditorRegistrars;
121: }
122:
123: /**
124: * Specify the custom editors to register via a {@link Map}, using the
125: * class name of the required type as the key and the {@link PropertyEditor}
126: * instance as the value.
127: * @param customEditors said <code>Map</code> of editors (can be <code>null</code>)
128: * @see ConfigurableListableBeanFactory#registerCustomEditor
129: */
130: public void setCustomEditors(Map customEditors) {
131: this .customEditors = customEditors;
132: }
133:
134: public void setBeanClassLoader(ClassLoader beanClassLoader) {
135: this .beanClassLoader = beanClassLoader;
136: }
137:
138: public void postProcessBeanFactory(
139: ConfigurableListableBeanFactory beanFactory)
140: throws BeansException {
141: if (this .propertyEditorRegistrars != null) {
142: for (int i = 0; i < this .propertyEditorRegistrars.length; i++) {
143: beanFactory
144: .addPropertyEditorRegistrar(this .propertyEditorRegistrars[i]);
145: }
146: }
147:
148: if (this .customEditors != null) {
149: for (Iterator it = this .customEditors.entrySet().iterator(); it
150: .hasNext();) {
151: Map.Entry entry = (Map.Entry) it.next();
152: Object key = entry.getKey();
153: Class requiredType = null;
154: if (key instanceof Class) {
155: requiredType = (Class) key;
156: } else if (key instanceof String) {
157: String className = (String) key;
158: requiredType = ClassUtils.resolveClassName(
159: className, this .beanClassLoader);
160: } else {
161: throw new IllegalArgumentException(
162: "Invalid key ["
163: + key
164: + "] for custom editor: needs to be Class or String.");
165: }
166: Object value = entry.getValue();
167: if (!(value instanceof PropertyEditor)) {
168: throw new IllegalArgumentException("Mapped value ["
169: + value + "] for custom editor key [" + key
170: + "] is not of required type ["
171: + PropertyEditor.class.getName() + "]");
172: }
173: beanFactory.registerCustomEditor(requiredType,
174: (PropertyEditor) value);
175: }
176: }
177: }
178:
179: }
|