super converter implementation
This commit is contained in:
parent
b04009357a
commit
0ef0ff60f0
|
|
@ -16,7 +16,7 @@
|
|||
package org.springframework.core.convert;
|
||||
|
||||
/**
|
||||
* A command object that is parameterized with the information necessary to perform a conversion of a source input to a
|
||||
* A command parameterized with the information necessary to perform a conversion of a source input to a
|
||||
* target output. Encapsulates knowledge about how to convert source objects to a specific target type using a specific
|
||||
* converter.
|
||||
*
|
||||
|
|
@ -25,20 +25,19 @@ package org.springframework.core.convert;
|
|||
public interface ConversionExecutor<S, T> {
|
||||
|
||||
/**
|
||||
* Returns the source class of conversions performed by this executor.
|
||||
* @return the source class
|
||||
* The type this executor converts from.
|
||||
*/
|
||||
public Class<S> getSourceClass();
|
||||
|
||||
/**
|
||||
* Returns the target class of conversions performed by this executor.
|
||||
* @return the target class
|
||||
*/
|
||||
* The type this executor converts to.
|
||||
s */
|
||||
public Class<T> getTargetClass();
|
||||
|
||||
/**
|
||||
* Execute the conversion for the provided source object.
|
||||
* @param source the source object to convert
|
||||
* Convert the source to T.
|
||||
* @param source the source to convert
|
||||
* @throws ConversionExecutionException if an exception occurs during type conversion
|
||||
*/
|
||||
public T execute(S source) throws ConversionExecutionException;
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ package org.springframework.core.convert;
|
|||
public interface ConversionService {
|
||||
|
||||
/**
|
||||
* Convert the source object to <code>targetClass</code>
|
||||
* Convert the source to target class T.
|
||||
* @param source the source to convert from (may be null)
|
||||
* @param targetClass the target class to convert to
|
||||
* @return the converted object, an instance of the <code>targetClass</code>, or <code>null</code> if a null source
|
||||
|
|
@ -39,7 +39,7 @@ public interface ConversionService {
|
|||
ConversionException;
|
||||
|
||||
/**
|
||||
* Convert the source object to <code>targetClass</code> using a custom converter.
|
||||
* Convert the source to target class T with a custom converter.
|
||||
* @param converterId the id of the custom converter, which must be registered with this conversion service and
|
||||
* capable of converting to the targetClass
|
||||
* @param source the source to convert from (may be null)
|
||||
|
|
@ -54,7 +54,7 @@ public interface ConversionService {
|
|||
throws ConversionExecutorNotFoundException, ConversionException;
|
||||
|
||||
/**
|
||||
* Get a ConversionExecutor capable of converting objects from <code>sourceClass</code> to <code>targetClass</code>.
|
||||
* Get a ConversionExecutor that converts objects from S to T.
|
||||
* The returned ConversionExecutor is thread-safe and may safely be cached for later use by client code.
|
||||
* @param sourceClass the source class to convert from (required)
|
||||
* @param targetClass the target class to convert to (required)
|
||||
|
|
@ -65,9 +65,8 @@ public interface ConversionService {
|
|||
throws ConversionExecutorNotFoundException;
|
||||
|
||||
/**
|
||||
* Get a ConversionExecutor that uses a custom converter to capable convert objects from <code>sourceClass</code> to
|
||||
* <code>targetClass</code>. The returned ConversionExecutor is thread-safe and may safely be cached for use in
|
||||
* client code.
|
||||
* Get a ConversionExecutor that that converts objects from S to T with a custom converter.
|
||||
* The returned ConversionExecutor is thread-safe and may safely be cached for use in client code.
|
||||
* @param converterId the id of the custom converter, which must be registered with this conversion service and
|
||||
* capable of converting from sourceClass to targetClass (required)
|
||||
* @param sourceClass the source class to convert from (required)
|
||||
|
|
@ -79,9 +78,8 @@ public interface ConversionService {
|
|||
Class<T> targetClass) throws ConversionExecutorNotFoundException;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Get a class by its alias.
|
||||
* @return the class, or <code>null</code> if no such alias exists
|
||||
*/
|
||||
public Class<?> getClassForAlias(String alias);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import org.springframework.core.convert.ConversionException;
|
|||
import org.springframework.core.convert.ConversionService;
|
||||
|
||||
/**
|
||||
* A converter converts a source object of type S to a target type of type T and back.
|
||||
* A converter converts a source object of type S to a target of type T and back.
|
||||
* <p>
|
||||
* Implementations of this interface are thread-safe and can be shared. Converters are typically registered with and
|
||||
* accessed through a {@link ConversionService}.
|
||||
|
|
@ -29,7 +29,7 @@ import org.springframework.core.convert.ConversionService;
|
|||
public interface Converter<S, T> {
|
||||
|
||||
/**
|
||||
* Convert the source S to target type T.
|
||||
* Convert the source of type S to target type T.
|
||||
* @param source the source object to convert, which must be an instance of S
|
||||
* @return the converted object, which must be an instance of T
|
||||
* @throws Exception an exception occurred performing the conversion; may be any checked exception, the conversion
|
||||
|
|
@ -39,7 +39,7 @@ public interface Converter<S, T> {
|
|||
public T convert(S source) throws Exception;
|
||||
|
||||
/**
|
||||
* Convert the target T back to source type S.
|
||||
* Convert the target of type T back to source type S.
|
||||
* @param target the target object to convert, which must be an instance of T
|
||||
* @return the converted object, which must be an instance of S
|
||||
* @throws Exception an exception occurred performing the conversion; may be any checked exception, the conversion
|
||||
|
|
|
|||
|
|
@ -37,12 +37,8 @@ import org.springframework.util.NumberUtils;
|
|||
*/
|
||||
public class NumberToNumber implements SuperConverter<Number, Number> {
|
||||
|
||||
public <N extends Number> N convert(Number source, Class<N> targetClass) throws Exception {
|
||||
public <RT extends Number> RT convert(Number source, Class<RT> targetClass) throws Exception {
|
||||
return NumberUtils.convertNumberToTargetClass(source, targetClass);
|
||||
}
|
||||
|
||||
public Number convertBack(Number target) throws Exception {
|
||||
return target;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -16,19 +16,19 @@
|
|||
package org.springframework.core.convert.converter;
|
||||
|
||||
/**
|
||||
* Converts from a String to Enum using {@link Enum#valueOf(Class, String)}.
|
||||
* Converts a String to a Enum using {@link Enum#valueOf(Class, String)}.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class StringToEnum implements SuperConverter<String, Enum> {
|
||||
public class StringToEnum implements SuperTwoWayConverter<String, Enum> {
|
||||
|
||||
public <E extends Enum> E convert(String source, Class<E> targetClass) throws Exception {
|
||||
public <RT extends Enum> RT convert(String source, Class<RT> targetClass) throws Exception {
|
||||
return Enum.valueOf(targetClass, source);
|
||||
}
|
||||
|
||||
public String convertBack(Enum target) throws Exception {
|
||||
return target.name();
|
||||
public <RS extends String> RS convertBack(Enum target, Class<RS> sourceClass) throws Exception {
|
||||
return (RS) target.name();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -19,8 +19,7 @@ import org.springframework.core.convert.ConversionException;
|
|||
import org.springframework.core.convert.ConversionService;
|
||||
|
||||
/**
|
||||
* A super converter converts a source object of type S to a target type of type AT and back, where AT is equal to or a
|
||||
* subclass of T, T being the "super" target type. This allows a single converter to convert to objects that are part of a common class hierarchy.
|
||||
* A super converter converts a source object of type S to a target of class hierarchy T.
|
||||
* <p>
|
||||
* Implementations of this interface are thread-safe and can be shared. Converters are typically registered with and
|
||||
* accessed through a {@link ConversionService}.
|
||||
|
|
@ -30,25 +29,14 @@ import org.springframework.core.convert.ConversionService;
|
|||
public interface SuperConverter<S, T> {
|
||||
|
||||
/**
|
||||
* Convert the source S to an instance of AT.
|
||||
* @param source the source object to convert, which must be an instance of S
|
||||
* @param actualTargetClass the actual target class to convert to (AT), which must be equal to or a specialization
|
||||
* of T.
|
||||
* @return the converted object, which must be an instance of AT
|
||||
* Convert the source of type S to an instance of type RT.
|
||||
* @param source the source object to convert, whose class must be equal to or a subclass of S
|
||||
* @param targetClass the requested target class to convert to (RT), which must be equal to T or extend from T
|
||||
* @return the converted object, which must be an instance of RT
|
||||
* @throws Exception an exception occurred performing the conversion; may be any checked exception, the conversion
|
||||
* system will handle wrapping the failure in a {@link ConversionException} that provides a consistent type
|
||||
* conversion error context
|
||||
*/
|
||||
public <AT extends T> AT convert(S source, Class<AT> actualTargetClass) throws Exception;
|
||||
|
||||
/**
|
||||
* Convert the target T to an instance of S.
|
||||
* @param target the target object to convert, which must be an instance of T.
|
||||
* @return the converted object, which must be an instance of S.
|
||||
* @throws Exception an exception occurred performing the conversion; may be any checked exception, the conversion
|
||||
* system will handle wrapping the failure in a {@link ConversionException} that provides a consistent type
|
||||
* conversion error context
|
||||
*/
|
||||
public S convertBack(T target) throws Exception;
|
||||
public <RT extends T> RT convert(S source, Class<RT> targetClass) throws Exception;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package org.springframework.core.convert.converter;
|
||||
|
||||
import org.springframework.core.convert.ConversionException;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
|
||||
/**
|
||||
* A super converter that can also convert a target object of type T to a source of class hierarchy S.
|
||||
* <p>
|
||||
* Implementations of this interface are thread-safe and can be shared. Converters are typically registered with and
|
||||
* accessed through a {@link ConversionService}.
|
||||
* </p>
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface SuperTwoWayConverter<S, T> extends SuperConverter<S, T> {
|
||||
|
||||
/**
|
||||
* Convert the target of type T to an instance of S.
|
||||
* @param target the target object to convert, whose class must be equal to or a subclass of T
|
||||
* @param sourceClass the requested source class to convert to, which must be equal to S or extend from S
|
||||
* @return the converted object, which must be an instance of S
|
||||
* @throws Exception an exception occurred performing the conversion; may be any checked exception, the conversion
|
||||
* system will handle wrapping the failure in a {@link ConversionException} that provides a consistent type
|
||||
* conversion error context
|
||||
*/
|
||||
public <RS extends S> RS convertBack(T target, Class<RS> sourceClass) throws Exception;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package org.springframework.core.convert.converter;
|
||||
|
||||
/**
|
||||
* Adapts a {@link SuperTwoWayConverter} to the {@link Converter} interface in a type safe way. This adapter is useful
|
||||
* for applying more general {@link SuperConverter} logic to a specific source/target class pair.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class SuperTwoWayConverterConverter<S, T> implements Converter<S, T> {
|
||||
|
||||
private SuperTwoWayConverter superConverter;
|
||||
|
||||
private Class sourceClass;
|
||||
|
||||
private Class targetClass;
|
||||
|
||||
public <SCS, SCT> SuperTwoWayConverterConverter(SuperTwoWayConverter<SCS, SCT> superConverter,
|
||||
Class<? extends SCS> sourceClass, Class<? extends SCT> targetClass) {
|
||||
this.superConverter = superConverter;
|
||||
this.sourceClass = sourceClass;
|
||||
this.targetClass = targetClass;
|
||||
}
|
||||
|
||||
public T convert(S source) throws Exception {
|
||||
return (T) superConverter.convert(source, targetClass);
|
||||
}
|
||||
|
||||
public S convertBack(T target) throws Exception {
|
||||
return (S) superConverter.convertBack(target, sourceClass);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -53,18 +53,7 @@ class ArrayToArray implements SuperConverter {
|
|||
this.elementConverter = elementConverter;
|
||||
}
|
||||
|
||||
public Class getSourceClass() {
|
||||
return Object[].class;
|
||||
}
|
||||
|
||||
public Class getSuperTargetClass() {
|
||||
return Object[].class;
|
||||
}
|
||||
|
||||
public Object convert(Object source, Class targetClass) throws Exception {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
Class sourceComponentType = source.getClass().getComponentType();
|
||||
Class targetComponentType = targetClass.getComponentType();
|
||||
int length = Array.getLength(source);
|
||||
|
|
@ -77,10 +66,6 @@ class ArrayToArray implements SuperConverter {
|
|||
return targetArray;
|
||||
}
|
||||
|
||||
public Object convertBack(Object target) throws Exception {
|
||||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
|
||||
private ConversionExecutor getElementConverter(Class sourceComponentType, Class targetComponentType) {
|
||||
if (elementConverter != null) {
|
||||
return elementConverter;
|
||||
|
|
|
|||
|
|
@ -17,19 +17,13 @@ package org.springframework.core.convert.service;
|
|||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.springframework.core.GenericCollectionTypeResolver;
|
||||
import org.springframework.core.convert.ConversionExecutor;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.converter.SuperConverter;
|
||||
import org.springframework.core.convert.converter.SuperTwoWayConverter;
|
||||
|
||||
/**
|
||||
* Special converter that converts from a source array to a target collection. Supports the selection of an
|
||||
|
|
@ -45,7 +39,7 @@ import org.springframework.core.convert.converter.SuperConverter;
|
|||
* @author Keith Donald
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
class ArrayToCollection implements SuperConverter {
|
||||
class ArrayToCollection implements SuperTwoWayConverter {
|
||||
|
||||
private ConversionService conversionService;
|
||||
|
||||
|
|
@ -69,11 +63,8 @@ class ArrayToCollection implements SuperConverter {
|
|||
}
|
||||
|
||||
public Object convert(Object source, Class targetClass) throws Exception {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
Class collectionImplClass = getCollectionImplClass(targetClass);
|
||||
Constructor constructor = collectionImplClass.getConstructor((Class[]) null);
|
||||
Class implClass = CollectionConversionUtils.getImpl(targetClass);
|
||||
Constructor constructor = implClass.getConstructor((Class[]) null);
|
||||
Collection collection = (Collection) constructor.newInstance((Object[]) null);
|
||||
ConversionExecutor converter = getArrayElementConverter(source, targetClass);
|
||||
int length = Array.getLength(source);
|
||||
|
|
@ -87,16 +78,10 @@ class ArrayToCollection implements SuperConverter {
|
|||
return collection;
|
||||
}
|
||||
|
||||
public Object convertBack(Object target) throws Exception {
|
||||
throw new UnsupportedOperationException("Should never be called");
|
||||
}
|
||||
|
||||
public Object convertBack(Object target, Class sourceClass) throws Exception {
|
||||
if (target == null) {
|
||||
return null;
|
||||
}
|
||||
Collection collection = (Collection) target;
|
||||
Object array = Array.newInstance(sourceClass.getComponentType(), collection.size());
|
||||
Class elementType = sourceClass.getComponentType();
|
||||
Object array = Array.newInstance(elementType, collection.size());
|
||||
int i = 0;
|
||||
for (Iterator it = collection.iterator(); it.hasNext(); i++) {
|
||||
Object value = it.next();
|
||||
|
|
@ -105,8 +90,7 @@ class ArrayToCollection implements SuperConverter {
|
|||
if (elementConverter != null) {
|
||||
converter = elementConverter;
|
||||
} else {
|
||||
converter = conversionService.getConversionExecutor(value.getClass(), sourceClass
|
||||
.getComponentType());
|
||||
converter = conversionService.getConversionExecutor(value.getClass(), elementType);
|
||||
}
|
||||
value = converter.execute(value);
|
||||
}
|
||||
|
|
@ -115,22 +99,6 @@ class ArrayToCollection implements SuperConverter {
|
|||
return array;
|
||||
}
|
||||
|
||||
private Class getCollectionImplClass(Class targetClass) {
|
||||
if (targetClass.isInterface()) {
|
||||
if (List.class.equals(targetClass)) {
|
||||
return ArrayList.class;
|
||||
} else if (Set.class.equals(targetClass)) {
|
||||
return LinkedHashSet.class;
|
||||
} else if (SortedSet.class.equals(targetClass)) {
|
||||
return TreeSet.class;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported collection interface [" + targetClass.getName() + "]");
|
||||
}
|
||||
} else {
|
||||
return targetClass;
|
||||
}
|
||||
}
|
||||
|
||||
private ConversionExecutor getArrayElementConverter(Object source, Class targetClass) {
|
||||
if (elementConverter != null) {
|
||||
return elementConverter;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2004-2009 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.core.convert.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
class CollectionConversionUtils {
|
||||
|
||||
static Class<?> getImpl(Class<?> targetClass) {
|
||||
if (targetClass.isInterface()) {
|
||||
if (List.class.equals(targetClass)) {
|
||||
return ArrayList.class;
|
||||
} else if (Set.class.equals(targetClass)) {
|
||||
return LinkedHashSet.class;
|
||||
} else if (SortedSet.class.equals(targetClass)) {
|
||||
return TreeSet.class;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported collection interface [" + targetClass.getName() + "]");
|
||||
}
|
||||
} else {
|
||||
return targetClass;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -15,14 +15,8 @@
|
|||
*/
|
||||
package org.springframework.core.convert.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.springframework.core.GenericCollectionTypeResolver;
|
||||
import org.springframework.core.convert.ConversionExecutor;
|
||||
|
|
@ -35,7 +29,7 @@ import org.springframework.core.convert.converter.SuperConverter;
|
|||
* @author Keith Donald
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
class CollectionToCollection implements SuperConverter {
|
||||
class CollectionToCollection implements SuperConverter<Collection, Collection> {
|
||||
|
||||
private ConversionService conversionService;
|
||||
|
||||
|
|
@ -58,21 +52,10 @@ class CollectionToCollection implements SuperConverter {
|
|||
this.elementConverter = elementConverter;
|
||||
}
|
||||
|
||||
public Class getSourceClass() {
|
||||
return Collection.class;
|
||||
}
|
||||
|
||||
public Class getSuperTargetClass() {
|
||||
return Collection.class;
|
||||
}
|
||||
|
||||
public Object convert(Object source, Class targetClass) throws Exception {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
Class targetCollectionImpl = getCollectionImplClass(targetClass);
|
||||
Collection targetCollection = (Collection) targetCollectionImpl.getConstructor((Class[]) null).newInstance(
|
||||
(Object[]) null);
|
||||
public Collection convert(Collection source, Class targetClass) throws Exception {
|
||||
Class implClass = CollectionConversionUtils.getImpl(targetClass);
|
||||
Collection targetCollection = (Collection) implClass.getConstructor((Class[]) null)
|
||||
.newInstance((Object[]) null);
|
||||
ConversionExecutor elementConverter = getElementConverter(source, targetClass);
|
||||
Collection sourceCollection = (Collection) source;
|
||||
Iterator it = sourceCollection.iterator();
|
||||
|
|
@ -86,27 +69,6 @@ class CollectionToCollection implements SuperConverter {
|
|||
return targetCollection;
|
||||
}
|
||||
|
||||
public Object convertBack(Object target) throws Exception {
|
||||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
|
||||
// this code is duplicated in ArrayToCollection.java and ObjectToCollection too
|
||||
private Class getCollectionImplClass(Class targetClass) {
|
||||
if (targetClass.isInterface()) {
|
||||
if (List.class.equals(targetClass)) {
|
||||
return ArrayList.class;
|
||||
} else if (Set.class.equals(targetClass)) {
|
||||
return LinkedHashSet.class;
|
||||
} else if (SortedSet.class.equals(targetClass)) {
|
||||
return TreeSet.class;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported collection interface [" + targetClass.getName() + "]");
|
||||
}
|
||||
} else {
|
||||
return targetClass;
|
||||
}
|
||||
}
|
||||
|
||||
private ConversionExecutor getElementConverter(Object source, Class targetClass) {
|
||||
if (elementConverter != null) {
|
||||
return elementConverter;
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ import org.springframework.core.convert.converter.StringToLong;
|
|||
import org.springframework.core.convert.converter.StringToShort;
|
||||
|
||||
/**
|
||||
* Default, local implementation of a conversion service. Will automatically register <i>from string</i> converters for
|
||||
* Default implementation of a conversion service. Will automatically register <i>from string</i> converters for
|
||||
* a number of standard Java types like Class, Number, Boolean and so on.
|
||||
*
|
||||
* @author Keith Donald
|
||||
|
|
@ -67,6 +67,7 @@ public class DefaultConversionService extends GenericConversionService {
|
|||
addConverter(new StringToLocale());
|
||||
addConverter(new StringToEnum());
|
||||
addConverter(new NumberToNumber());
|
||||
// TODO probably don't allow these to be customized, or at least make public
|
||||
addConverter(new ObjectToCollection(this));
|
||||
addConverter(new CollectionToCollection(this));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,11 +34,14 @@ import org.springframework.core.convert.ConversionExecutorNotFoundException;
|
|||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.converter.SuperConverter;
|
||||
import org.springframework.core.convert.converter.SuperTwoWayConverter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Base implementation of a conversion service. Initially empty, e.g. no converters are registered by default.
|
||||
*
|
||||
* TODO custom converters TODO handle case where no Converter/SuperConverter generic param info is available
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
@ -50,6 +53,12 @@ public class GenericConversionService implements ConversionService {
|
|||
*/
|
||||
private final Map sourceClassConverters = new HashMap();
|
||||
|
||||
/**
|
||||
* An indexed map of Converters. Each Map.Entry key is a source class (S) that can be converted from. Each Map.Entry
|
||||
* value is a Map that defines the targetClass-to-Converter mappings for that source.
|
||||
*/
|
||||
private final Map sourceClassSuperConverters = new HashMap();
|
||||
|
||||
/**
|
||||
* Indexes classes by well-known aliases.
|
||||
*/
|
||||
|
|
@ -95,7 +104,17 @@ public class GenericConversionService implements ConversionService {
|
|||
* @param converter the super converter to register
|
||||
*/
|
||||
public void addConverter(SuperConverter converter) {
|
||||
// TODO
|
||||
List typeInfo = getTypeInfo(converter);
|
||||
Class sourceClass = (Class) typeInfo.get(0);
|
||||
Class targetClass = (Class) typeInfo.get(1);
|
||||
// index forward
|
||||
Map sourceMap = getSourceSuperConverterMap(sourceClass);
|
||||
sourceMap.put(targetClass, converter);
|
||||
if (converter instanceof SuperTwoWayConverter) {
|
||||
// index reverse
|
||||
sourceMap = getSourceSuperConverterMap(targetClass);
|
||||
sourceMap.put(sourceClass, new ReverseSuperConverter((SuperTwoWayConverter) converter));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -109,22 +128,14 @@ public class GenericConversionService implements ConversionService {
|
|||
|
||||
public Object executeConversion(Object source, Class targetClass) throws ConversionExecutorNotFoundException,
|
||||
ConversionException {
|
||||
if (source != null) {
|
||||
ConversionExecutor conversionExecutor = getConversionExecutor(source.getClass(), targetClass);
|
||||
return conversionExecutor.execute(source);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Object executeConversion(String converterId, Object source, Class targetClass)
|
||||
throws ConversionExecutorNotFoundException, ConversionException {
|
||||
if (source != null) {
|
||||
ConversionExecutor conversionExecutor = getConversionExecutor(converterId, source.getClass(), targetClass);
|
||||
return conversionExecutor.execute(source);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ConversionExecutor getConversionExecutor(Class sourceClass, Class targetClass)
|
||||
|
|
@ -151,7 +162,8 @@ public class GenericConversionService implements ConversionService {
|
|||
}
|
||||
if (targetClass.isArray()) {
|
||||
if (Collection.class.isAssignableFrom(sourceClass)) {
|
||||
return new StaticSuperConversionExecutor(sourceClass, targetClass, new CollectionToArray(this));
|
||||
SuperConverter collectionToArray = new ReverseSuperConverter(new ArrayToCollection(this));
|
||||
return new StaticSuperConversionExecutor(sourceClass, targetClass, collectionToArray);
|
||||
} else {
|
||||
return new StaticSuperConversionExecutor(sourceClass, targetClass, new ObjectToArray(this));
|
||||
}
|
||||
|
|
@ -161,6 +173,10 @@ public class GenericConversionService implements ConversionService {
|
|||
// we found a converter
|
||||
return new StaticConversionExecutor(sourceClass, targetClass, converter);
|
||||
} else {
|
||||
SuperConverter superConverter = findRegisteredSuperConverter(sourceClass, targetClass);
|
||||
if (superConverter != null) {
|
||||
return new StaticSuperConversionExecutor(sourceClass, targetClass, superConverter);
|
||||
}
|
||||
if (parent != null) {
|
||||
// try the parent
|
||||
return parent.getConversionExecutor(sourceClass, targetClass);
|
||||
|
|
@ -192,7 +208,7 @@ public class GenericConversionService implements ConversionService {
|
|||
|
||||
// internal helpers
|
||||
|
||||
private List getTypeInfo(Converter converter) {
|
||||
private List getTypeInfo(Object converter) {
|
||||
List typeInfo = new ArrayList(2);
|
||||
Class classToIntrospect = converter.getClass();
|
||||
while (classToIntrospect != null) {
|
||||
|
|
@ -200,7 +216,8 @@ public class GenericConversionService implements ConversionService {
|
|||
for (Type genericInterface : genericInterfaces) {
|
||||
if (genericInterface instanceof ParameterizedType) {
|
||||
ParameterizedType parameterizedInterface = (ParameterizedType) genericInterface;
|
||||
if (Converter.class.equals(parameterizedInterface.getRawType())) {
|
||||
if (Converter.class.equals(parameterizedInterface.getRawType())
|
||||
|| SuperConverter.class.isAssignableFrom((Class) parameterizedInterface.getRawType())) {
|
||||
Type s = parameterizedInterface.getActualTypeArguments()[0];
|
||||
Type t = parameterizedInterface.getActualTypeArguments()[1];
|
||||
typeInfo.add(getParameterClass(s, converter.getClass()));
|
||||
|
|
@ -213,12 +230,12 @@ public class GenericConversionService implements ConversionService {
|
|||
return typeInfo;
|
||||
}
|
||||
|
||||
private Class<?> getParameterClass(Type parameterType, Class<?> converterClass) {
|
||||
private Class getParameterClass(Type parameterType, Class converterClass) {
|
||||
if (parameterType instanceof TypeVariable) {
|
||||
parameterType = GenericTypeResolver.resolveTypeVariable((TypeVariable<?>) parameterType, converterClass);
|
||||
parameterType = GenericTypeResolver.resolveTypeVariable((TypeVariable) parameterType, converterClass);
|
||||
}
|
||||
if (parameterType instanceof Class) {
|
||||
return (Class<?>) parameterType;
|
||||
return (Class) parameterType;
|
||||
}
|
||||
// when would this happen?
|
||||
return null;
|
||||
|
|
@ -227,12 +244,21 @@ public class GenericConversionService implements ConversionService {
|
|||
private Map getSourceMap(Class sourceClass) {
|
||||
Map sourceMap = (Map) sourceClassConverters.get(sourceClass);
|
||||
if (sourceMap == null) {
|
||||
sourceMap = new HashMap<Class<?>, Converter<?, ?>>();
|
||||
sourceMap = new HashMap();
|
||||
sourceClassConverters.put(sourceClass, sourceMap);
|
||||
}
|
||||
return sourceMap;
|
||||
}
|
||||
|
||||
private Map getSourceSuperConverterMap(Class sourceClass) {
|
||||
Map sourceMap = (Map) sourceClassSuperConverters.get(sourceClass);
|
||||
if (sourceMap == null) {
|
||||
sourceMap = new HashMap();
|
||||
sourceClassSuperConverters.put(sourceClass, sourceMap);
|
||||
}
|
||||
return sourceMap;
|
||||
}
|
||||
|
||||
private Class convertToWrapperClassIfNecessary(Class targetType) {
|
||||
if (targetType.isPrimitive()) {
|
||||
if (targetType.equals(int.class)) {
|
||||
|
|
@ -265,8 +291,8 @@ public class GenericConversionService implements ConversionService {
|
|||
classQueue.addFirst(sourceClass);
|
||||
while (!classQueue.isEmpty()) {
|
||||
Class currentClass = (Class) classQueue.removeLast();
|
||||
Map<Class, Converter> sourceTargetConverters = findConvertersForSource(currentClass);
|
||||
Converter converter = findTargetConverter(sourceTargetConverters, targetClass);
|
||||
Map converters = getConvertersForSource(currentClass);
|
||||
Converter converter = getConverter(converters, targetClass);
|
||||
if (converter != null) {
|
||||
return converter;
|
||||
}
|
||||
|
|
@ -275,15 +301,15 @@ public class GenericConversionService implements ConversionService {
|
|||
classQueue.addFirst(interfaces[i]);
|
||||
}
|
||||
}
|
||||
Map objectConverters = findConvertersForSource(Object.class);
|
||||
return findTargetConverter(objectConverters, targetClass);
|
||||
Map objectConverters = getConvertersForSource(Object.class);
|
||||
return getConverter(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);
|
||||
Map converters = getConvertersForSource(currentClass);
|
||||
Converter converter = getConverter(converters, targetClass);
|
||||
if (converter != null) {
|
||||
return converter;
|
||||
}
|
||||
|
|
@ -299,15 +325,98 @@ public class GenericConversionService implements ConversionService {
|
|||
}
|
||||
}
|
||||
|
||||
private Map findConvertersForSource(Class sourceClass) {
|
||||
Map sourceConverters = (Map) sourceClassConverters.get(sourceClass);
|
||||
return sourceConverters != null ? sourceConverters : Collections.emptyMap();
|
||||
private Map getConvertersForSource(Class sourceClass) {
|
||||
Map converters = (Map) sourceClassConverters.get(sourceClass);
|
||||
return converters != null ? converters : Collections.emptyMap();
|
||||
}
|
||||
|
||||
private Converter findTargetConverter(Map sourceTargetConverters, Class targetClass) {
|
||||
if (sourceTargetConverters.isEmpty()) {
|
||||
private Converter getConverter(Map converters, Class targetClass) {
|
||||
return (Converter) converters.get(targetClass);
|
||||
}
|
||||
|
||||
private SuperConverter findRegisteredSuperConverter(Class sourceClass, Class targetClass) {
|
||||
if (sourceClass.isInterface()) {
|
||||
LinkedList classQueue = new LinkedList();
|
||||
classQueue.addFirst(sourceClass);
|
||||
while (!classQueue.isEmpty()) {
|
||||
Class currentClass = (Class) classQueue.removeLast();
|
||||
Map converters = getSuperConvertersForSource(currentClass);
|
||||
SuperConverter converter = findSuperConverter(converters, targetClass);
|
||||
if (converter != null) {
|
||||
return converter;
|
||||
}
|
||||
Class[] interfaces = currentClass.getInterfaces();
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
classQueue.addFirst(interfaces[i]);
|
||||
}
|
||||
}
|
||||
Map objectConverters = getSuperConvertersForSource(Object.class);
|
||||
return findSuperConverter(objectConverters, targetClass);
|
||||
} else {
|
||||
LinkedList classQueue = new LinkedList();
|
||||
classQueue.addFirst(sourceClass);
|
||||
while (!classQueue.isEmpty()) {
|
||||
Class currentClass = (Class) classQueue.removeLast();
|
||||
Map converters = getSuperConvertersForSource(currentClass);
|
||||
SuperConverter converter = findSuperConverter(converters, 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;
|
||||
}
|
||||
return (Converter) sourceTargetConverters.get(targetClass);
|
||||
}
|
||||
|
||||
private Map getSuperConvertersForSource(Class sourceClass) {
|
||||
Map converters = (Map) sourceClassSuperConverters.get(sourceClass);
|
||||
return converters != null ? converters : Collections.emptyMap();
|
||||
}
|
||||
|
||||
private SuperConverter findSuperConverter(Map converters, Class targetClass) {
|
||||
if (converters.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (targetClass.isInterface()) {
|
||||
LinkedList classQueue = new LinkedList();
|
||||
classQueue.addFirst(targetClass);
|
||||
while (!classQueue.isEmpty()) {
|
||||
Class currentClass = (Class) classQueue.removeLast();
|
||||
SuperConverter converter = (SuperConverter) converters.get(currentClass);
|
||||
if (converter != null) {
|
||||
return converter;
|
||||
}
|
||||
Class[] interfaces = currentClass.getInterfaces();
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
classQueue.addFirst(interfaces[i]);
|
||||
}
|
||||
}
|
||||
return (SuperConverter) converters.get(Object.class);
|
||||
} else {
|
||||
LinkedList classQueue = new LinkedList();
|
||||
classQueue.addFirst(targetClass);
|
||||
while (!classQueue.isEmpty()) {
|
||||
Class currentClass = (Class) classQueue.removeLast();
|
||||
SuperConverter converter = (SuperConverter) converters.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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -17,11 +17,6 @@ package org.springframework.core.convert.service;
|
|||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
|
||||
/**
|
||||
* Package private converter that is a "no op".
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
class NoOpConverter implements Converter {
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import org.springframework.core.convert.ConversionService;
|
|||
import org.springframework.core.convert.converter.SuperConverter;
|
||||
|
||||
/**
|
||||
* Special two-way converter that converts an object to an single-element array. Mainly used internally by
|
||||
* Special converter that converts an object to an single-element array. Mainly used internally by
|
||||
* {@link ConversionService} implementations.
|
||||
*
|
||||
* @author Keith Donald
|
||||
|
|
@ -51,14 +51,6 @@ class ObjectToArray implements SuperConverter {
|
|||
this.elementConverter = elementConverter;
|
||||
}
|
||||
|
||||
public Class getSourceClass() {
|
||||
return Object.class;
|
||||
}
|
||||
|
||||
public Class getSuperTargetClass() {
|
||||
return Object[].class;
|
||||
}
|
||||
|
||||
public Object convert(Object source, Class targetClass) throws Exception {
|
||||
Class componentType = targetClass.getComponentType();
|
||||
Object array = Array.newInstance(componentType, 1);
|
||||
|
|
@ -72,8 +64,4 @@ class ObjectToArray implements SuperConverter {
|
|||
return array;
|
||||
}
|
||||
|
||||
public Object convertBack(Object target) throws Exception {
|
||||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -16,13 +16,7 @@
|
|||
package org.springframework.core.convert.service;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.springframework.core.GenericCollectionTypeResolver;
|
||||
import org.springframework.core.convert.ConversionExecutor;
|
||||
|
|
@ -36,7 +30,7 @@ import org.springframework.core.convert.converter.SuperConverter;
|
|||
* @author Keith Donald
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
class ObjectToCollection implements SuperConverter {
|
||||
class ObjectToCollection implements SuperConverter<Object, Collection> {
|
||||
|
||||
private ConversionService conversionService;
|
||||
|
||||
|
|
@ -59,20 +53,9 @@ class ObjectToCollection implements SuperConverter {
|
|||
this.elementConverter = elementConverter;
|
||||
}
|
||||
|
||||
public Class getSourceClass() {
|
||||
return Object.class;
|
||||
}
|
||||
|
||||
public Class getSuperTargetClass() {
|
||||
return Collection.class;
|
||||
}
|
||||
|
||||
public Object convert(Object source, Class targetClass) throws Exception {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
Class collectionImplClass = getCollectionImplClass(targetClass);
|
||||
Constructor constructor = collectionImplClass.getConstructor((Class[]) null);
|
||||
public Collection convert(Object source, Class targetClass) throws Exception {
|
||||
Class implClass = CollectionConversionUtils.getImpl(targetClass);
|
||||
Constructor constructor = implClass.getConstructor((Class[]) null);
|
||||
Collection collection = (Collection) constructor.newInstance((Object[]) null);
|
||||
ConversionExecutor converter = getElementConverter(source, targetClass);
|
||||
Object value;
|
||||
|
|
@ -85,27 +68,6 @@ class ObjectToCollection implements SuperConverter {
|
|||
return collection;
|
||||
}
|
||||
|
||||
public Object convertBack(Object target) throws Exception {
|
||||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
|
||||
// this code is duplicated in ArrayToCollection and CollectionToCollection
|
||||
private Class getCollectionImplClass(Class targetClass) {
|
||||
if (targetClass.isInterface()) {
|
||||
if (List.class.equals(targetClass)) {
|
||||
return ArrayList.class;
|
||||
} else if (Set.class.equals(targetClass)) {
|
||||
return LinkedHashSet.class;
|
||||
} else if (SortedSet.class.equals(targetClass)) {
|
||||
return TreeSet.class;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported collection interface [" + targetClass.getName() + "]");
|
||||
}
|
||||
} else {
|
||||
return targetClass;
|
||||
}
|
||||
}
|
||||
|
||||
private ConversionExecutor getElementConverter(Object source, Class targetClass) {
|
||||
if (elementConverter != null) {
|
||||
return elementConverter;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2004-2009 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.core.convert.service;
|
||||
|
||||
import org.springframework.core.convert.converter.SuperConverter;
|
||||
import org.springframework.core.convert.converter.SuperTwoWayConverter;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
class ReverseSuperConverter implements SuperConverter {
|
||||
|
||||
private SuperTwoWayConverter converter;
|
||||
|
||||
public ReverseSuperConverter(SuperTwoWayConverter converter) {
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
public Object convert(Object source, Class targetClass) throws Exception {
|
||||
return converter.convertBack(source, targetClass);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2004-2008 the original author or authors.
|
||||
* Copyright 2004-2009 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.
|
||||
|
|
@ -21,16 +21,15 @@ import org.springframework.core.convert.converter.Converter;
|
|||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
class StaticConversionExecutor implements ConversionExecutor {
|
||||
class StaticConversionExecutor<S, T> implements ConversionExecutor<S, T> {
|
||||
|
||||
private final Class sourceClass;
|
||||
private final Class<S> sourceClass;
|
||||
|
||||
private final Class targetClass;
|
||||
private final Class<T> targetClass;
|
||||
|
||||
private final Converter converter;
|
||||
private final Converter<S, T> converter;
|
||||
|
||||
public StaticConversionExecutor(Class sourceClass, Class targetClass, Converter converter) {
|
||||
public StaticConversionExecutor(Class<S> sourceClass, Class<T> targetClass, Converter<S, T> converter) {
|
||||
Assert.notNull(sourceClass, "The source class is required");
|
||||
Assert.notNull(targetClass, "The target class is required");
|
||||
Assert.notNull(converter, "The converter is required");
|
||||
|
|
@ -39,15 +38,15 @@ class StaticConversionExecutor implements ConversionExecutor {
|
|||
this.converter = converter;
|
||||
}
|
||||
|
||||
public Class getSourceClass() {
|
||||
public Class<S> getSourceClass() {
|
||||
return sourceClass;
|
||||
}
|
||||
|
||||
public Class getTargetClass() {
|
||||
public Class<T> getTargetClass() {
|
||||
return targetClass;
|
||||
}
|
||||
|
||||
public Object execute(Object source) throws ConversionExecutionException {
|
||||
public T execute(S source) throws ConversionExecutionException {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -66,7 +65,7 @@ class StaticConversionExecutor implements ConversionExecutor {
|
|||
if (!(o instanceof StaticConversionExecutor)) {
|
||||
return false;
|
||||
}
|
||||
StaticConversionExecutor other = (StaticConversionExecutor) o;
|
||||
StaticConversionExecutor<?, ?> other = (StaticConversionExecutor<?, ?>) o;
|
||||
return sourceClass.equals(other.sourceClass) && targetClass.equals(other.targetClass);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2004-2008 the original author or authors.
|
||||
* Copyright 2004-2009 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.
|
||||
|
|
@ -21,16 +21,15 @@ import org.springframework.core.convert.converter.SuperConverter;
|
|||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
class StaticSuperConversionExecutor implements ConversionExecutor {
|
||||
class StaticSuperConversionExecutor<S, T> implements ConversionExecutor<S, T> {
|
||||
|
||||
private final Class sourceClass;
|
||||
private final Class<S> sourceClass;
|
||||
|
||||
private final Class targetClass;
|
||||
private final Class<T> targetClass;
|
||||
|
||||
private final SuperConverter converter;
|
||||
private final SuperConverter<S, T> converter;
|
||||
|
||||
public StaticSuperConversionExecutor(Class sourceClass, Class targetClass, SuperConverter converter) {
|
||||
public StaticSuperConversionExecutor(Class<S> sourceClass, Class<T> targetClass, SuperConverter<S, T> converter) {
|
||||
Assert.notNull(sourceClass, "The source class is required");
|
||||
Assert.notNull(targetClass, "The target class is required");
|
||||
Assert.notNull(converter, "The super converter is required");
|
||||
|
|
@ -39,15 +38,15 @@ class StaticSuperConversionExecutor implements ConversionExecutor {
|
|||
this.converter = converter;
|
||||
}
|
||||
|
||||
public Class getSourceClass() {
|
||||
public Class<S> getSourceClass() {
|
||||
return sourceClass;
|
||||
}
|
||||
|
||||
public Class getTargetClass() {
|
||||
public Class<T> getTargetClass() {
|
||||
return targetClass;
|
||||
}
|
||||
|
||||
public Object execute(Object source) throws ConversionExecutionException {
|
||||
public T execute(S source) throws ConversionExecutionException {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -66,7 +65,7 @@ class StaticSuperConversionExecutor implements ConversionExecutor {
|
|||
if (!(o instanceof StaticSuperConversionExecutor)) {
|
||||
return false;
|
||||
}
|
||||
StaticSuperConversionExecutor other = (StaticSuperConversionExecutor) o;
|
||||
StaticSuperConversionExecutor<?, ?> other = (StaticSuperConversionExecutor<?, ?>) o;
|
||||
return sourceClass.equals(other.sourceClass) && targetClass.equals(other.targetClass);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,159 +0,0 @@
|
|||
/*
|
||||
* Copyright 2004-2009 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.core.convert.service;
|
||||
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.core.convert.ConversionExecutor;
|
||||
import org.springframework.core.convert.ConversionExecutorNotFoundException;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.converter.StringToBoolean;
|
||||
|
||||
/**
|
||||
* Test case for the default conversion service.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class DefaultConversionServiceTests extends TestCase {
|
||||
|
||||
ConversionService service = new DefaultConversionService();
|
||||
|
||||
public void testConversionForwardIndex() {
|
||||
ConversionExecutor<String, Integer> executor = service.getConversionExecutor(String.class, Integer.class);
|
||||
Integer three = executor.execute("3");
|
||||
assertEquals(3, three.intValue());
|
||||
}
|
||||
|
||||
public void testConversionReverseIndex() {
|
||||
ConversionExecutor<Integer, String> executor = service.getConversionExecutor(Integer.class, String.class);
|
||||
String threeString = executor.execute(new Integer(3));
|
||||
assertEquals("3", threeString);
|
||||
}
|
||||
|
||||
public void testConversionCompatibleTypes() {
|
||||
ArrayList source = new ArrayList();
|
||||
assertSame(source, service.getConversionExecutor(ArrayList.class, List.class).execute(source));
|
||||
}
|
||||
|
||||
public void testConversionOverrideDefaultConverter() {
|
||||
Converter<String, Boolean> customConverter = new StringToBoolean("ja", "nee");
|
||||
((GenericConversionService) service).addConverter(customConverter);
|
||||
ConversionExecutor<String, Boolean> executor = service.getConversionExecutor(String.class, Boolean.class);
|
||||
assertTrue(executor.execute("ja").booleanValue());
|
||||
}
|
||||
|
||||
public void testConverterLookupTargetClassNotSupported() {
|
||||
try {
|
||||
service.getConversionExecutor(String.class, HashMap.class);
|
||||
fail("Should have thrown an exception");
|
||||
} catch (ConversionExecutorNotFoundException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void testConversionToPrimitive() {
|
||||
DefaultConversionService service = new DefaultConversionService();
|
||||
ConversionExecutor executor = service.getConversionExecutor(String.class, int.class);
|
||||
Integer three = (Integer) executor.execute("3");
|
||||
assertEquals(3, three.intValue());
|
||||
}
|
||||
|
||||
public void testConversionArrayToArray() {
|
||||
ConversionExecutor executor = service.getConversionExecutor(String[].class, Integer[].class);
|
||||
Integer[] result = (Integer[]) executor.execute(new String[] { "1", "2", "3" });
|
||||
assertEquals(new Integer(1), result[0]);
|
||||
assertEquals(new Integer(2), result[1]);
|
||||
assertEquals(new Integer(3), result[2]);
|
||||
}
|
||||
|
||||
public void testConversionArrayToPrimitiveArray() {
|
||||
ConversionExecutor executor = service.getConversionExecutor(String[].class, int[].class);
|
||||
int[] result = (int[]) executor.execute(new String[] { "1", "2", "3" });
|
||||
assertEquals(1, result[0]);
|
||||
assertEquals(2, result[1]);
|
||||
assertEquals(3, result[2]);
|
||||
}
|
||||
|
||||
public void testConversionArrayToList() {
|
||||
ConversionExecutor executor = service.getConversionExecutor(String[].class, List.class);
|
||||
List result = (List) executor.execute(new String[] { "1", "2", "3" });
|
||||
assertEquals("1", result.get(0));
|
||||
assertEquals("2", result.get(1));
|
||||
assertEquals("3", result.get(2));
|
||||
}
|
||||
|
||||
public void testConversionToArray() {
|
||||
ConversionExecutor executor = service.getConversionExecutor(Collection.class, String[].class);
|
||||
List list = new ArrayList();
|
||||
list.add("1");
|
||||
list.add("2");
|
||||
list.add("3");
|
||||
String[] result = (String[]) executor.execute(list);
|
||||
assertEquals("1", result[0]);
|
||||
assertEquals("2", result[1]);
|
||||
assertEquals("3", result[2]);
|
||||
}
|
||||
|
||||
public void testConversionListToArrayWithComponentConversion() {
|
||||
ConversionExecutor executor = service.getConversionExecutor(Collection.class, Integer[].class);
|
||||
List list = new ArrayList();
|
||||
list.add("1");
|
||||
list.add("2");
|
||||
list.add("3");
|
||||
Integer[] result = (Integer[]) executor.execute(list);
|
||||
assertEquals(new Integer(1), result[0]);
|
||||
assertEquals(new Integer(2), result[1]);
|
||||
assertEquals(new Integer(3), result[2]);
|
||||
}
|
||||
|
||||
public void testConversionArrayToConcreteList() {
|
||||
ConversionExecutor executor = service.getConversionExecutor(String[].class, LinkedList.class);
|
||||
LinkedList result = (LinkedList) executor.execute(new String[] { "1", "2", "3" });
|
||||
assertEquals("1", result.get(0));
|
||||
assertEquals("2", result.get(1));
|
||||
assertEquals("3", result.get(2));
|
||||
}
|
||||
|
||||
public void testConversionArrayToAbstractList() {
|
||||
try {
|
||||
service.getConversionExecutor(String[].class, AbstractList.class);
|
||||
} catch (IllegalArgumentException e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void testConversionStringToArray() {
|
||||
ConversionExecutor executor = service.getConversionExecutor(String.class, String[].class);
|
||||
String[] result = (String[]) executor.execute("1,2,3");
|
||||
assertEquals(1, result.length);
|
||||
assertEquals("1,2,3", result[0]);
|
||||
}
|
||||
|
||||
public void testConversionStringToArrayWithElementConversion() {
|
||||
ConversionExecutor executor = service.getConversionExecutor(String.class, Integer[].class);
|
||||
Integer[] result = (Integer[]) executor.execute("123");
|
||||
assertEquals(1, result.length);
|
||||
assertEquals(new Integer(123), result[0]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,253 @@
|
|||
package org.springframework.core.convert.service;
|
||||
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.core.convert.ConversionExecutionException;
|
||||
import org.springframework.core.convert.ConversionExecutor;
|
||||
import org.springframework.core.convert.ConversionExecutorNotFoundException;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.converter.NumberToNumber;
|
||||
import org.springframework.core.convert.converter.StringToEnum;
|
||||
import org.springframework.core.convert.converter.StringToInteger;
|
||||
import org.springframework.core.convert.service.GenericConversionService;
|
||||
|
||||
public class GenericConversionServiceTests extends TestCase {
|
||||
|
||||
private GenericConversionService service = new GenericConversionService();
|
||||
|
||||
public void testExecuteConversion() {
|
||||
service.addConverter(new StringToInteger());
|
||||
assertEquals(new Integer(3), service.executeConversion("3", Integer.class));
|
||||
}
|
||||
|
||||
public void testConverterConversionForwardIndex() {
|
||||
service.addConverter(new StringToInteger());
|
||||
ConversionExecutor executor = service.getConversionExecutor(String.class, Integer.class);
|
||||
Integer three = (Integer) executor.execute("3");
|
||||
assertEquals(3, three.intValue());
|
||||
}
|
||||
|
||||
public void testConverterConversionReverseIndex() {
|
||||
service.addConverter(new StringToInteger());
|
||||
ConversionExecutor executor = service.getConversionExecutor(Integer.class, String.class);
|
||||
String threeString = (String) executor.execute(new Integer(3));
|
||||
assertEquals("3", threeString);
|
||||
}
|
||||
|
||||
public void testConversionExecutorNotFound() {
|
||||
try {
|
||||
service.getConversionExecutor(String.class, Integer.class);
|
||||
fail("Should have thrown an exception");
|
||||
} catch (ConversionExecutorNotFoundException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void testConversionCompatibleTypes() {
|
||||
ArrayList source = new ArrayList();
|
||||
assertSame(source, service.getConversionExecutor(ArrayList.class, List.class).execute(source));
|
||||
}
|
||||
|
||||
public void testConversionExecutorNullArgument() {
|
||||
service.addConverter(new StringToInteger());
|
||||
ConversionExecutor executor = service.getConversionExecutor(String.class, Integer.class);
|
||||
assertNull(executor.execute(null));
|
||||
}
|
||||
|
||||
public void testConversionExecutorWrongTypeArgument() {
|
||||
service.addConverter(new StringToInteger());
|
||||
ConversionExecutor executor = service.getConversionExecutor(Integer.class, String.class);
|
||||
try {
|
||||
executor.execute("BOGUS");
|
||||
fail("Should have failed");
|
||||
} catch (ConversionExecutionException e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void testConverterConversionSuperSourceType() {
|
||||
service.addConverter(new Converter<CharSequence, Integer>() {
|
||||
public Integer convert(CharSequence source) throws Exception {
|
||||
return Integer.valueOf(source.toString());
|
||||
}
|
||||
|
||||
public CharSequence convertBack(Integer target) throws Exception {
|
||||
return target.toString();
|
||||
}
|
||||
});
|
||||
ConversionExecutor executor = service.getConversionExecutor(String.class, Integer.class);
|
||||
Integer result = (Integer) executor.execute("3");
|
||||
assertEquals(new Integer(3), result);
|
||||
}
|
||||
|
||||
public void testConverterConversionNoSuperTargetType() {
|
||||
service.addConverter(new Converter<CharSequence, Number>() {
|
||||
public Integer convert(CharSequence source) throws Exception {
|
||||
return Integer.valueOf(source.toString());
|
||||
}
|
||||
|
||||
public CharSequence convertBack(Number target) throws Exception {
|
||||
return target.toString();
|
||||
}
|
||||
});
|
||||
try {
|
||||
ConversionExecutor executor = service.getConversionExecutor(String.class, Integer.class);
|
||||
fail("Should have failed");
|
||||
} catch (ConversionExecutorNotFoundException e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void testConversionObjectToPrimitive() {
|
||||
service.addConverter(new StringToInteger());
|
||||
ConversionExecutor executor = service.getConversionExecutor(String.class, int.class);
|
||||
Integer three = (Integer) executor.execute("3");
|
||||
assertEquals(3, three.intValue());
|
||||
}
|
||||
|
||||
public void testConversionArrayToArray() {
|
||||
service.addConverter(new StringToInteger());
|
||||
ConversionExecutor executor = service.getConversionExecutor(String[].class, Integer[].class);
|
||||
Integer[] result = (Integer[]) executor.execute(new String[] { "1", "2", "3" });
|
||||
assertEquals(new Integer(1), result[0]);
|
||||
assertEquals(new Integer(2), result[1]);
|
||||
assertEquals(new Integer(3), result[2]);
|
||||
}
|
||||
|
||||
public void testConversionArrayToPrimitiveArray() {
|
||||
service.addConverter(new StringToInteger());
|
||||
ConversionExecutor executor = service.getConversionExecutor(String[].class, int[].class);
|
||||
int[] result = (int[]) executor.execute(new String[] { "1", "2", "3" });
|
||||
assertEquals(1, result[0]);
|
||||
assertEquals(2, result[1]);
|
||||
assertEquals(3, result[2]);
|
||||
}
|
||||
|
||||
public void testConversionArrayToListInterface() {
|
||||
ConversionExecutor executor = service.getConversionExecutor(String[].class, List.class);
|
||||
List result = (List) executor.execute(new String[] { "1", "2", "3" });
|
||||
assertEquals("1", result.get(0));
|
||||
assertEquals("2", result.get(1));
|
||||
assertEquals("3", result.get(2));
|
||||
}
|
||||
|
||||
public void testConversionArrayToListImpl() {
|
||||
ConversionExecutor executor = service.getConversionExecutor(String[].class, LinkedList.class);
|
||||
LinkedList result = (LinkedList) executor.execute(new String[] { "1", "2", "3" });
|
||||
assertEquals("1", result.get(0));
|
||||
assertEquals("2", result.get(1));
|
||||
assertEquals("3", result.get(2));
|
||||
}
|
||||
|
||||
public void testConversionArrayToAbstractList() {
|
||||
try {
|
||||
service.getConversionExecutor(String[].class, AbstractList.class);
|
||||
} catch (IllegalArgumentException e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void testConversionListToArray() {
|
||||
ConversionExecutor executor = service.getConversionExecutor(Collection.class, String[].class);
|
||||
List list = new ArrayList();
|
||||
list.add("1");
|
||||
list.add("2");
|
||||
list.add("3");
|
||||
String[] result = (String[]) executor.execute(list);
|
||||
assertEquals("1", result[0]);
|
||||
assertEquals("2", result[1]);
|
||||
assertEquals("3", result[2]);
|
||||
}
|
||||
|
||||
public void testConversionListToArrayWithComponentConversion() {
|
||||
service.addConverter(new StringToInteger());
|
||||
ConversionExecutor executor = service.getConversionExecutor(Collection.class, Integer[].class);
|
||||
List list = new ArrayList();
|
||||
list.add("1");
|
||||
list.add("2");
|
||||
list.add("3");
|
||||
Integer[] result = (Integer[]) executor.execute(list);
|
||||
assertEquals(new Integer(1), result[0]);
|
||||
assertEquals(new Integer(2), result[1]);
|
||||
assertEquals(new Integer(3), result[2]);
|
||||
}
|
||||
|
||||
public void testConversionObjectToArray() {
|
||||
ConversionExecutor executor = service.getConversionExecutor(String.class, String[].class);
|
||||
String[] result = (String[]) executor.execute("1,2,3");
|
||||
assertEquals(1, result.length);
|
||||
assertEquals("1,2,3", result[0]);
|
||||
}
|
||||
|
||||
public void testConversionObjectToArrayWithElementConversion() {
|
||||
service.addConverter(new StringToInteger());
|
||||
ConversionExecutor executor = service.getConversionExecutor(String.class, Integer[].class);
|
||||
Integer[] result = (Integer[]) executor.execute("123");
|
||||
assertEquals(1, result.length);
|
||||
assertEquals(new Integer(123), result[0]);
|
||||
}
|
||||
|
||||
public static enum FooEnum {
|
||||
BAR
|
||||
}
|
||||
|
||||
public void testSuperConverterConversionForwardIndex() {
|
||||
service.addConverter(new StringToEnum());
|
||||
ConversionExecutor executor = service.getConversionExecutor(String.class, FooEnum.class);
|
||||
assertEquals(FooEnum.BAR, executor.execute("BAR"));
|
||||
}
|
||||
|
||||
public void testSuperTwoWayConverterConversionReverseIndex() {
|
||||
service.addConverter(new StringToEnum());
|
||||
ConversionExecutor executor = service.getConversionExecutor(FooEnum.class, String.class);
|
||||
assertEquals("BAR", executor.execute(FooEnum.BAR));
|
||||
}
|
||||
|
||||
public void testSuperConverterConversionNotConvertibleAbstractType() {
|
||||
service.addConverter(new StringToEnum());
|
||||
ConversionExecutor executor = service.getConversionExecutor(String.class, Enum.class);
|
||||
try {
|
||||
executor.execute("WHATEV");
|
||||
fail("Should have failed");
|
||||
} catch (ConversionExecutionException e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void testSuperConverterConversionNotConvertibleAbstractType2() {
|
||||
service.addConverter(new NumberToNumber());
|
||||
Number customNumber = new Number() {
|
||||
@Override
|
||||
public double doubleValue() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float floatValue() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int intValue() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long longValue() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
ConversionExecutor executor = service.getConversionExecutor(Integer.class, customNumber.getClass());
|
||||
try {
|
||||
executor.execute(3);
|
||||
fail("Should have failed");
|
||||
} catch (ConversionExecutionException e) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue