SWF-1234 Integration with Spring 3 type conversion
This commit is contained in:
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.binding.convert;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A service interface for retrieving type conversion executors. The returned command objects are thread-safe and may be
|
||||
@@ -74,15 +73,6 @@ public interface ConversionService {
|
||||
public ConversionExecutor getConversionExecutor(String id, Class sourceClass, Class targetClass)
|
||||
throws ConversionExecutorNotFoundException;
|
||||
|
||||
/**
|
||||
* Return all conversion executors capable of converting <i>from</i> the provided <code>sourceClass</code>. For
|
||||
* example, <code>getConversionExecutor(String.class)</code> would return all converters that convert from String to
|
||||
* some other Object. Mainly useful for adapting a set of converters to some other environment.
|
||||
* @param sourceClass the source class converting from
|
||||
* @return the conversion executors that can convert from that source class
|
||||
*/
|
||||
public Set getConversionExecutors(Class sourceClass);
|
||||
|
||||
/**
|
||||
* Lookup a class by its well-known alias. For example, <code>long</code> for <code>java.lang.Long</code>
|
||||
* @param alias the class alias
|
||||
@@ -90,4 +80,11 @@ public interface ConversionService {
|
||||
*/
|
||||
public Class getClassForAlias(String alias);
|
||||
|
||||
/**
|
||||
* Return the underlying Spring ConversionService.
|
||||
*
|
||||
* @return the conversion service
|
||||
*/
|
||||
public org.springframework.core.convert.ConversionService getDelegateConversionService();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2004-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.binding.convert.converters;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A Spring Binding Converter that delegates to a Spring {@link ConversionService} to do the actual type conversion.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class SpringConvertingConverterAdapter implements Converter {
|
||||
|
||||
/**
|
||||
* The source value type to convert from.
|
||||
*/
|
||||
private final Class sourceClass;
|
||||
|
||||
/**
|
||||
* The target value type to convert to.
|
||||
*/
|
||||
private final Class targetClass;
|
||||
|
||||
/**
|
||||
* The ConversionService that will perform the conversion.
|
||||
*/
|
||||
private ConversionService conversionService;
|
||||
|
||||
public SpringConvertingConverterAdapter(Class sourceClass, Class targetClass, ConversionService conversionService) {
|
||||
Assert.notNull(sourceClass, "The source class to convert from is required.");
|
||||
Assert.notNull(targetClass, "The target class to convert to is required.");
|
||||
Assert.notNull(conversionService, "A Spring ConversionService is required.");
|
||||
this.sourceClass = sourceClass;
|
||||
this.targetClass = targetClass;
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
public Object convertSourceToTargetClass(Object source, Class targetClass) throws Exception {
|
||||
return conversionService.convert(source, targetClass);
|
||||
}
|
||||
|
||||
public Class getSourceClass() {
|
||||
return sourceClass;
|
||||
}
|
||||
|
||||
public Class getTargetClass() {
|
||||
return targetClass;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,25 +20,8 @@ import java.math.BigInteger;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.springframework.binding.convert.converters.CollectionToCollection;
|
||||
import org.springframework.binding.convert.converters.NumberToNumber;
|
||||
import org.springframework.binding.convert.converters.ObjectToCollection;
|
||||
import org.springframework.binding.convert.converters.StringToBigDecimal;
|
||||
import org.springframework.binding.convert.converters.StringToBigInteger;
|
||||
import org.springframework.binding.convert.converters.StringToBoolean;
|
||||
import org.springframework.binding.convert.converters.StringToByte;
|
||||
import org.springframework.binding.convert.converters.StringToCharacter;
|
||||
import org.springframework.binding.convert.converters.StringToDate;
|
||||
import org.springframework.binding.convert.converters.StringToDouble;
|
||||
import org.springframework.binding.convert.converters.StringToEnum;
|
||||
import org.springframework.binding.convert.converters.StringToFloat;
|
||||
import org.springframework.binding.convert.converters.StringToInteger;
|
||||
import org.springframework.binding.convert.converters.StringToLabeledEnum;
|
||||
import org.springframework.binding.convert.converters.StringToLocale;
|
||||
import org.springframework.binding.convert.converters.StringToLong;
|
||||
import org.springframework.binding.convert.converters.StringToShort;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.enums.LabeledEnum;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Default, local implementation of a conversion service. Will automatically register <i>from string</i> converters for
|
||||
@@ -56,29 +39,26 @@ public class DefaultConversionService extends GenericConversionService {
|
||||
addDefaultAliases();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new default conversion service with an instance of a Spring ConversionService.
|
||||
*
|
||||
* @param delegateConversionService the Spring conversion service
|
||||
*/
|
||||
public DefaultConversionService(ConversionService delegateConversionService) {
|
||||
super(delegateConversionService);
|
||||
addDefaultConverters();
|
||||
addDefaultAliases();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all default converters to the conversion service.
|
||||
*
|
||||
* Note: Staring with Spring Web Flow 2.1, this method does not register any Spring Binding converters. All type
|
||||
* conversion is driven through Spring's type conversion instead.
|
||||
*
|
||||
* @see GenericConversionService
|
||||
*/
|
||||
protected void addDefaultConverters() {
|
||||
addConverter(new StringToByte());
|
||||
addConverter(new StringToBoolean());
|
||||
addConverter(new StringToCharacter());
|
||||
addConverter(new StringToShort());
|
||||
addConverter(new StringToInteger());
|
||||
addConverter(new StringToLong());
|
||||
addConverter(new StringToFloat());
|
||||
addConverter(new StringToDouble());
|
||||
addConverter(new StringToBigInteger());
|
||||
addConverter(new StringToBigDecimal());
|
||||
addConverter(new StringToLocale());
|
||||
addConverter(new StringToDate());
|
||||
addConverter(new StringToLabeledEnum());
|
||||
addConverter(new NumberToNumber());
|
||||
addConverter(new ObjectToCollection(this));
|
||||
addConverter(new CollectionToCollection(this));
|
||||
if (ClassUtils.isPresent("java.lang.Enum", this.getClass().getClassLoader())) {
|
||||
addConverter(new StringToEnum());
|
||||
}
|
||||
}
|
||||
|
||||
protected void addDefaultAliases() {
|
||||
|
||||
@@ -17,13 +17,8 @@ package org.springframework.binding.convert.service;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.binding.convert.ConversionException;
|
||||
import org.springframework.binding.convert.ConversionExecutor;
|
||||
@@ -36,7 +31,10 @@ import org.springframework.binding.convert.converters.Converter;
|
||||
import org.springframework.binding.convert.converters.ObjectToArray;
|
||||
import org.springframework.binding.convert.converters.ObjectToCollection;
|
||||
import org.springframework.binding.convert.converters.ReverseConverter;
|
||||
import org.springframework.binding.convert.converters.SpringConvertingConverterAdapter;
|
||||
import org.springframework.binding.convert.converters.TwoWayConverter;
|
||||
import org.springframework.core.convert.converter.ConverterRegistry;
|
||||
import org.springframework.format.support.FormattingConversionServiceFactoryBean;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -47,11 +45,9 @@ import org.springframework.util.Assert;
|
||||
public class GenericConversionService implements ConversionService {
|
||||
|
||||
/**
|
||||
* An indexed map of converters. Each entry key is a source class that can be converted from, and each entry value
|
||||
* is a map of target classes that can be converted to, ultimately mapping to a specific converter that can perform
|
||||
* the source->target conversion.
|
||||
* Spring ConversionService where existing custom {@link Converter} types will be registered through an adapter.
|
||||
*/
|
||||
private final Map sourceClassConverters = new HashMap();
|
||||
private org.springframework.core.convert.ConversionService delegate;
|
||||
|
||||
/**
|
||||
* A map of custom converters. Custom converters are assigned a unique identifier that can be used to lookup the
|
||||
@@ -69,6 +65,24 @@ public class GenericConversionService implements ConversionService {
|
||||
*/
|
||||
private ConversionService parent;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public GenericConversionService() {
|
||||
FormattingConversionServiceFactoryBean factoryBean = new FormattingConversionServiceFactoryBean();
|
||||
factoryBean.afterPropertiesSet();
|
||||
this.delegate = factoryBean.getObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor accepting a specific instance of a Spring ConversionService to delegate to.
|
||||
* @param delegateConversionService the conversion service
|
||||
*/
|
||||
public GenericConversionService(org.springframework.core.convert.ConversionService delegateConversionService) {
|
||||
Assert.notNull(delegateConversionService);
|
||||
this.delegate = delegateConversionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parent of this conversion service. Could be null.
|
||||
*/
|
||||
@@ -84,24 +98,42 @@ public class GenericConversionService implements ConversionService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add given converter to this conversion service.
|
||||
* @return the Spring ConverterRegistry
|
||||
*/
|
||||
public org.springframework.core.convert.ConversionService getDelegateConversionService() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the given converter with the underlying Spring ConversionService with the help of an adapter. The
|
||||
* adapter allows an existing Spring Binding converter to be invoked within Spring's type conversion system.
|
||||
*
|
||||
* @param converter the converter
|
||||
*
|
||||
* @see ConverterRegistry
|
||||
* @see org.springframework.core.convert.ConversionService
|
||||
* @see SpringBindingConverterAdapter
|
||||
*/
|
||||
public void addConverter(Converter converter) {
|
||||
Class sourceClass = converter.getSourceClass();
|
||||
Class targetClass = converter.getTargetClass();
|
||||
Map sourceMap = getSourceMap(sourceClass);
|
||||
sourceMap.put(targetClass, converter);
|
||||
((ConverterRegistry) delegate).addConverter(new SpringBindingConverterAdapter(converter));
|
||||
if (converter instanceof TwoWayConverter) {
|
||||
sourceMap = getSourceMap(targetClass);
|
||||
sourceMap.put(sourceClass, new ReverseConverter((TwoWayConverter) converter));
|
||||
TwoWayConverter twoWayConverter = (TwoWayConverter) converter;
|
||||
((ConverterRegistry) delegate).addConverter(new SpringBindingConverterAdapter(new ReverseConverter(
|
||||
twoWayConverter)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add given custom converter to this conversion service.
|
||||
*
|
||||
* Note: Converters registered through this method will not be involve the Spring type conversion system, which is
|
||||
* now used the default type conversion mechanism. Spring's type conversion does not support named converters. This
|
||||
* method is provided for backwards compatibility.
|
||||
*
|
||||
* @param id the id of the custom converter instance
|
||||
* @param converter the converter
|
||||
*
|
||||
* @deprecated use {@link #addConverter(Converter)} instead
|
||||
*/
|
||||
public void addConverter(String id, Converter converter) {
|
||||
customConverters.put(id, converter);
|
||||
@@ -114,15 +146,6 @@ public class GenericConversionService implements ConversionService {
|
||||
aliasMap.put(alias, targetType);
|
||||
}
|
||||
|
||||
private Map getSourceMap(Class sourceClass) {
|
||||
Map sourceMap = (Map) sourceClassConverters.get(sourceClass);
|
||||
if (sourceMap == null) {
|
||||
sourceMap = new HashMap();
|
||||
sourceClassConverters.put(sourceClass, sourceMap);
|
||||
}
|
||||
return sourceMap;
|
||||
}
|
||||
|
||||
public ConversionExecutor getConversionExecutor(Class sourceClass, Class targetClass)
|
||||
throws ConversionExecutorNotFoundException {
|
||||
Assert.notNull(sourceClass, "The source class to convert from is required");
|
||||
@@ -132,40 +155,15 @@ public class GenericConversionService implements ConversionService {
|
||||
if (targetClass.isAssignableFrom(sourceClass)) {
|
||||
return new StaticConversionExecutor(sourceClass, targetClass, new NoOpConverter(sourceClass, targetClass));
|
||||
}
|
||||
// special handling for arrays since they are not indexable classes
|
||||
if (sourceClass.isArray()) {
|
||||
if (targetClass.isArray()) {
|
||||
return new StaticConversionExecutor(sourceClass, targetClass, new ArrayToArray(this));
|
||||
} else if (Collection.class.isAssignableFrom(targetClass)) {
|
||||
if (!targetClass.isInterface() && Modifier.isAbstract(targetClass.getModifiers())) {
|
||||
throw new IllegalArgumentException("Conversion target class [" + targetClass.getName()
|
||||
+ "] is invalid; cannot convert to abstract collection types--"
|
||||
+ "request an interface or concrete implementation instead");
|
||||
}
|
||||
return new StaticConversionExecutor(sourceClass, targetClass, new ArrayToCollection(this));
|
||||
}
|
||||
}
|
||||
if (targetClass.isArray()) {
|
||||
if (Collection.class.isAssignableFrom(sourceClass)) {
|
||||
Converter collectionToArray = new ReverseConverter(new ArrayToCollection(this));
|
||||
return new StaticConversionExecutor(sourceClass, targetClass, collectionToArray);
|
||||
} else {
|
||||
return new StaticConversionExecutor(sourceClass, targetClass, new ObjectToArray(this));
|
||||
}
|
||||
}
|
||||
Converter converter = findRegisteredConverter(sourceClass, targetClass);
|
||||
if (converter != null) {
|
||||
// we found a converter
|
||||
return new StaticConversionExecutor(sourceClass, targetClass, converter);
|
||||
if (delegate.canConvert(sourceClass, targetClass)) {
|
||||
return new StaticConversionExecutor(sourceClass, targetClass, new SpringConvertingConverterAdapter(
|
||||
sourceClass, targetClass, delegate));
|
||||
} else if (parent != null) {
|
||||
return parent.getConversionExecutor(sourceClass, targetClass);
|
||||
} else {
|
||||
if (parent != null) {
|
||||
// try the parent
|
||||
return parent.getConversionExecutor(sourceClass, targetClass);
|
||||
} else {
|
||||
throw new ConversionExecutorNotFoundException(sourceClass, targetClass,
|
||||
"No ConversionExecutor found for converting from sourceClass [" + sourceClass.getName()
|
||||
+ "] to target class [" + targetClass.getName() + "]");
|
||||
}
|
||||
throw new ConversionExecutorNotFoundException(sourceClass, targetClass,
|
||||
"No ConversionExecutor found for converting from sourceClass [" + sourceClass.getName()
|
||||
+ "] to target class [" + targetClass.getName() + "]");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,46 +339,6 @@ public class GenericConversionService implements ConversionService {
|
||||
}
|
||||
}
|
||||
|
||||
private Converter findRegisteredConverter(Class sourceClass, Class targetClass) {
|
||||
if (sourceClass.isInterface()) {
|
||||
LinkedList classQueue = new LinkedList();
|
||||
classQueue.addFirst(sourceClass);
|
||||
while (!classQueue.isEmpty()) {
|
||||
Class currentClass = (Class) classQueue.removeLast();
|
||||
Map sourceTargetConverters = findConvertersForSource(currentClass);
|
||||
Converter converter = findTargetConverter(sourceTargetConverters, targetClass);
|
||||
if (converter != null) {
|
||||
return converter;
|
||||
}
|
||||
Class[] interfaces = currentClass.getInterfaces();
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
classQueue.addFirst(interfaces[i]);
|
||||
}
|
||||
}
|
||||
Map objectConverters = findConvertersForSource(Object.class);
|
||||
return findTargetConverter(objectConverters, targetClass);
|
||||
} else {
|
||||
LinkedList classQueue = new LinkedList();
|
||||
classQueue.addFirst(sourceClass);
|
||||
while (!classQueue.isEmpty()) {
|
||||
Class currentClass = (Class) classQueue.removeLast();
|
||||
Map sourceTargetConverters = findConvertersForSource(currentClass);
|
||||
Converter converter = findTargetConverter(sourceTargetConverters, targetClass);
|
||||
if (converter != null) {
|
||||
return converter;
|
||||
}
|
||||
if (currentClass.getSuperclass() != null) {
|
||||
classQueue.addFirst(currentClass.getSuperclass());
|
||||
}
|
||||
Class[] interfaces = currentClass.getInterfaces();
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
classQueue.addFirst(interfaces[i]);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Object executeConversion(Object source, Class targetClass) throws ConversionException {
|
||||
if (source != null) {
|
||||
ConversionExecutor conversionExecutor = getConversionExecutor(source.getClass(), targetClass);
|
||||
@@ -412,97 +370,8 @@ public class GenericConversionService implements ConversionService {
|
||||
}
|
||||
}
|
||||
|
||||
// subclassing support
|
||||
|
||||
public Set getConversionExecutors(Class sourceClass) {
|
||||
Set parentExecutors;
|
||||
if (parent != null) {
|
||||
parentExecutors = parent.getConversionExecutors(sourceClass);
|
||||
} else {
|
||||
parentExecutors = Collections.EMPTY_SET;
|
||||
}
|
||||
Map sourceMap = getSourceMap(sourceClass);
|
||||
if (parentExecutors.isEmpty() && sourceMap.isEmpty()) {
|
||||
return Collections.EMPTY_SET;
|
||||
}
|
||||
Set entries = sourceMap.entrySet();
|
||||
Set conversionExecutors = new HashSet(entries.size() + parentExecutors.size());
|
||||
for (Iterator it = entries.iterator(); it.hasNext();) {
|
||||
Map.Entry entry = (Map.Entry) it.next();
|
||||
Class targetClass = (Class) entry.getKey();
|
||||
Converter converter = (Converter) entry.getValue();
|
||||
conversionExecutors.add(new StaticConversionExecutor(sourceClass, targetClass, converter));
|
||||
}
|
||||
conversionExecutors.addAll(parentExecutors);
|
||||
return conversionExecutors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an indexed map of converters. Each entry key is a source class that can be converted from, and each entry
|
||||
* value is a map of target classes that can be convertered to, ultimately mapping to a specific converter that can
|
||||
* perform the source->target conversion.
|
||||
*/
|
||||
protected Map getSourceClassConverters() {
|
||||
return sourceClassConverters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a registered converter object
|
||||
* @param sourceClass the source class
|
||||
* @param targetClass the target class
|
||||
*/
|
||||
protected Converter getConverter(Class sourceClass, Class targetClass) {
|
||||
Map sourceTargetConverters = findConvertersForSource(sourceClass);
|
||||
return findTargetConverter(sourceTargetConverters, targetClass);
|
||||
}
|
||||
|
||||
// internal helpers
|
||||
|
||||
private Map findConvertersForSource(Class sourceClass) {
|
||||
Map sourceConverters = (Map) sourceClassConverters.get(sourceClass);
|
||||
return sourceConverters != null ? sourceConverters : Collections.EMPTY_MAP;
|
||||
}
|
||||
|
||||
private Converter findTargetConverter(Map sourceTargetConverters, Class targetClass) {
|
||||
if (sourceTargetConverters.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (targetClass.isInterface()) {
|
||||
LinkedList classQueue = new LinkedList();
|
||||
classQueue.addFirst(targetClass);
|
||||
while (!classQueue.isEmpty()) {
|
||||
Class currentClass = (Class) classQueue.removeLast();
|
||||
Converter converter = (Converter) sourceTargetConverters.get(currentClass);
|
||||
if (converter != null) {
|
||||
return converter;
|
||||
}
|
||||
Class[] interfaces = currentClass.getInterfaces();
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
classQueue.addFirst(interfaces[i]);
|
||||
}
|
||||
}
|
||||
return (Converter) sourceTargetConverters.get(Object.class);
|
||||
} else {
|
||||
LinkedList classQueue = new LinkedList();
|
||||
classQueue.addFirst(targetClass);
|
||||
while (!classQueue.isEmpty()) {
|
||||
Class currentClass = (Class) classQueue.removeLast();
|
||||
Converter converter = (Converter) sourceTargetConverters.get(currentClass);
|
||||
if (converter != null) {
|
||||
return converter;
|
||||
}
|
||||
if (currentClass.getSuperclass() != null) {
|
||||
classQueue.addFirst(currentClass.getSuperclass());
|
||||
}
|
||||
Class[] interfaces = currentClass.getInterfaces();
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
classQueue.addFirst(interfaces[i]);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Class convertToWrapperClassIfNecessary(Class targetType) {
|
||||
if (targetType.isPrimitive()) {
|
||||
if (targetType.equals(int.class)) {
|
||||
@@ -528,4 +397,5 @@ public class GenericConversionService implements ConversionService {
|
||||
return targetType;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2004-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.binding.convert.service;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.binding.convert.converters.Converter;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A Spring Converter that makes it possible for a Spring Binding Converter to be registered with a Spring
|
||||
* {@link ConversionService}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class SpringBindingConverterAdapter implements GenericConverter {
|
||||
|
||||
private Converter converter;
|
||||
|
||||
public SpringBindingConverterAdapter(Converter converter) {
|
||||
Assert.notNull(converter, "A Spring Binding converter is required.");
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
try {
|
||||
return converter.convertSourceToTargetClass(source, targetType.getObjectType());
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Set getConvertibleTypes() {
|
||||
return Collections.singleton(new ConvertiblePair(converter.getSourceClass(), converter.getTargetClass()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,18 +15,11 @@
|
||||
*/
|
||||
package org.springframework.binding.expression.beanwrapper;
|
||||
|
||||
import java.beans.PropertyEditorSupport;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.NotReadablePropertyException;
|
||||
import org.springframework.beans.NotWritablePropertyException;
|
||||
import org.springframework.beans.PropertyEditorRegistry;
|
||||
import org.springframework.beans.TypeMismatchException;
|
||||
import org.springframework.binding.convert.ConversionException;
|
||||
import org.springframework.binding.convert.ConversionExecutor;
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
import org.springframework.binding.expression.EvaluationException;
|
||||
import org.springframework.binding.expression.Expression;
|
||||
@@ -95,7 +88,7 @@ public class BeanWrapperExpression implements Expression {
|
||||
public void setValue(Object context, Object value) {
|
||||
try {
|
||||
BeanWrapperImpl beanWrapper = new BeanWrapperImpl(context);
|
||||
registerConvertersAsPropertyEditors(beanWrapper);
|
||||
beanWrapper.setConversionService(conversionService.getDelegateConversionService());
|
||||
beanWrapper.setPropertyValue(expression, value);
|
||||
} catch (NotWritablePropertyException e) {
|
||||
throw new PropertyNotFoundException(context.getClass(), expression, e);
|
||||
@@ -129,39 +122,4 @@ public class BeanWrapperExpression implements Expression {
|
||||
return expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts the String->Object converters to PropertyEditors for use during a setValue attempt. Excludes any
|
||||
* String->Enum converter, since BeanWrapper has built in support for Enum conversion.
|
||||
* @param registry the registry to register converter-to-editor adapters with
|
||||
*/
|
||||
protected void registerConvertersAsPropertyEditors(PropertyEditorRegistry registry) {
|
||||
Set converters = conversionService.getConversionExecutors(String.class);
|
||||
for (Iterator it = converters.iterator(); it.hasNext();) {
|
||||
ConversionExecutor converter = (ConversionExecutor) it.next();
|
||||
if (!converter.getTargetClass().getName().equals("java.lang.Enum")) {
|
||||
registry.registerCustomEditor(converter.getTargetClass(), new PropertyEditorConverter(converter));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class PropertyEditorConverter extends PropertyEditorSupport {
|
||||
|
||||
private ConversionExecutor converter;
|
||||
|
||||
public PropertyEditorConverter(ConversionExecutor converter) {
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
public void setAsText(String text) throws IllegalArgumentException {
|
||||
try {
|
||||
Object convertedValue = converter.execute(text);
|
||||
setValue(convertedValue);
|
||||
} catch (ConversionException e) {
|
||||
IllegalArgumentException iae = new IllegalArgumentException("Unable to convert text '" + text + "'");
|
||||
iae.initCause(e);
|
||||
throw iae;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -149,4 +149,8 @@ public class SpringELExpression implements Expression {
|
||||
return variableValues;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getExpressionString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,11 +16,12 @@
|
||||
package org.springframework.binding.expression.spel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
import org.springframework.binding.convert.service.DefaultConversionService;
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.binding.expression.ExpressionParser;
|
||||
import org.springframework.binding.expression.ExpressionVariable;
|
||||
@@ -28,16 +29,11 @@ import org.springframework.binding.expression.ParserContext;
|
||||
import org.springframework.binding.expression.ParserException;
|
||||
import org.springframework.binding.expression.support.NullParserContext;
|
||||
import org.springframework.context.expression.MapAccessor;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
import org.springframework.expression.TypeConverter;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.expression.spel.support.StandardTypeConverter;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
import org.springframework.format.datetime.DateFormatter;
|
||||
import org.springframework.format.support.FormattingConversionServiceFactoryBean;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -57,29 +53,17 @@ public class SpringELExpressionParser implements ExpressionParser {
|
||||
private List propertyAccessors = new ArrayList();
|
||||
|
||||
public SpringELExpressionParser(SpelExpressionParser expressionParser) {
|
||||
this(expressionParser, new DefaultConversionService());
|
||||
}
|
||||
|
||||
public SpringELExpressionParser(SpelExpressionParser expressionParser, ConversionService conversionService) {
|
||||
this.expressionParser = expressionParser;
|
||||
this.propertyAccessors.add(new MapAccessor());
|
||||
}
|
||||
|
||||
public ConversionService getConversionService() {
|
||||
ensureConversionServiceInitialized();
|
||||
return conversionService;
|
||||
}
|
||||
|
||||
public void setConversionService(ConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
private void ensureConversionServiceInitialized() {
|
||||
if (this.conversionService == null) {
|
||||
FormattingConversionServiceFactoryBean factoryBean = new FormattingConversionServiceFactoryBean() {
|
||||
protected void installFormatters(FormatterRegistry registry) {
|
||||
registry.addFormatterForFieldType(Date.class, new DateFormatter());
|
||||
}
|
||||
};
|
||||
factoryBean.afterPropertiesSet();
|
||||
this.conversionService = factoryBean.getObject();
|
||||
}
|
||||
public ConversionService getConversionService() {
|
||||
return conversionService;
|
||||
}
|
||||
|
||||
public void addPropertyAccessor(PropertyAccessor propertyAccessor) {
|
||||
@@ -90,17 +74,13 @@ public class SpringELExpressionParser implements ExpressionParser {
|
||||
Assert.hasText(expressionString, "The expression string to parse is required and must not be empty");
|
||||
parserContext = (parserContext == null) ? NullParserContext.INSTANCE : parserContext;
|
||||
StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
|
||||
evaluationContext.setTypeConverter(getTypeConverter());
|
||||
evaluationContext.setTypeConverter(new StandardTypeConverter(conversionService.getDelegateConversionService()));
|
||||
evaluationContext.getPropertyAccessors().addAll(propertyAccessors);
|
||||
Map spelExpressionVariables = parseSpelExpressionVariables(parserContext.getExpressionVariables());
|
||||
return new SpringELExpression(parseSpelExpression(expressionString, parserContext), spelExpressionVariables,
|
||||
parserContext.getExpectedEvaluationResultType(), evaluationContext);
|
||||
}
|
||||
|
||||
private TypeConverter getTypeConverter() {
|
||||
return (conversionService != null) ? new StandardTypeConverter(conversionService) : new StandardTypeConverter();
|
||||
}
|
||||
|
||||
private org.springframework.expression.Expression parseSpelExpression(String expression, ParserContext parserContext) {
|
||||
return expressionParser.parseExpression(expression, getSpelParserContext(parserContext));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user