custom converters
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
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
|
||||
* safely cached for use by client code.
|
||||
@@ -35,8 +37,8 @@ public interface ConversionService {
|
||||
public Object executeConversion(Object source, Class targetClass) throws ConversionException;
|
||||
|
||||
/**
|
||||
* Return the conversion executor capable of converting source objects of the specified <code>sourceClass</code>
|
||||
* to instances of the <code>targetClass</code>.
|
||||
* Return the default conversion executor capable of converting source objects of the specified
|
||||
* <code>sourceClass</code> to instances of the <code>targetClass</code>.
|
||||
* <p>
|
||||
* The returned ConversionExecutor is thread-safe and may safely be cached for use in client code.
|
||||
* @param sourceClass the source class to convert from (required)
|
||||
@@ -47,17 +49,31 @@ public interface ConversionService {
|
||||
public ConversionExecutor getConversionExecutor(Class sourceClass, Class targetClass)
|
||||
throws ConversionExecutorNotFoundException;
|
||||
|
||||
/**
|
||||
* Return the custom conversion executor capable of converting source objects of the specified
|
||||
* <code>sourceClass</code> to instances of the <code>targetClass</code>.
|
||||
* <p>
|
||||
* The returned ConversionExecutor is thread-safe and may safely be cached for use in client code.
|
||||
* @param id the id of the custom conversion executor (required)
|
||||
* @param sourceClass the source class to convert from (required)
|
||||
* @param targetClass the target class to convert to (required)
|
||||
* @return the executor that can execute instance type conversion, never null
|
||||
* @throws ConversionExecutorNotFoundException when no suitable conversion executor could be found
|
||||
*/
|
||||
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>ConversionExecutor[] getConversionExecutor(String.class)</code> would return all converters that
|
||||
* convert from String to some other Object.
|
||||
* 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 ConversionExecutor[] getConversionExecutors(Class sourceClass);
|
||||
public Set getConversionExecutors(Class sourceClass);
|
||||
|
||||
/**
|
||||
* Lookup a class by it alias. For example, <code>long</code> for <code>java.lang.Long</code>
|
||||
* Lookup a class by its well-known alias. For example, <code>long</code> for <code>java.lang.Long</code>
|
||||
* @param alias the class alias
|
||||
* @return the class, or <code>null</code> if no alias exists
|
||||
*/
|
||||
|
||||
@@ -50,6 +50,10 @@ public class FormattedStringToNumber extends StringToObject {
|
||||
|
||||
private boolean lenient;
|
||||
|
||||
public FormattedStringToNumber() {
|
||||
super(Number.class);
|
||||
}
|
||||
|
||||
public FormattedStringToNumber(Class numberClass) {
|
||||
super(numberClass);
|
||||
}
|
||||
|
||||
@@ -16,13 +16,12 @@
|
||||
package org.springframework.binding.convert.service;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
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.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -52,6 +51,12 @@ public class GenericConversionService implements ConversionService {
|
||||
*/
|
||||
private final Map sourceClassConverters = new HashMap();
|
||||
|
||||
/**
|
||||
* A map of custom converters. Custom converters are assigned a unique identifier that can be used to lookup the
|
||||
* converter. This allows multiple converters for the same source->target class to be registered.
|
||||
*/
|
||||
private final Map customConverters = new HashMap();
|
||||
|
||||
/**
|
||||
* Indexes classes by well-known aliases.
|
||||
*/
|
||||
@@ -83,14 +88,6 @@ public class GenericConversionService implements ConversionService {
|
||||
public void addConverter(Converter converter) {
|
||||
Class sourceClass = converter.getSourceClass();
|
||||
Class targetClass = converter.getTargetClass();
|
||||
if (sourceClass.isPrimitive()) {
|
||||
throw new IllegalArgumentException("Invalid Converter " + converter
|
||||
+ "; A primitive type is not allowed for the [sourceClass] argument");
|
||||
}
|
||||
if (targetClass.isPrimitive()) {
|
||||
throw new IllegalArgumentException("Invalid Converter " + converter
|
||||
+ "; A primitive type is not allowed for the [targetClass] argument");
|
||||
}
|
||||
Map sourceMap = getSourceMap(sourceClass);
|
||||
sourceMap.put(targetClass, converter);
|
||||
if (converter instanceof TwoWayConverter) {
|
||||
@@ -99,6 +96,15 @@ public class GenericConversionService implements ConversionService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add given custom converter to this conversion service.
|
||||
* @param id the id of the custom converter instance
|
||||
* @param converter the converter
|
||||
*/
|
||||
public void addConverter(String id, Converter converter) {
|
||||
customConverters.put(id, converter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an alias for given target type.
|
||||
*/
|
||||
@@ -154,12 +160,42 @@ public class GenericConversionService implements ConversionService {
|
||||
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() + "'");
|
||||
"No ConversionExecutor found for converting from sourceClass [" + sourceClass.getName()
|
||||
+ "] to target class [" + targetClass.getName() + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ConversionExecutor getConversionExecutor(String id, Class sourceClass, Class targetClass)
|
||||
throws ConversionExecutorNotFoundException {
|
||||
Converter converter = (Converter) customConverters.get(id);
|
||||
if (converter == null) {
|
||||
throw new ConversionExecutorNotFoundException(sourceClass, targetClass,
|
||||
"No custom ConversionExecutor found with id '" + id + "' for converting from sourceClass ["
|
||||
+ sourceClass.getName() + "] to targetClass [" + targetClass.getName() + "]");
|
||||
}
|
||||
if (converter.getSourceClass().isAssignableFrom(sourceClass)) {
|
||||
if (!converter.getTargetClass().isAssignableFrom(targetClass)) {
|
||||
throw new ConversionExecutorNotFoundException(sourceClass, targetClass,
|
||||
"Custom ConversionExecutor with id '" + id + "' cannot convert from sourceClass ["
|
||||
+ sourceClass.getName() + "] to targetClass [" + targetClass.getName() + "]");
|
||||
}
|
||||
return new StaticConversionExecutor(sourceClass, targetClass, converter);
|
||||
} else if (converter.getTargetClass().isAssignableFrom(sourceClass) && converter instanceof TwoWayConverter) {
|
||||
if (!converter.getSourceClass().isAssignableFrom(targetClass)) {
|
||||
throw new ConversionExecutorNotFoundException(sourceClass, targetClass,
|
||||
"Custom ConversionExecutor with id '" + id + "' cannot convert from sourceClass ["
|
||||
+ sourceClass.getName() + "] to targetClass [" + targetClass.getName() + "]");
|
||||
}
|
||||
TwoWayConverter twoWay = (TwoWayConverter) converter;
|
||||
return new StaticConversionExecutor(sourceClass, targetClass, new ReverseConverter(twoWay));
|
||||
} else {
|
||||
throw new ConversionExecutorNotFoundException(sourceClass, targetClass,
|
||||
"Custom ConversionExecutor with id '" + id + "' cannot convert from sourceClass ["
|
||||
+ sourceClass.getName() + "] to targetClass [" + targetClass.getName() + "]");
|
||||
}
|
||||
}
|
||||
|
||||
private Converter findRegisteredConverter(Class sourceClass, Class targetClass) {
|
||||
if (sourceClass.isInterface()) {
|
||||
LinkedList classQueue = new LinkedList();
|
||||
@@ -224,20 +260,27 @@ public class GenericConversionService implements ConversionService {
|
||||
|
||||
// subclassing support
|
||||
|
||||
public ConversionExecutor[] getConversionExecutors(Class sourceClass) {
|
||||
public Set getConversionExecutors(Class sourceClass) {
|
||||
Set parentExecutors;
|
||||
if (parent != null) {
|
||||
parentExecutors = parent.getConversionExecutors(sourceClass);
|
||||
} else {
|
||||
parentExecutors = Collections.EMPTY_SET;
|
||||
}
|
||||
Map sourceMap = getSourceMap(sourceClass);
|
||||
if (sourceMap.isEmpty()) {
|
||||
return new ConversionExecutor[0];
|
||||
if (parentExecutors.isEmpty() && sourceMap.isEmpty()) {
|
||||
return Collections.EMPTY_SET;
|
||||
}
|
||||
Set entries = sourceMap.entrySet();
|
||||
List conversionExecutors = new ArrayList(entries.size());
|
||||
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));
|
||||
}
|
||||
return (ConversionExecutor[]) conversionExecutors.toArray(new ConversionExecutor[entries.size()]);
|
||||
conversionExecutors.addAll(parentExecutors);
|
||||
return conversionExecutors;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
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;
|
||||
@@ -88,9 +90,9 @@ public class BeanWrapperExpression implements Expression {
|
||||
public void setValue(Object context, Object value) {
|
||||
try {
|
||||
BeanWrapperImpl beanWrapper = new BeanWrapperImpl(context);
|
||||
ConversionExecutor[] converters = conversionService.getConversionExecutors(String.class);
|
||||
for (int i = 0; i < converters.length; i++) {
|
||||
ConversionExecutor converter = converters[i];
|
||||
Set converters = conversionService.getConversionExecutors(String.class);
|
||||
for (Iterator it = converters.iterator(); it.hasNext();) {
|
||||
ConversionExecutor converter = (ConversionExecutor) it.next();
|
||||
beanWrapper.registerCustomEditor(converter.getTargetClass(), new PropertyEditorConverter(converter));
|
||||
}
|
||||
beanWrapper.setPropertyValue(expression, value);
|
||||
|
||||
Reference in New Issue
Block a user