提交 3a7b4bf1 编写于 作者: K Keith Donald

basic conversion service impl; still need super converters, custom converters,...

basic conversion service impl; still need super converters, custom converters, and conversion of generic collection elements
上级 c1f3ec0c
/*
* 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.lang.reflect.Array;
import org.springframework.core.convert.ConversionExecutor;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.converter.SuperConverter;
/**
* Special one-way converter that converts from a source array to a target array. Supports type conversion of the
* individual array elements; for example, the ability to convert a String[] to an Integer[]. Mainly used internally by
* {@link ConversionService} implementations.
*
* @author Keith Donald
*/
@SuppressWarnings("unchecked")
class ArrayToArray implements SuperConverter {
private ConversionService conversionService;
private ConversionExecutor elementConverter;
/**
* Creates a new array-to-array converter.
* @param conversionService the service to use to lookup conversion executors for individual array elements
* dynamically
*/
public ArrayToArray(ConversionService conversionService) {
this.conversionService = conversionService;
}
/**
* Creates a new array-to-array converter.
* @param elementConverter a specific conversion executor to use to convert elements in the source array to elements
* in the target array.
*/
public ArrayToArray(ConversionExecutor 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 {
if (source == null) {
return null;
}
Class sourceComponentType = source.getClass().getComponentType();
Class targetComponentType = targetClass.getComponentType();
int length = Array.getLength(source);
Object targetArray = Array.newInstance(targetComponentType, length);
ConversionExecutor converter = getElementConverter(sourceComponentType, targetComponentType);
for (int i = 0; i < length; i++) {
Object value = Array.get(source, i);
Array.set(targetArray, i, converter.execute(value));
}
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;
} else {
return conversionService.getConversionExecutor(sourceComponentType, targetComponentType);
}
}
}
/*
* 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.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;
/**
* Special converter that converts from a source array to a target collection. Supports the selection of an
* "approximate" collection implementation when a target collection interface such as <code>List.class</code> is
* specified. Supports type conversion of array elements when a concrete parameterized collection class is provided,
* such as <code>IntegerList<Integer>.class</code>.
*
* Note that type erasure prevents arbitrary access to generic collection element type information at runtime,
* preventing the ability to convert elements for collections declared as properties.
*
* Mainly used internally by {@link ConversionService} implementations.
*
* @author Keith Donald
*/
@SuppressWarnings("unchecked")
class ArrayToCollection implements SuperConverter {
private ConversionService conversionService;
private ConversionExecutor elementConverter;
/**
* Creates a new array to collection converter.
* @param conversionService the conversion service to use to lookup the converter to apply to array elements added
* to the target collection
*/
public ArrayToCollection(ConversionService conversionService) {
this.conversionService = conversionService;
}
/**
* Creates a new array to collection converter.
* @param elementConverter A specific converter to use on array elements when adding them to the target collection
*/
public ArrayToCollection(ConversionExecutor elementConverter) {
this.elementConverter = elementConverter;
}
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);
ConversionExecutor converter = getArrayElementConverter(source, targetClass);
int length = Array.getLength(source);
for (int i = 0; i < length; i++) {
Object value = Array.get(source, i);
if (converter != null) {
value = converter.execute(value);
}
collection.add(value);
}
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());
int i = 0;
for (Iterator it = collection.iterator(); it.hasNext(); i++) {
Object value = it.next();
if (value != null) {
ConversionExecutor converter;
if (elementConverter != null) {
converter = elementConverter;
} else {
converter = conversionService.getConversionExecutor(value.getClass(), sourceClass
.getComponentType());
}
value = converter.execute(value);
}
Array.set(array, i, value);
}
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;
} else {
Class elementType = GenericCollectionTypeResolver.getCollectionType(targetClass);
if (elementType != null) {
Class componentType = source.getClass().getComponentType();
return conversionService.getConversionExecutor(componentType, elementType);
}
return null;
}
}
}
\ No newline at end of file
/*
* 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.lang.reflect.Array;
import java.util.Collection;
import java.util.Iterator;
import org.springframework.core.convert.ConversionExecutor;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.converter.SuperConverter;
/**
* Special converter that converts from a source array to a target collection. Supports the selection of an
* "approximate" collection implementation when a target collection interface such as <code>List.class</code> is
* specified. Supports type conversion of array elements when a concrete parameterized collection class is provided,
* such as <code>IntegerList<Integer>.class</code>.
*
* Note that type erasure prevents arbitrary access to generic collection element type information at runtime,
* preventing the ability to convert elements for collections declared as properties.
*
* Mainly used internally by {@link ConversionService} implementations.
*
* @author Keith Donald
*/
@SuppressWarnings("unchecked")
class CollectionToArray implements SuperConverter {
private ConversionService conversionService;
private ConversionExecutor elementConverter;
/**
* Creates a new array to collection converter.
* @param conversionService the conversion service to use to lookup the converter to apply to array elements added
* to the target collection
*/
public CollectionToArray(ConversionService conversionService) {
this.conversionService = conversionService;
}
/**
* Creates a new array to collection converter.
* @param elementConverter A specific converter to use on array elements when adding them to the target collection
*/
public CollectionToArray(ConversionExecutor elementConverter) {
this.elementConverter = elementConverter;
}
public Object convert(Object source, Class targetClass) throws Exception {
Collection collection = (Collection) source;
Object array = Array.newInstance(targetClass.getComponentType(), collection.size());
int i = 0;
for (Iterator it = collection.iterator(); it.hasNext(); i++) {
Object value = it.next();
if (value != null) {
ConversionExecutor converter;
if (elementConverter != null) {
converter = elementConverter;
} else {
converter = conversionService.getConversionExecutor(value.getClass(), targetClass
.getComponentType());
}
value = converter.execute(value);
}
Array.set(array, i, value);
}
return array;
}
public Object convertBack(Object target) throws Exception {
throw new UnsupportedOperationException("Should never be called");
}
}
\ No newline at end of file
/*
* 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.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;
/**
* A converter that can convert from one collection type to another.
*
* @author Keith Donald
*/
@SuppressWarnings("unchecked")
class CollectionToCollection implements SuperConverter {
private ConversionService conversionService;
private ConversionExecutor elementConverter;
/**
* Creates a new collection-to-collection converter
* @param conversionService the conversion service to use to convert collection elements to add to the target
* collection
*/
public CollectionToCollection(ConversionService conversionService) {
this.conversionService = conversionService;
}
/**
* Creates a new collection-to-collection converter
* @param elementConverter a specific converter to use to convert collection elements added to the target collection
*/
public CollectionToCollection(ConversionExecutor elementConverter) {
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);
ConversionExecutor elementConverter = getElementConverter(source, targetClass);
Collection sourceCollection = (Collection) source;
Iterator it = sourceCollection.iterator();
while (it.hasNext()) {
Object value = it.next();
if (elementConverter != null) {
value = elementConverter.execute(value);
}
targetCollection.add(value);
}
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;
} else {
Class elementType = GenericCollectionTypeResolver.getCollectionType(targetClass);
if (elementType != null) {
Class componentType = source.getClass().getComponentType();
return conversionService.getConversionExecutor(componentType, elementType);
}
return null;
}
}
}
\ No newline at end of file
/*
* 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.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.Locale;
import org.springframework.core.convert.converter.NumberToNumber;
import org.springframework.core.convert.converter.StringToBigDecimal;
import org.springframework.core.convert.converter.StringToBigInteger;
import org.springframework.core.convert.converter.StringToBoolean;
import org.springframework.core.convert.converter.StringToByte;
import org.springframework.core.convert.converter.StringToCharacter;
import org.springframework.core.convert.converter.StringToDouble;
import org.springframework.core.convert.converter.StringToEnum;
import org.springframework.core.convert.converter.StringToFloat;
import org.springframework.core.convert.converter.StringToInteger;
import org.springframework.core.convert.converter.StringToLocale;
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
* a number of standard Java types like Class, Number, Boolean and so on.
*
* @author Keith Donald
*/
public class DefaultConversionService extends GenericConversionService {
/**
* Creates a new default conversion service, installing the default converters.
*/
public DefaultConversionService() {
addDefaultConverters();
addDefaultAliases();
}
/**
* Add all default converters to the conversion service.
*/
protected void addDefaultConverters() {
addConverter(new StringToByte());
addConverter(new StringToBoolean());
addConverter(new StringToCharacter());
addConverter(new StringToShort());
addConverter(new StringToInteger());
addConverter(new StringToLong());
addConverter(new StringToFloat());
addConverter(new StringToDouble());
addConverter(new StringToBigInteger());
addConverter(new StringToBigDecimal());
addConverter(new StringToLocale());
addConverter(new StringToEnum());
addConverter(new NumberToNumber());
addConverter(new ObjectToCollection(this));
addConverter(new CollectionToCollection(this));
}
protected void addDefaultAliases() {
addAlias("string", String.class);
addAlias("byte", Byte.class);
addAlias("boolean", Boolean.class);
addAlias("char", Character.class);
addAlias("short", Short.class);
addAlias("int", Integer.class);
addAlias("long", Long.class);
addAlias("float", Float.class);
addAlias("double", Double.class);
addAlias("bigInteger", BigInteger.class);
addAlias("bigDecimal", BigDecimal.class);
addAlias("locale", Locale.class);
addAlias("enum", Enum.class);
addAlias("date", Date.class);
}
}
\ No newline at end of file
/*
* 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.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.convert.ConversionException;
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.SuperConverter;
import org.springframework.util.Assert;
/**
* Base implementation of a conversion service. Initially empty, e.g. no converters are registered by default.
*
* @author Keith Donald
*/
@SuppressWarnings("unchecked")
public class GenericConversionService implements ConversionService {
/**
* 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 sourceClassConverters = new HashMap();
/**
* Indexes classes by well-known aliases.
*/
private final Map aliasMap = new HashMap<String, Class<?>>();
/**
* An optional parent conversion service.
*/
private ConversionService parent;
/**
* Returns the parent of this conversion service. Could be null.
*/
public ConversionService getParent() {
return parent;
}
/**
* Set the parent of this conversion service. This is optional.
*/
public void setParent(ConversionService parent) {
this.parent = parent;
}
/**
* Register the Converter with this conversion service.
* @param converter the converter to register
*/
public void addConverter(Converter converter) {
List typeInfo = getTypeInfo(converter);
Class sourceClass = (Class) typeInfo.get(0);
Class targetClass = (Class) typeInfo.get(1);
// index forward
Map sourceMap = getSourceMap(sourceClass);
sourceMap.put(targetClass, converter);
// index reverse
sourceMap = getSourceMap(targetClass);
sourceMap.put(sourceClass, new ReverseConverter(converter));
}
/**
* Register the SuperConverter with this conversion service.
* @param converter the super converter to register
*/
public void addConverter(SuperConverter converter) {
// TODO
}
/**
* Add a convenient alias for the target type. {@link #getClassForAlias(String)} can then be used to lookup the type
* given the alias.
* @see #getClassForAlias(String)
*/
public void addAlias(String alias, Class targetType) {
aliasMap.put(alias, targetType);
}
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)
throws ConversionExecutorNotFoundException {
Assert.notNull(sourceClass, "The source class to convert from is required");
Assert.notNull(targetClass, "The target class to convert to is required");
if (targetClass.isAssignableFrom(sourceClass)) {
return new StaticConversionExecutor(sourceClass, targetClass, new NoOpConverter());
}
sourceClass = convertToWrapperClassIfNecessary(sourceClass);
targetClass = convertToWrapperClassIfNecessary(targetClass);
// special handling for arrays since they are not indexable classes
if (sourceClass.isArray()) {
if (targetClass.isArray()) {
return new StaticSuperConversionExecutor(sourceClass, targetClass, new ArrayToArray(this));
} else if (Collection.class.isAssignableFrom(targetClass)) {
if (!targetClass.isInterface() && Modifier.isAbstract(targetClass.getModifiers())) {
throw new IllegalArgumentException("Conversion target class [" + targetClass.getName()
+ "] is invalid; cannot convert to abstract collection types--"
+ "request an interface or concrete implementation instead");
}
return new StaticSuperConversionExecutor(sourceClass, targetClass, new ArrayToCollection(this));
}
}
if (targetClass.isArray()) {
if (Collection.class.isAssignableFrom(sourceClass)) {
return new StaticSuperConversionExecutor(sourceClass, targetClass, new CollectionToArray(this));
} else {
return new StaticSuperConversionExecutor(sourceClass, targetClass, new ObjectToArray(this));
}
}
Converter converter = findRegisteredConverter(sourceClass, targetClass);
if (converter != null) {
// we found a converter
return new StaticConversionExecutor(sourceClass, targetClass, converter);
} else {
if (parent != null) {
// try the parent
return parent.getConversionExecutor(sourceClass, targetClass);
} else {
throw new ConversionExecutorNotFoundException(sourceClass, targetClass,
"No ConversionExecutor found for converting from sourceClass [" + sourceClass.getName()
+ "] to target class [" + targetClass.getName() + "]");
}
}
}
public ConversionExecutor getConversionExecutor(String converterId, Class sourceClass, Class targetClass)
throws ConversionExecutorNotFoundException {
throw new UnsupportedOperationException("Not yet implemented");
}
public Class getClassForAlias(String name) throws IllegalArgumentException {
Class clazz = (Class) aliasMap.get(name);
if (clazz != null) {
return clazz;
} else {
if (parent != null) {
return parent.getClassForAlias(name);
} else {
return null;
}
}
}
// internal helpers
private List getTypeInfo(Converter converter) {
List typeInfo = new ArrayList(2);
Class classToIntrospect = converter.getClass();
while (classToIntrospect != null) {
Type[] genericInterfaces = converter.getClass().getGenericInterfaces();
for (Type genericInterface : genericInterfaces) {
if (genericInterface instanceof ParameterizedType) {
ParameterizedType parameterizedInterface = (ParameterizedType) genericInterface;
if (Converter.class.equals(parameterizedInterface.getRawType())) {
Type s = parameterizedInterface.getActualTypeArguments()[0];
Type t = parameterizedInterface.getActualTypeArguments()[1];
typeInfo.add(getParameterClass(s, converter.getClass()));
typeInfo.add(getParameterClass(t, converter.getClass()));
}
}
}
classToIntrospect = classToIntrospect.getSuperclass();
}
return typeInfo;
}
private Class<?> getParameterClass(Type parameterType, Class<?> converterClass) {
if (parameterType instanceof TypeVariable) {
parameterType = GenericTypeResolver.resolveTypeVariable((TypeVariable<?>) parameterType, converterClass);
}
if (parameterType instanceof Class) {
return (Class<?>) parameterType;
}
// when would this happen?
return null;
}
private Map getSourceMap(Class sourceClass) {
Map sourceMap = (Map) sourceClassConverters.get(sourceClass);
if (sourceMap == null) {
sourceMap = new HashMap<Class<?>, Converter<?, ?>>();
sourceClassConverters.put(sourceClass, sourceMap);
}
return sourceMap;
}
private Class convertToWrapperClassIfNecessary(Class targetType) {
if (targetType.isPrimitive()) {
if (targetType.equals(int.class)) {
return Integer.class;
} else if (targetType.equals(short.class)) {
return Short.class;
} else if (targetType.equals(long.class)) {
return Long.class;
} else if (targetType.equals(float.class)) {
return Float.class;
} else if (targetType.equals(double.class)) {
return Double.class;
} else if (targetType.equals(byte.class)) {
return Byte.class;
} else if (targetType.equals(boolean.class)) {
return Boolean.class;
} else if (targetType.equals(char.class)) {
return Character.class;
} else {
throw new IllegalStateException("Should never happen - primitive type is not a primitive?");
}
} else {
return targetType;
}
}
private Converter findRegisteredConverter(Class sourceClass, Class targetClass) {
if (sourceClass.isInterface()) {
LinkedList classQueue = new LinkedList();
classQueue.addFirst(sourceClass);
while (!classQueue.isEmpty()) {
Class currentClass = (Class) classQueue.removeLast();
Map<Class, Converter> sourceTargetConverters = findConvertersForSource(currentClass);
Converter converter = findTargetConverter(sourceTargetConverters, targetClass);
if (converter != null) {
return converter;
}
Class[] interfaces = currentClass.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
classQueue.addFirst(interfaces[i]);
}
}
Map objectConverters = findConvertersForSource(Object.class);
return findTargetConverter(objectConverters, targetClass);
} else {
LinkedList classQueue = new LinkedList();
classQueue.addFirst(sourceClass);
while (!classQueue.isEmpty()) {
Class currentClass = (Class) classQueue.removeLast();
Map sourceTargetConverters = findConvertersForSource(currentClass);
Converter converter = findTargetConverter(sourceTargetConverters, targetClass);
if (converter != null) {
return converter;
}
if (currentClass.getSuperclass() != null) {
classQueue.addFirst(currentClass.getSuperclass());
}
Class[] interfaces = currentClass.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
classQueue.addFirst(interfaces[i]);
}
}
return null;
}
}
private Map findConvertersForSource(Class sourceClass) {
Map sourceConverters = (Map) sourceClassConverters.get(sourceClass);
return sourceConverters != null ? sourceConverters : Collections.emptyMap();
}
private Converter findTargetConverter(Map sourceTargetConverters, Class targetClass) {
if (sourceTargetConverters.isEmpty()) {
return null;
}
return (Converter) sourceTargetConverters.get(targetClass);
}
}
\ No newline at end of file
/*
* 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.Converter;
/**
* Package private converter that is a "no op".
*
* @author Keith Donald
*/
@SuppressWarnings("unchecked")
class NoOpConverter implements Converter {
public Object convert(Object source) throws Exception {
return source;
}
public Object convertBack(Object target) throws Exception {
return target;
}
}
\ No newline at end of file
/*
* 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.lang.reflect.Array;
import org.springframework.core.convert.ConversionExecutor;
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
* {@link ConversionService} implementations.
*
* @author Keith Donald
*/
@SuppressWarnings("unchecked")
class ObjectToArray implements SuperConverter {
private ConversionService conversionService;
private ConversionExecutor elementConverter;
/**
* Creates a new object to array converter.
* @param conversionService the conversion service to resolve the converter to use to convert the object added to
* the target array.
*/
public ObjectToArray(ConversionService conversionService) {
this.conversionService = conversionService;
}
/**
* Creates a new object to array converter.
* @param elementConverter a specific converter to use to convert the object added to the target array.
*/
public ObjectToArray(ConversionExecutor 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 {
Class componentType = targetClass.getComponentType();
Object array = Array.newInstance(componentType, 1);
ConversionExecutor converter;
if (elementConverter != null) {
converter = elementConverter;
} else {
converter = conversionService.getConversionExecutor(source.getClass(), componentType);
}
Array.set(array, 0, converter.execute(source));
return array;
}
public Object convertBack(Object target) throws Exception {
throw new UnsupportedOperationException("Not supported");
}
}
\ No newline at end of file
/*
* 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.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;
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 collection. Supports type conversion of the
* individual element with parameterized collection implementations.
*
* @author Keith Donald
*/
@SuppressWarnings("unchecked")
class ObjectToCollection implements SuperConverter {
private ConversionService conversionService;
private ConversionExecutor elementConverter;
/**
* Creates a new object to collection converter
* @param conversionService the conversion service to lookup the converter to use to convert an object when adding
* it to a target collection
*/
public ObjectToCollection(ConversionService conversionService) {
this.conversionService = conversionService;
}
/**
* Creates a new object to collection converter
* @param elementConverter a specific converter to execute on an object when adding it to a target collection
*/
public ObjectToCollection(ConversionExecutor elementConverter) {
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);
Collection collection = (Collection) constructor.newInstance((Object[]) null);
ConversionExecutor converter = getElementConverter(source, targetClass);
Object value;
if (converter != null) {
value = converter.execute(source);
} else {
value = source;
}
collection.add(value);
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;
} else {
Class elementType = GenericCollectionTypeResolver.getCollectionType(targetClass);
if (elementType != null) {
Class componentType = source.getClass().getComponentType();
return conversionService.getConversionExecutor(componentType, elementType);
}
return null;
}
}
}
\ No newline at end of file
/*
* 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.Converter;
@SuppressWarnings("unchecked")
class ReverseConverter implements Converter {
private Converter converter;
public ReverseConverter(Converter converter) {
this.converter = converter;
}
public Object convert(Object source) throws Exception {
return converter.convertBack(source);
}
public Object convertBack(Object target) throws Exception {
throw new IllegalStateException("Should not be called");
}
}
/*
* Copyright 2004-2008 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.ConversionExecutionException;
import org.springframework.core.convert.ConversionExecutor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.style.ToStringCreator;
import org.springframework.util.Assert;
@SuppressWarnings("unchecked")
class StaticConversionExecutor implements ConversionExecutor {
private final Class sourceClass;
private final Class targetClass;
private final Converter converter;
public StaticConversionExecutor(Class sourceClass, Class targetClass, Converter converter) {
Assert.notNull(sourceClass, "The source class is required");
Assert.notNull(targetClass, "The target class is required");
Assert.notNull(converter, "The converter is required");
this.sourceClass = sourceClass;
this.targetClass = targetClass;
this.converter = converter;
}
public Class getSourceClass() {
return sourceClass;
}
public Class getTargetClass() {
return targetClass;
}
public Object execute(Object source) throws ConversionExecutionException {
if (source == null) {
return null;
}
if (!sourceClass.isInstance(source)) {
throw new ConversionExecutionException(source, getSourceClass(), getTargetClass(), "Source object "
+ source + " to convert is expected to be an instance of [" + getSourceClass().getName() + "]");
}
try {
return converter.convert(source);
} catch (Exception e) {
throw new ConversionExecutionException(source, getSourceClass(), getTargetClass(), e);
}
}
public boolean equals(Object o) {
if (!(o instanceof StaticConversionExecutor)) {
return false;
}
StaticConversionExecutor other = (StaticConversionExecutor) o;
return sourceClass.equals(other.sourceClass) && targetClass.equals(other.targetClass);
}
public int hashCode() {
return sourceClass.hashCode() + targetClass.hashCode();
}
public String toString() {
return new ToStringCreator(this).append("sourceClass", sourceClass).append("targetClass", targetClass)
.toString();
}
}
\ No newline at end of file
/*
* Copyright 2004-2008 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.ConversionExecutionException;
import org.springframework.core.convert.ConversionExecutor;
import org.springframework.core.convert.converter.SuperConverter;
import org.springframework.core.style.ToStringCreator;
import org.springframework.util.Assert;
@SuppressWarnings("unchecked")
class StaticSuperConversionExecutor implements ConversionExecutor {
private final Class sourceClass;
private final Class targetClass;
private final SuperConverter converter;
public StaticSuperConversionExecutor(Class sourceClass, Class targetClass, SuperConverter 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");
this.sourceClass = sourceClass;
this.targetClass = targetClass;
this.converter = converter;
}
public Class getSourceClass() {
return sourceClass;
}
public Class getTargetClass() {
return targetClass;
}
public Object execute(Object source) throws ConversionExecutionException {
if (source == null) {
return null;
}
if (!sourceClass.isInstance(source)) {
throw new ConversionExecutionException(source, getSourceClass(), getTargetClass(), "Source object "
+ source + " to convert is expected to be an instance of [" + getSourceClass().getName() + "]");
}
try {
return converter.convert(source, targetClass);
} catch (Exception e) {
throw new ConversionExecutionException(source, getSourceClass(), getTargetClass(), e);
}
}
public boolean equals(Object o) {
if (!(o instanceof StaticSuperConversionExecutor)) {
return false;
}
StaticSuperConversionExecutor other = (StaticSuperConversionExecutor) o;
return sourceClass.equals(other.sourceClass) && targetClass.equals(other.targetClass);
}
public int hashCode() {
return sourceClass.hashCode() + targetClass.hashCode();
}
public String toString() {
return new ToStringCreator(this).append("sourceClass", sourceClass).append("targetClass", targetClass)
.toString();
}
}
\ No newline at end of file
<html>
<body>
<p>
ConversionService implementation.
</p>
</body>
</html>
\ No newline at end of file
/*
* 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]);
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册