diff --git a/spring-binding/.settings/org.eclipse.jdt.core.prefs b/spring-binding/.settings/org.eclipse.jdt.core.prefs
index 5aafbc8d..f53c1ef9 100644
--- a/spring-binding/.settings/org.eclipse.jdt.core.prefs
+++ b/spring-binding/.settings/org.eclipse.jdt.core.prefs
@@ -1,4 +1,4 @@
-#Tue Aug 12 14:24:16 EDT 2008
+#Thu Feb 12 13:53:33 EST 2009
eclipse.preferences.version=1
org.eclipse.jdt.core.codeComplete.argumentPrefixes=
org.eclipse.jdt.core.codeComplete.argumentSuffixes=
@@ -9,22 +9,22 @@ org.eclipse.jdt.core.codeComplete.localSuffixes=
org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.4
+org.eclipse.jdt.core.compiler.compliance=1.5
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.doc.comment.support=enabled
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
-org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
org.eclipse.jdt.core.compiler.problem.deprecation=warning
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
@@ -79,7 +79,7 @@ org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=di
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
-org.eclipse.jdt.core.compiler.source=1.3
+org.eclipse.jdt.core.compiler.source=1.5
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToArray.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToArray.java
index 68ceb3cc..91219df5 100644
--- a/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToArray.java
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToArray.java
@@ -31,6 +31,8 @@ public class ArrayToArray implements Converter {
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
@@ -39,6 +41,10 @@ public class ArrayToArray implements Converter {
this.conversionService = conversionService;
}
+ public ArrayToArray(ConversionExecutor elementConverter) {
+ this.elementConverter = elementConverter;
+ }
+
public Class getSourceClass() {
return Object[].class;
}
@@ -55,12 +61,19 @@ public class ArrayToArray implements Converter {
Class targetComponentType = targetClass.getComponentType();
int length = Array.getLength(source);
Object targetArray = Array.newInstance(targetComponentType, length);
- ConversionExecutor converter = conversionService
- .getConversionExecutor(sourceComponentType, targetComponentType);
+ 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;
}
+
+ private ConversionExecutor getElementConverter(Class sourceComponentType, Class targetComponentType) {
+ if (elementConverter != null) {
+ return elementConverter;
+ } else {
+ return conversionService.getConversionExecutor(sourceComponentType, targetComponentType);
+ }
+ }
}
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToCollection.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToCollection.java
index 73672df0..140f7c63 100644
--- a/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToCollection.java
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToCollection.java
@@ -32,7 +32,7 @@ import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.JdkVersion;
/**
- * Special one-way converter that converts from a source array to a target collection. Supports the selection of an
+ * Special converter that converts from a source array to a target collection. Supports the selection of an
* "approximate" collection implementation when a target collection interface such as List.class is
* specified. Supports type conversion of array elements when a concrete parameterized collection class is provided,
* such as IntegerList.class.
@@ -48,10 +48,16 @@ public class ArrayToCollection implements TwoWayConverter {
private ConversionService conversionService;
+ private ConversionExecutor elementConverter;
+
public ArrayToCollection(ConversionService conversionService) {
this.conversionService = conversionService;
}
+ public ArrayToCollection(ConversionExecutor elementConverter) {
+ this.elementConverter = elementConverter;
+ }
+
public Class getSourceClass() {
return Object[].class;
}
@@ -67,7 +73,7 @@ public class ArrayToCollection implements TwoWayConverter {
Class collectionImplClass = getCollectionImplClass(targetClass);
Constructor constructor = collectionImplClass.getConstructor(null);
Collection collection = (Collection) constructor.newInstance(null);
- ConversionExecutor converter = getElementConverter(source, targetClass);
+ ConversionExecutor converter = getArrayElementConverter(source, targetClass);
int length = Array.getLength(source);
for (int i = 0; i < length; i++) {
Object value = Array.get(source, i);
@@ -114,15 +120,19 @@ public class ArrayToCollection implements TwoWayConverter {
}
}
- private ConversionExecutor getElementConverter(Object source, Class targetClass) {
- if (JdkVersion.isAtLeastJava15()) {
- Class elementType = GenericCollectionTypeResolver.getCollectionType(targetClass);
- if (elementType != null) {
- Class componentType = source.getClass().getComponentType();
- return conversionService.getConversionExecutor(componentType, elementType);
+ private ConversionExecutor getArrayElementConverter(Object source, Class targetClass) {
+ if (elementConverter != null) {
+ return elementConverter;
+ } else {
+ if (JdkVersion.isAtLeastJava15()) {
+ Class elementType = GenericCollectionTypeResolver.getCollectionType(targetClass);
+ if (elementType != null) {
+ Class componentType = source.getClass().getComponentType();
+ return conversionService.getConversionExecutor(componentType, elementType);
+ }
}
+ return null;
}
- return null;
}
}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/service/DefaultConversionService.java b/spring-binding/src/main/java/org/springframework/binding/convert/service/DefaultConversionService.java
index 3dd48b78..04810f18 100644
--- a/spring-binding/src/main/java/org/springframework/binding/convert/service/DefaultConversionService.java
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/service/DefaultConversionService.java
@@ -20,6 +20,7 @@ import java.math.BigInteger;
import java.util.Date;
import java.util.Locale;
+import org.springframework.binding.convert.converters.CollectionToCollection;
import org.springframework.binding.convert.converters.NumberToNumber;
import org.springframework.binding.convert.converters.ObjectToCollection;
import org.springframework.binding.convert.converters.StringToBigDecimal;
@@ -72,8 +73,9 @@ public class DefaultConversionService extends GenericConversionService {
addConverter(new StringToLocale());
addConverter(new StringToDate());
addConverter(new StringToLabeledEnum());
- addConverter(new ObjectToCollection(this));
addConverter(new NumberToNumber());
+ addConverter(new ObjectToCollection(this));
+ addConverter(new CollectionToCollection(this));
if (ClassUtils.isPresent("java.lang.Enum", this.getClass().getClassLoader())) {
addConverter(new StringToEnum());
}
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/service/GenericConversionService.java b/spring-binding/src/main/java/org/springframework/binding/convert/service/GenericConversionService.java
index 106b0b9b..c8ab4e9a 100644
--- a/spring-binding/src/main/java/org/springframework/binding/convert/service/GenericConversionService.java
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/service/GenericConversionService.java
@@ -130,6 +130,7 @@ public class GenericConversionService implements ConversionService {
if (targetClass.isAssignableFrom(sourceClass)) {
return new StaticConversionExecutor(sourceClass, targetClass, new NoOpConverter(sourceClass, targetClass));
}
+ // special handling for arrays since they are not indexable classes
if (sourceClass.isArray()) {
if (targetClass.isArray()) {
return new StaticConversionExecutor(sourceClass, targetClass, new ArrayToArray(this));
@@ -183,6 +184,66 @@ public class GenericConversionService implements ConversionService {
}
sourceClass = convertToWrapperClassIfNecessary(sourceClass);
targetClass = convertToWrapperClassIfNecessary(targetClass);
+ if (sourceClass.isArray()) {
+ Class sourceComponentType = sourceClass.getComponentType();
+ if (targetClass.isArray()) {
+ Class targetComponentType = targetClass.getComponentType();
+ if (converter.getSourceClass().isAssignableFrom(sourceComponentType)) {
+ if (!converter.getTargetClass().isAssignableFrom(targetComponentType)) {
+ throw new ConversionExecutorNotFoundException(sourceClass, targetClass,
+ "Custom ConversionExecutor with id '" + id + "' cannot convert from array of type ["
+ + sourceComponentType + "]; to an array of type [" + targetComponentType + "]");
+ }
+ ConversionExecutor elementConverter = new StaticConversionExecutor(sourceComponentType,
+ targetComponentType, converter);
+ return new StaticConversionExecutor(sourceClass, targetClass, new ArrayToArray(elementConverter));
+ } else if (converter.getTargetClass().isAssignableFrom(sourceComponentType)
+ && converter instanceof TwoWayConverter) {
+ TwoWayConverter twoWay = (TwoWayConverter) converter;
+ ConversionExecutor elementConverter = new StaticConversionExecutor(sourceComponentType,
+ targetComponentType, new ReverseConverter(twoWay));
+ return new StaticConversionExecutor(sourceClass, targetClass, new ArrayToArray(elementConverter));
+ } else {
+ throw new ConversionExecutorNotFoundException(sourceClass, targetClass,
+ "Custom ConversionExecutor with id '" + id + "' cannot convert from array of type ["
+ + sourceComponentType + "]; to an array of type [" + targetComponentType + "]");
+ }
+ } else if (Collection.class.isAssignableFrom(targetClass)) {
+ // type erasure has prevented us from getting the concrete type, this is best we can do for now
+ Class targetComponentType = converter.getTargetClass();
+ if (converter.getSourceClass().isAssignableFrom(sourceComponentType)) {
+ if (!converter.getTargetClass().isAssignableFrom(targetComponentType)) {
+ throw new ConversionExecutorNotFoundException(sourceClass, targetClass,
+ "Custom ConversionExecutor with id '" + id + "' cannot convert from array of type ["
+ + sourceComponentType + "]; to collection of type [" + targetComponentType
+ + "]");
+ }
+ ConversionExecutor elementConverter = new StaticConversionExecutor(sourceComponentType,
+ targetComponentType, converter);
+ return new StaticConversionExecutor(sourceClass, targetClass, new ArrayToCollection(
+ elementConverter));
+ } else if (converter.getTargetClass().isAssignableFrom(sourceComponentType)
+ && converter instanceof TwoWayConverter) {
+ TwoWayConverter twoWay = (TwoWayConverter) converter;
+ ConversionExecutor elementConverter = new StaticConversionExecutor(sourceComponentType,
+ targetComponentType, new ReverseConverter(twoWay));
+ return new StaticConversionExecutor(sourceClass, targetClass, new ArrayToCollection(
+ elementConverter));
+ } else {
+ throw new ConversionExecutorNotFoundException(sourceClass, targetClass,
+ "Custom ConversionExecutor with id '" + id + "' cannot convert from array of type ["
+ + sourceComponentType + "]; to collection of type [" + targetComponentType + "]");
+ }
+ }
+ }
+ if (targetClass.isArray()) {
+ if (Collection.class.isAssignableFrom(sourceClass)) {
+ // type erasure limits us here as well
+ throw new UnsupportedOperationException("Not yet implemented");
+ } else {
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+ }
if (converter.getSourceClass().isAssignableFrom(sourceClass)) {
if (!converter.getTargetClass().isAssignableFrom(targetClass)) {
throw new ConversionExecutorNotFoundException(sourceClass, targetClass,
diff --git a/spring-binding/src/test/java/org/springframework/binding/convert/service/DefaultConversionServiceTests.java b/spring-binding/src/test/java/org/springframework/binding/convert/service/DefaultConversionServiceTests.java
index 9d69bc6e..ff7a4b61 100644
--- a/spring-binding/src/test/java/org/springframework/binding/convert/service/DefaultConversionServiceTests.java
+++ b/spring-binding/src/test/java/org/springframework/binding/convert/service/DefaultConversionServiceTests.java
@@ -22,6 +22,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
@@ -168,6 +169,34 @@ public class DefaultConversionServiceTests extends TestCase {
}
}
+ public void testRegisterCustomConverterArrayToArray() {
+ DefaultConversionService service = new DefaultConversionService();
+ service.addConverter("princy", new CustomTwoWayConverter());
+ ConversionExecutor executor = service.getConversionExecutor("princy", String[].class, Principal[].class);
+ Principal[] p = (Principal[]) executor.execute(new String[] { "princy1", "princy2" });
+ assertEquals("princy1", p[0].getName());
+ assertEquals("princy2", p[1].getName());
+ }
+
+ public void testRegisterCustomConverterArrayToArrayReverse() {
+ DefaultConversionService service = new DefaultConversionService();
+ service.addConverter("princy", new CustomTwoWayConverter());
+ ConversionExecutor executor = service.getConversionExecutor("princy", Principal[].class, String[].class);
+ final Principal princy1 = new Principal() {
+ public String getName() {
+ return "princy1";
+ }
+ };
+ final Principal princy2 = new Principal() {
+ public String getName() {
+ return "princy2";
+ }
+ };
+ String[] p = (String[]) executor.execute(new Principal[] { princy1, princy2 });
+ assertEquals("princy1", p[0]);
+ assertEquals("princy2", p[1]);
+ }
+
public void testConversionPrimitive() {
DefaultConversionService service = new DefaultConversionService();
ConversionExecutor executor = service.getConversionExecutor(String.class, int.class);
@@ -175,7 +204,7 @@ public class DefaultConversionServiceTests extends TestCase {
assertEquals(3, three.intValue());
}
- public void testArrayConversion() {
+ public void testArrayToArrayConversion() {
DefaultConversionService service = new DefaultConversionService();
ConversionExecutor executor = service.getConversionExecutor(String[].class, Integer[].class);
Integer[] result = (Integer[]) executor.execute(new String[] { "1", "2", "3" });
@@ -184,7 +213,7 @@ public class DefaultConversionServiceTests extends TestCase {
assertEquals(new Integer(3), result[2]);
}
- public void testPrimitiveArrayConversion() {
+ public void testArrayToArrayPrimitiveConversion() {
DefaultConversionService service = new DefaultConversionService();
ConversionExecutor executor = service.getConversionExecutor(String[].class, int[].class);
int[] result = (int[]) executor.execute(new String[] { "1", "2", "3" });
@@ -193,7 +222,7 @@ public class DefaultConversionServiceTests extends TestCase {
assertEquals(3, result[2]);
}
- public void testArrayListConversion() {
+ public void testArrayToListConversion() {
DefaultConversionService service = new DefaultConversionService();
ConversionExecutor executor = service.getConversionExecutor(String[].class, List.class);
List result = (List) executor.execute(new String[] { "1", "2", "3" });
@@ -202,7 +231,7 @@ public class DefaultConversionServiceTests extends TestCase {
assertEquals("3", result.get(2));
}
- public void testListArrayConversion() {
+ public void testListToArrayConversion() {
DefaultConversionService service = new DefaultConversionService();
ConversionExecutor executor = service.getConversionExecutor(Collection.class, String[].class);
List list = new ArrayList();
@@ -215,7 +244,20 @@ public class DefaultConversionServiceTests extends TestCase {
assertEquals("3", result[2]);
}
- public void testListArrayConversionWithComponentConversion() {
+ public void testSetToListConversion() {
+ DefaultConversionService service = new DefaultConversionService();
+ ConversionExecutor executor = service.getConversionExecutor(Set.class, List.class);
+ Set set = new LinkedHashSet();
+ set.add("1");
+ set.add("2");
+ set.add("3");
+ List result = (List) executor.execute(set);
+ assertEquals("1", result.get(0));
+ assertEquals("2", result.get(1));
+ assertEquals("3", result.get(2));
+ }
+
+ public void testListToArrayConversionWithComponentConversion() {
DefaultConversionService service = new DefaultConversionService();
ConversionExecutor executor = service.getConversionExecutor(Collection.class, Integer[].class);
List list = new ArrayList();
@@ -228,7 +270,7 @@ public class DefaultConversionServiceTests extends TestCase {
assertEquals(new Integer(3), result[2]);
}
- public void testArrayLinkedListConversion() {
+ public void testArrayToLinkedListConversion() {
DefaultConversionService service = new DefaultConversionService();
ConversionExecutor executor = service.getConversionExecutor(String[].class, LinkedList.class);
LinkedList result = (LinkedList) executor.execute(new String[] { "1", "2", "3" });
@@ -246,7 +288,7 @@ public class DefaultConversionServiceTests extends TestCase {
}
}
- public void testToArrayConversion() {
+ public void testStringToArrayConversion() {
DefaultConversionService service = new DefaultConversionService();
ConversionExecutor executor = service.getConversionExecutor(String.class, String[].class);
String[] result = (String[]) executor.execute("1,2,3");
@@ -254,7 +296,7 @@ public class DefaultConversionServiceTests extends TestCase {
assertEquals("1,2,3", result[0]);
}
- public void testToListConversion() {
+ public void testStringToListConversion() {
DefaultConversionService service = new DefaultConversionService();
ConversionExecutor executor = service.getConversionExecutor(String.class, List.class);
List result = (List) executor.execute("1,2,3");
@@ -262,7 +304,7 @@ public class DefaultConversionServiceTests extends TestCase {
assertEquals("1,2,3", result.get(0));
}
- public void testToArrayConversionWithElementConversion() {
+ public void testStringToArrayConversionWithElementConversion() {
DefaultConversionService service = new DefaultConversionService();
ConversionExecutor executor = service.getConversionExecutor(String.class, Integer[].class);
Integer[] result = (Integer[]) executor.execute("123");