super converter implementation
This commit is contained in:
parent
b04009357a
commit
0ef0ff60f0
|
|
@ -16,7 +16,7 @@
|
||||||
package org.springframework.core.convert;
|
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
|
* target output. Encapsulates knowledge about how to convert source objects to a specific target type using a specific
|
||||||
* converter.
|
* converter.
|
||||||
*
|
*
|
||||||
|
|
@ -25,20 +25,19 @@ package org.springframework.core.convert;
|
||||||
public interface ConversionExecutor<S, T> {
|
public interface ConversionExecutor<S, T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the source class of conversions performed by this executor.
|
* The type this executor converts from.
|
||||||
* @return the source class
|
|
||||||
*/
|
*/
|
||||||
public Class<S> getSourceClass();
|
public Class<S> getSourceClass();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the target class of conversions performed by this executor.
|
* The type this executor converts to.
|
||||||
* @return the target class
|
s */
|
||||||
*/
|
|
||||||
public Class<T> getTargetClass();
|
public Class<T> getTargetClass();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the conversion for the provided source object.
|
* Convert the source to T.
|
||||||
* @param source the source object to convert
|
* @param source the source to convert
|
||||||
|
* @throws ConversionExecutionException if an exception occurs during type conversion
|
||||||
*/
|
*/
|
||||||
public T execute(S source) throws ConversionExecutionException;
|
public T execute(S source) throws ConversionExecutionException;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ package org.springframework.core.convert;
|
||||||
public interface ConversionService {
|
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 source the source to convert from (may be null)
|
||||||
* @param targetClass the target class to convert to
|
* @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
|
* @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;
|
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
|
* @param converterId the id of the custom converter, which must be registered with this conversion service and
|
||||||
* capable of converting to the targetClass
|
* capable of converting to the targetClass
|
||||||
* @param source the source to convert from (may be null)
|
* @param source the source to convert from (may be null)
|
||||||
|
|
@ -54,7 +54,7 @@ public interface ConversionService {
|
||||||
throws ConversionExecutorNotFoundException, ConversionException;
|
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.
|
* 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 sourceClass the source class to convert from (required)
|
||||||
* @param targetClass the target class to convert to (required)
|
* @param targetClass the target class to convert to (required)
|
||||||
|
|
@ -65,9 +65,8 @@ public interface ConversionService {
|
||||||
throws ConversionExecutorNotFoundException;
|
throws ConversionExecutorNotFoundException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a ConversionExecutor that uses a custom converter to capable convert objects from <code>sourceClass</code> to
|
* Get a ConversionExecutor that that converts objects from S to T with a custom converter.
|
||||||
* <code>targetClass</code>. The returned ConversionExecutor is thread-safe and may safely be cached for use in
|
* The returned ConversionExecutor is thread-safe and may safely be cached for use in client code.
|
||||||
* client code.
|
|
||||||
* @param converterId the id of the custom converter, which must be registered with this conversion service and
|
* @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)
|
* capable of converting from sourceClass to targetClass (required)
|
||||||
* @param sourceClass the source class to convert from (required)
|
* @param sourceClass the source class to convert from (required)
|
||||||
|
|
@ -79,9 +78,8 @@ public interface ConversionService {
|
||||||
Class<T> targetClass) throws ConversionExecutorNotFoundException;
|
Class<T> targetClass) throws ConversionExecutorNotFoundException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lookup a class by its well-known alias. For example, <code>long</code> for <code>java.lang.Long</code>
|
* Get a class by its alias.
|
||||||
* @param alias the class alias
|
* @return the class, or <code>null</code> if no such alias exists
|
||||||
* @return the class, or <code>null</code> if no alias exists
|
|
||||||
*/
|
*/
|
||||||
public Class<?> getClassForAlias(String alias);
|
public Class<?> getClassForAlias(String alias);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import org.springframework.core.convert.ConversionException;
|
||||||
import org.springframework.core.convert.ConversionService;
|
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>
|
* <p>
|
||||||
* Implementations of this interface are thread-safe and can be shared. Converters are typically registered with and
|
* Implementations of this interface are thread-safe and can be shared. Converters are typically registered with and
|
||||||
* accessed through a {@link ConversionService}.
|
* accessed through a {@link ConversionService}.
|
||||||
|
|
@ -29,7 +29,7 @@ import org.springframework.core.convert.ConversionService;
|
||||||
public interface Converter<S, T> {
|
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
|
* @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
|
* @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
|
* @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;
|
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
|
* @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
|
* @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
|
* @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 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);
|
return NumberUtils.convertNumberToTargetClass(source, targetClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Number convertBack(Number target) throws Exception {
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -16,19 +16,19 @@
|
||||||
package org.springframework.core.convert.converter;
|
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
|
* @author Keith Donald
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@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);
|
return Enum.valueOf(targetClass, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String convertBack(Enum target) throws Exception {
|
public <RS extends String> RS convertBack(Enum target, Class<RS> sourceClass) throws Exception {
|
||||||
return target.name();
|
return (RS) target.name();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -19,8 +19,7 @@ import org.springframework.core.convert.ConversionException;
|
||||||
import org.springframework.core.convert.ConversionService;
|
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
|
* A super converter converts a source object of type S to a target of class hierarchy T.
|
||||||
* 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.
|
|
||||||
* <p>
|
* <p>
|
||||||
* Implementations of this interface are thread-safe and can be shared. Converters are typically registered with and
|
* Implementations of this interface are thread-safe and can be shared. Converters are typically registered with and
|
||||||
* accessed through a {@link ConversionService}.
|
* accessed through a {@link ConversionService}.
|
||||||
|
|
@ -30,25 +29,14 @@ import org.springframework.core.convert.ConversionService;
|
||||||
public interface SuperConverter<S, T> {
|
public interface SuperConverter<S, T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert the source S to an instance of AT.
|
* Convert the source of type S to an instance of type RT.
|
||||||
* @param source the source object to convert, which must be an instance of S
|
* @param source the source object to convert, whose class must be equal to or a subclass of S
|
||||||
* @param actualTargetClass the actual target class to convert to (AT), which must be equal to or a specialization
|
* @param targetClass the requested target class to convert to (RT), which must be equal to T or extend from T
|
||||||
* of T.
|
* @return the converted object, which must be an instance of RT
|
||||||
* @return the converted object, which must be an instance of AT
|
|
||||||
* @throws Exception an exception occurred performing the conversion; may be any checked exception, the conversion
|
* @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
|
* system will handle wrapping the failure in a {@link ConversionException} that provides a consistent type
|
||||||
* conversion error context
|
* conversion error context
|
||||||
*/
|
*/
|
||||||
public <AT extends T> AT convert(S source, Class<AT> actualTargetClass) throws Exception;
|
public <RT extends T> RT convert(S source, Class<RT> targetClass) 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;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -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;
|
this.elementConverter = elementConverter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class getSourceClass() {
|
|
||||||
return Object[].class;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class getSuperTargetClass() {
|
|
||||||
return Object[].class;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object convert(Object source, Class targetClass) throws Exception {
|
public Object convert(Object source, Class targetClass) throws Exception {
|
||||||
if (source == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Class sourceComponentType = source.getClass().getComponentType();
|
Class sourceComponentType = source.getClass().getComponentType();
|
||||||
Class targetComponentType = targetClass.getComponentType();
|
Class targetComponentType = targetClass.getComponentType();
|
||||||
int length = Array.getLength(source);
|
int length = Array.getLength(source);
|
||||||
|
|
@ -77,10 +66,6 @@ class ArrayToArray implements SuperConverter {
|
||||||
return targetArray;
|
return targetArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object convertBack(Object target) throws Exception {
|
|
||||||
throw new UnsupportedOperationException("Not supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
private ConversionExecutor getElementConverter(Class sourceComponentType, Class targetComponentType) {
|
private ConversionExecutor getElementConverter(Class sourceComponentType, Class targetComponentType) {
|
||||||
if (elementConverter != null) {
|
if (elementConverter != null) {
|
||||||
return elementConverter;
|
return elementConverter;
|
||||||
|
|
|
||||||
|
|
@ -17,19 +17,13 @@ package org.springframework.core.convert.service;
|
||||||
|
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
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.GenericCollectionTypeResolver;
|
||||||
import org.springframework.core.convert.ConversionExecutor;
|
import org.springframework.core.convert.ConversionExecutor;
|
||||||
import org.springframework.core.convert.ConversionService;
|
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
|
* 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
|
* @author Keith Donald
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
class ArrayToCollection implements SuperConverter {
|
class ArrayToCollection implements SuperTwoWayConverter {
|
||||||
|
|
||||||
private ConversionService conversionService;
|
private ConversionService conversionService;
|
||||||
|
|
||||||
|
|
@ -69,11 +63,8 @@ class ArrayToCollection implements SuperConverter {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object convert(Object source, Class targetClass) throws Exception {
|
public Object convert(Object source, Class targetClass) throws Exception {
|
||||||
if (source == null) {
|
Class implClass = CollectionConversionUtils.getImpl(targetClass);
|
||||||
return null;
|
Constructor constructor = implClass.getConstructor((Class[]) null);
|
||||||
}
|
|
||||||
Class collectionImplClass = getCollectionImplClass(targetClass);
|
|
||||||
Constructor constructor = collectionImplClass.getConstructor((Class[]) null);
|
|
||||||
Collection collection = (Collection) constructor.newInstance((Object[]) null);
|
Collection collection = (Collection) constructor.newInstance((Object[]) null);
|
||||||
ConversionExecutor converter = getArrayElementConverter(source, targetClass);
|
ConversionExecutor converter = getArrayElementConverter(source, targetClass);
|
||||||
int length = Array.getLength(source);
|
int length = Array.getLength(source);
|
||||||
|
|
@ -87,16 +78,10 @@ class ArrayToCollection implements SuperConverter {
|
||||||
return collection;
|
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 {
|
public Object convertBack(Object target, Class sourceClass) throws Exception {
|
||||||
if (target == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Collection collection = (Collection) target;
|
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;
|
int i = 0;
|
||||||
for (Iterator it = collection.iterator(); it.hasNext(); i++) {
|
for (Iterator it = collection.iterator(); it.hasNext(); i++) {
|
||||||
Object value = it.next();
|
Object value = it.next();
|
||||||
|
|
@ -105,8 +90,7 @@ class ArrayToCollection implements SuperConverter {
|
||||||
if (elementConverter != null) {
|
if (elementConverter != null) {
|
||||||
converter = elementConverter;
|
converter = elementConverter;
|
||||||
} else {
|
} else {
|
||||||
converter = conversionService.getConversionExecutor(value.getClass(), sourceClass
|
converter = conversionService.getConversionExecutor(value.getClass(), elementType);
|
||||||
.getComponentType());
|
|
||||||
}
|
}
|
||||||
value = converter.execute(value);
|
value = converter.execute(value);
|
||||||
}
|
}
|
||||||
|
|
@ -115,22 +99,6 @@ class ArrayToCollection implements SuperConverter {
|
||||||
return array;
|
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) {
|
private ConversionExecutor getArrayElementConverter(Object source, Class targetClass) {
|
||||||
if (elementConverter != null) {
|
if (elementConverter != null) {
|
||||||
return elementConverter;
|
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;
|
package org.springframework.core.convert.service;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
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.GenericCollectionTypeResolver;
|
||||||
import org.springframework.core.convert.ConversionExecutor;
|
import org.springframework.core.convert.ConversionExecutor;
|
||||||
|
|
@ -35,7 +29,7 @@ import org.springframework.core.convert.converter.SuperConverter;
|
||||||
* @author Keith Donald
|
* @author Keith Donald
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
class CollectionToCollection implements SuperConverter {
|
class CollectionToCollection implements SuperConverter<Collection, Collection> {
|
||||||
|
|
||||||
private ConversionService conversionService;
|
private ConversionService conversionService;
|
||||||
|
|
||||||
|
|
@ -58,21 +52,10 @@ class CollectionToCollection implements SuperConverter {
|
||||||
this.elementConverter = elementConverter;
|
this.elementConverter = elementConverter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class getSourceClass() {
|
public Collection convert(Collection source, Class targetClass) throws Exception {
|
||||||
return Collection.class;
|
Class implClass = CollectionConversionUtils.getImpl(targetClass);
|
||||||
}
|
Collection targetCollection = (Collection) implClass.getConstructor((Class[]) null)
|
||||||
|
.newInstance((Object[]) null);
|
||||||
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);
|
|
||||||
ConversionExecutor elementConverter = getElementConverter(source, targetClass);
|
ConversionExecutor elementConverter = getElementConverter(source, targetClass);
|
||||||
Collection sourceCollection = (Collection) source;
|
Collection sourceCollection = (Collection) source;
|
||||||
Iterator it = sourceCollection.iterator();
|
Iterator it = sourceCollection.iterator();
|
||||||
|
|
@ -86,27 +69,6 @@ class CollectionToCollection implements SuperConverter {
|
||||||
return targetCollection;
|
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) {
|
private ConversionExecutor getElementConverter(Object source, Class targetClass) {
|
||||||
if (elementConverter != null) {
|
if (elementConverter != null) {
|
||||||
return elementConverter;
|
return elementConverter;
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ import org.springframework.core.convert.converter.StringToLong;
|
||||||
import org.springframework.core.convert.converter.StringToShort;
|
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.
|
* a number of standard Java types like Class, Number, Boolean and so on.
|
||||||
*
|
*
|
||||||
* @author Keith Donald
|
* @author Keith Donald
|
||||||
|
|
@ -67,6 +67,7 @@ public class DefaultConversionService extends GenericConversionService {
|
||||||
addConverter(new StringToLocale());
|
addConverter(new StringToLocale());
|
||||||
addConverter(new StringToEnum());
|
addConverter(new StringToEnum());
|
||||||
addConverter(new NumberToNumber());
|
addConverter(new NumberToNumber());
|
||||||
|
// TODO probably don't allow these to be customized, or at least make public
|
||||||
addConverter(new ObjectToCollection(this));
|
addConverter(new ObjectToCollection(this));
|
||||||
addConverter(new CollectionToCollection(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.ConversionService;
|
||||||
import org.springframework.core.convert.converter.Converter;
|
import org.springframework.core.convert.converter.Converter;
|
||||||
import org.springframework.core.convert.converter.SuperConverter;
|
import org.springframework.core.convert.converter.SuperConverter;
|
||||||
|
import org.springframework.core.convert.converter.SuperTwoWayConverter;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base implementation of a conversion service. Initially empty, e.g. no converters are registered by default.
|
* 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
|
* @author Keith Donald
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
|
@ -50,6 +53,12 @@ public class GenericConversionService implements ConversionService {
|
||||||
*/
|
*/
|
||||||
private final Map sourceClassConverters = new HashMap();
|
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.
|
* Indexes classes by well-known aliases.
|
||||||
*/
|
*/
|
||||||
|
|
@ -95,7 +104,17 @@ public class GenericConversionService implements ConversionService {
|
||||||
* @param converter the super converter to register
|
* @param converter the super converter to register
|
||||||
*/
|
*/
|
||||||
public void addConverter(SuperConverter converter) {
|
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,
|
public Object executeConversion(Object source, Class targetClass) throws ConversionExecutorNotFoundException,
|
||||||
ConversionException {
|
ConversionException {
|
||||||
if (source != null) {
|
|
||||||
ConversionExecutor conversionExecutor = getConversionExecutor(source.getClass(), targetClass);
|
ConversionExecutor conversionExecutor = getConversionExecutor(source.getClass(), targetClass);
|
||||||
return conversionExecutor.execute(source);
|
return conversionExecutor.execute(source);
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object executeConversion(String converterId, Object source, Class targetClass)
|
public Object executeConversion(String converterId, Object source, Class targetClass)
|
||||||
throws ConversionExecutorNotFoundException, ConversionException {
|
throws ConversionExecutorNotFoundException, ConversionException {
|
||||||
if (source != null) {
|
|
||||||
ConversionExecutor conversionExecutor = getConversionExecutor(converterId, source.getClass(), targetClass);
|
ConversionExecutor conversionExecutor = getConversionExecutor(converterId, source.getClass(), targetClass);
|
||||||
return conversionExecutor.execute(source);
|
return conversionExecutor.execute(source);
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConversionExecutor getConversionExecutor(Class sourceClass, Class targetClass)
|
public ConversionExecutor getConversionExecutor(Class sourceClass, Class targetClass)
|
||||||
|
|
@ -151,7 +162,8 @@ public class GenericConversionService implements ConversionService {
|
||||||
}
|
}
|
||||||
if (targetClass.isArray()) {
|
if (targetClass.isArray()) {
|
||||||
if (Collection.class.isAssignableFrom(sourceClass)) {
|
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 {
|
} else {
|
||||||
return new StaticSuperConversionExecutor(sourceClass, targetClass, new ObjectToArray(this));
|
return new StaticSuperConversionExecutor(sourceClass, targetClass, new ObjectToArray(this));
|
||||||
}
|
}
|
||||||
|
|
@ -161,6 +173,10 @@ public class GenericConversionService implements ConversionService {
|
||||||
// we found a converter
|
// we found a converter
|
||||||
return new StaticConversionExecutor(sourceClass, targetClass, converter);
|
return new StaticConversionExecutor(sourceClass, targetClass, converter);
|
||||||
} else {
|
} else {
|
||||||
|
SuperConverter superConverter = findRegisteredSuperConverter(sourceClass, targetClass);
|
||||||
|
if (superConverter != null) {
|
||||||
|
return new StaticSuperConversionExecutor(sourceClass, targetClass, superConverter);
|
||||||
|
}
|
||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
// try the parent
|
// try the parent
|
||||||
return parent.getConversionExecutor(sourceClass, targetClass);
|
return parent.getConversionExecutor(sourceClass, targetClass);
|
||||||
|
|
@ -192,7 +208,7 @@ public class GenericConversionService implements ConversionService {
|
||||||
|
|
||||||
// internal helpers
|
// internal helpers
|
||||||
|
|
||||||
private List getTypeInfo(Converter converter) {
|
private List getTypeInfo(Object converter) {
|
||||||
List typeInfo = new ArrayList(2);
|
List typeInfo = new ArrayList(2);
|
||||||
Class classToIntrospect = converter.getClass();
|
Class classToIntrospect = converter.getClass();
|
||||||
while (classToIntrospect != null) {
|
while (classToIntrospect != null) {
|
||||||
|
|
@ -200,7 +216,8 @@ public class GenericConversionService implements ConversionService {
|
||||||
for (Type genericInterface : genericInterfaces) {
|
for (Type genericInterface : genericInterfaces) {
|
||||||
if (genericInterface instanceof ParameterizedType) {
|
if (genericInterface instanceof ParameterizedType) {
|
||||||
ParameterizedType parameterizedInterface = (ParameterizedType) genericInterface;
|
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 s = parameterizedInterface.getActualTypeArguments()[0];
|
||||||
Type t = parameterizedInterface.getActualTypeArguments()[1];
|
Type t = parameterizedInterface.getActualTypeArguments()[1];
|
||||||
typeInfo.add(getParameterClass(s, converter.getClass()));
|
typeInfo.add(getParameterClass(s, converter.getClass()));
|
||||||
|
|
@ -213,12 +230,12 @@ public class GenericConversionService implements ConversionService {
|
||||||
return typeInfo;
|
return typeInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Class<?> getParameterClass(Type parameterType, Class<?> converterClass) {
|
private Class getParameterClass(Type parameterType, Class converterClass) {
|
||||||
if (parameterType instanceof TypeVariable) {
|
if (parameterType instanceof TypeVariable) {
|
||||||
parameterType = GenericTypeResolver.resolveTypeVariable((TypeVariable<?>) parameterType, converterClass);
|
parameterType = GenericTypeResolver.resolveTypeVariable((TypeVariable) parameterType, converterClass);
|
||||||
}
|
}
|
||||||
if (parameterType instanceof Class) {
|
if (parameterType instanceof Class) {
|
||||||
return (Class<?>) parameterType;
|
return (Class) parameterType;
|
||||||
}
|
}
|
||||||
// when would this happen?
|
// when would this happen?
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -227,12 +244,21 @@ public class GenericConversionService implements ConversionService {
|
||||||
private Map getSourceMap(Class sourceClass) {
|
private Map getSourceMap(Class sourceClass) {
|
||||||
Map sourceMap = (Map) sourceClassConverters.get(sourceClass);
|
Map sourceMap = (Map) sourceClassConverters.get(sourceClass);
|
||||||
if (sourceMap == null) {
|
if (sourceMap == null) {
|
||||||
sourceMap = new HashMap<Class<?>, Converter<?, ?>>();
|
sourceMap = new HashMap();
|
||||||
sourceClassConverters.put(sourceClass, sourceMap);
|
sourceClassConverters.put(sourceClass, sourceMap);
|
||||||
}
|
}
|
||||||
return 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) {
|
private Class convertToWrapperClassIfNecessary(Class targetType) {
|
||||||
if (targetType.isPrimitive()) {
|
if (targetType.isPrimitive()) {
|
||||||
if (targetType.equals(int.class)) {
|
if (targetType.equals(int.class)) {
|
||||||
|
|
@ -265,8 +291,8 @@ public class GenericConversionService implements ConversionService {
|
||||||
classQueue.addFirst(sourceClass);
|
classQueue.addFirst(sourceClass);
|
||||||
while (!classQueue.isEmpty()) {
|
while (!classQueue.isEmpty()) {
|
||||||
Class currentClass = (Class) classQueue.removeLast();
|
Class currentClass = (Class) classQueue.removeLast();
|
||||||
Map<Class, Converter> sourceTargetConverters = findConvertersForSource(currentClass);
|
Map converters = getConvertersForSource(currentClass);
|
||||||
Converter converter = findTargetConverter(sourceTargetConverters, targetClass);
|
Converter converter = getConverter(converters, targetClass);
|
||||||
if (converter != null) {
|
if (converter != null) {
|
||||||
return converter;
|
return converter;
|
||||||
}
|
}
|
||||||
|
|
@ -275,15 +301,15 @@ public class GenericConversionService implements ConversionService {
|
||||||
classQueue.addFirst(interfaces[i]);
|
classQueue.addFirst(interfaces[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Map objectConverters = findConvertersForSource(Object.class);
|
Map objectConverters = getConvertersForSource(Object.class);
|
||||||
return findTargetConverter(objectConverters, targetClass);
|
return getConverter(objectConverters, targetClass);
|
||||||
} else {
|
} else {
|
||||||
LinkedList classQueue = new LinkedList();
|
LinkedList classQueue = new LinkedList();
|
||||||
classQueue.addFirst(sourceClass);
|
classQueue.addFirst(sourceClass);
|
||||||
while (!classQueue.isEmpty()) {
|
while (!classQueue.isEmpty()) {
|
||||||
Class currentClass = (Class) classQueue.removeLast();
|
Class currentClass = (Class) classQueue.removeLast();
|
||||||
Map sourceTargetConverters = findConvertersForSource(currentClass);
|
Map converters = getConvertersForSource(currentClass);
|
||||||
Converter converter = findTargetConverter(sourceTargetConverters, targetClass);
|
Converter converter = getConverter(converters, targetClass);
|
||||||
if (converter != null) {
|
if (converter != null) {
|
||||||
return converter;
|
return converter;
|
||||||
}
|
}
|
||||||
|
|
@ -299,15 +325,98 @@ public class GenericConversionService implements ConversionService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map findConvertersForSource(Class sourceClass) {
|
private Map getConvertersForSource(Class sourceClass) {
|
||||||
Map sourceConverters = (Map) sourceClassConverters.get(sourceClass);
|
Map converters = (Map) sourceClassConverters.get(sourceClass);
|
||||||
return sourceConverters != null ? sourceConverters : Collections.emptyMap();
|
return converters != null ? converters : Collections.emptyMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Converter findTargetConverter(Map sourceTargetConverters, Class targetClass) {
|
private Converter getConverter(Map converters, Class targetClass) {
|
||||||
if (sourceTargetConverters.isEmpty()) {
|
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 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;
|
import org.springframework.core.convert.converter.Converter;
|
||||||
|
|
||||||
/**
|
|
||||||
* Package private converter that is a "no op".
|
|
||||||
*
|
|
||||||
* @author Keith Donald
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
class NoOpConverter implements Converter {
|
class NoOpConverter implements Converter {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import org.springframework.core.convert.ConversionService;
|
||||||
import org.springframework.core.convert.converter.SuperConverter;
|
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.
|
* {@link ConversionService} implementations.
|
||||||
*
|
*
|
||||||
* @author Keith Donald
|
* @author Keith Donald
|
||||||
|
|
@ -51,14 +51,6 @@ class ObjectToArray implements SuperConverter {
|
||||||
this.elementConverter = elementConverter;
|
this.elementConverter = elementConverter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class getSourceClass() {
|
|
||||||
return Object.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class getSuperTargetClass() {
|
|
||||||
return Object[].class;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object convert(Object source, Class targetClass) throws Exception {
|
public Object convert(Object source, Class targetClass) throws Exception {
|
||||||
Class componentType = targetClass.getComponentType();
|
Class componentType = targetClass.getComponentType();
|
||||||
Object array = Array.newInstance(componentType, 1);
|
Object array = Array.newInstance(componentType, 1);
|
||||||
|
|
@ -72,8 +64,4 @@ class ObjectToArray implements SuperConverter {
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object convertBack(Object target) throws Exception {
|
|
||||||
throw new UnsupportedOperationException("Not supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -16,13 +16,7 @@
|
||||||
package org.springframework.core.convert.service;
|
package org.springframework.core.convert.service;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
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.GenericCollectionTypeResolver;
|
||||||
import org.springframework.core.convert.ConversionExecutor;
|
import org.springframework.core.convert.ConversionExecutor;
|
||||||
|
|
@ -36,7 +30,7 @@ import org.springframework.core.convert.converter.SuperConverter;
|
||||||
* @author Keith Donald
|
* @author Keith Donald
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
class ObjectToCollection implements SuperConverter {
|
class ObjectToCollection implements SuperConverter<Object, Collection> {
|
||||||
|
|
||||||
private ConversionService conversionService;
|
private ConversionService conversionService;
|
||||||
|
|
||||||
|
|
@ -59,20 +53,9 @@ class ObjectToCollection implements SuperConverter {
|
||||||
this.elementConverter = elementConverter;
|
this.elementConverter = elementConverter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class getSourceClass() {
|
public Collection convert(Object source, Class targetClass) throws Exception {
|
||||||
return Object.class;
|
Class implClass = CollectionConversionUtils.getImpl(targetClass);
|
||||||
}
|
Constructor constructor = implClass.getConstructor((Class[]) null);
|
||||||
|
|
||||||
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);
|
|
||||||
Collection collection = (Collection) constructor.newInstance((Object[]) null);
|
Collection collection = (Collection) constructor.newInstance((Object[]) null);
|
||||||
ConversionExecutor converter = getElementConverter(source, targetClass);
|
ConversionExecutor converter = getElementConverter(source, targetClass);
|
||||||
Object value;
|
Object value;
|
||||||
|
|
@ -85,27 +68,6 @@ class ObjectToCollection implements SuperConverter {
|
||||||
return collection;
|
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) {
|
private ConversionExecutor getElementConverter(Object source, Class targetClass) {
|
||||||
if (elementConverter != null) {
|
if (elementConverter != null) {
|
||||||
return elementConverter;
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.core.style.ToStringCreator;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
class StaticConversionExecutor<S, T> implements ConversionExecutor<S, T> {
|
||||||
class StaticConversionExecutor implements ConversionExecutor {
|
|
||||||
|
|
||||||
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(sourceClass, "The source class is required");
|
||||||
Assert.notNull(targetClass, "The target class is required");
|
Assert.notNull(targetClass, "The target class is required");
|
||||||
Assert.notNull(converter, "The converter is required");
|
Assert.notNull(converter, "The converter is required");
|
||||||
|
|
@ -39,15 +38,15 @@ class StaticConversionExecutor implements ConversionExecutor {
|
||||||
this.converter = converter;
|
this.converter = converter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class getSourceClass() {
|
public Class<S> getSourceClass() {
|
||||||
return sourceClass;
|
return sourceClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class getTargetClass() {
|
public Class<T> getTargetClass() {
|
||||||
return targetClass;
|
return targetClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object execute(Object source) throws ConversionExecutionException {
|
public T execute(S source) throws ConversionExecutionException {
|
||||||
if (source == null) {
|
if (source == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
@ -66,7 +65,7 @@ class StaticConversionExecutor implements ConversionExecutor {
|
||||||
if (!(o instanceof StaticConversionExecutor)) {
|
if (!(o instanceof StaticConversionExecutor)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
StaticConversionExecutor other = (StaticConversionExecutor) o;
|
StaticConversionExecutor<?, ?> other = (StaticConversionExecutor<?, ?>) o;
|
||||||
return sourceClass.equals(other.sourceClass) && targetClass.equals(other.targetClass);
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.core.style.ToStringCreator;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
class StaticSuperConversionExecutor<S, T> implements ConversionExecutor<S, T> {
|
||||||
class StaticSuperConversionExecutor implements ConversionExecutor {
|
|
||||||
|
|
||||||
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(sourceClass, "The source class is required");
|
||||||
Assert.notNull(targetClass, "The target class is required");
|
Assert.notNull(targetClass, "The target class is required");
|
||||||
Assert.notNull(converter, "The super converter is required");
|
Assert.notNull(converter, "The super converter is required");
|
||||||
|
|
@ -39,15 +38,15 @@ class StaticSuperConversionExecutor implements ConversionExecutor {
|
||||||
this.converter = converter;
|
this.converter = converter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class getSourceClass() {
|
public Class<S> getSourceClass() {
|
||||||
return sourceClass;
|
return sourceClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class getTargetClass() {
|
public Class<T> getTargetClass() {
|
||||||
return targetClass;
|
return targetClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object execute(Object source) throws ConversionExecutionException {
|
public T execute(S source) throws ConversionExecutionException {
|
||||||
if (source == null) {
|
if (source == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
@ -66,7 +65,7 @@ class StaticSuperConversionExecutor implements ConversionExecutor {
|
||||||
if (!(o instanceof StaticSuperConversionExecutor)) {
|
if (!(o instanceof StaticSuperConversionExecutor)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
StaticSuperConversionExecutor other = (StaticSuperConversionExecutor) o;
|
StaticSuperConversionExecutor<?, ?> other = (StaticSuperConversionExecutor<?, ?>) o;
|
||||||
return sourceClass.equals(other.sourceClass) && targetClass.equals(other.targetClass);
|
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