14 changed files with 1452 additions and 0 deletions
@ -0,0 +1,91 @@
@@ -0,0 +1,91 @@
|
||||
/* |
||||
* 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); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,147 @@
@@ -0,0 +1,147 @@
|
||||
/* |
||||
* 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; |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,88 @@
@@ -0,0 +1,88 @@
|
||||
/* |
||||
* 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"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,123 @@
@@ -0,0 +1,123 @@
|
||||
/* |
||||
* 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; |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,91 @@
@@ -0,0 +1,91 @@
|
||||
/* |
||||
* 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); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,313 @@
@@ -0,0 +1,313 @@
|
||||
/* |
||||
* 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); |
||||
} |
||||
} |
||||
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
/* |
||||
* 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; |
||||
} |
||||
} |
||||
@ -0,0 +1,79 @@
@@ -0,0 +1,79 @@
|
||||
/* |
||||
* 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"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,121 @@
@@ -0,0 +1,121 @@
|
||||
/* |
||||
* 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; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,36 @@
@@ -0,0 +1,36 @@
|
||||
/* |
||||
* 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"); |
||||
} |
||||
} |
||||
@ -0,0 +1,81 @@
@@ -0,0 +1,81 @@
|
||||
/* |
||||
* 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(); |
||||
} |
||||
} |
||||
@ -0,0 +1,81 @@
@@ -0,0 +1,81 @@
|
||||
/* |
||||
* 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(); |
||||
} |
||||
} |
||||
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
<html> |
||||
<body> |
||||
<p> |
||||
ConversionService implementation. |
||||
</p> |
||||
</body> |
||||
</html> |
||||
@ -0,0 +1,159 @@
@@ -0,0 +1,159 @@
|
||||
/* |
||||
* 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]); |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue