added object to collection; refined converter lookup algorithm

This commit is contained in:
Keith Donald
2008-07-14 15:12:27 +00:00
parent d187db5e85
commit 2298664bb8
7 changed files with 180 additions and 146 deletions

View File

@@ -15,7 +15,6 @@
*/
package org.springframework.binding.convert;
/**
* A command object that is parameterized with the information necessary to perform a conversion of a source input to a
* target output. Encapsulates knowledge about how to convert source objects to a specific target type using a specific

View File

@@ -64,46 +64,17 @@ public class ArrayToCollection implements TwoWayConverter {
if (source == null) {
return null;
}
Class collectionImplClass;
if (targetClass.isInterface()) {
if (List.class.equals(targetClass)) {
collectionImplClass = ArrayList.class;
} else if (Set.class.equals(targetClass)) {
collectionImplClass = LinkedHashSet.class;
} else if (SortedSet.class.equals(targetClass)) {
collectionImplClass = TreeSet.class;
} else {
throw new IllegalArgumentException("Unsupported collection interface [" + targetClass.getName() + "]");
}
} else {
collectionImplClass = targetClass;
}
Class collectionImplClass = getCollectionImplClass(targetClass);
Constructor constructor = collectionImplClass.getConstructor(null);
ConversionExecutor converter;
if (JdkVersion.isAtLeastJava15()) {
Class elementType = GenericCollectionTypeResolver.getCollectionType(targetClass);
if (elementType != null) {
Class componentType = source.getClass().getComponentType();
converter = conversionService.getConversionExecutor(componentType, elementType);
} else {
converter = null;
}
} else {
converter = null;
}
Collection collection = (Collection) constructor.newInstance(null);
ConversionExecutor converter = getElementConverter(source, targetClass);
int length = Array.getLength(source);
if (converter != null) {
for (int i = 0; i < length; i++) {
Object value = Array.get(source, i);
for (int i = 0; i < length; i++) {
Object value = Array.get(source, i);
if (converter != null) {
value = converter.execute(value);
collection.add(value);
}
} else {
for (int i = 0; i < length; i++) {
Object value = Array.get(source, i);
collection.add(value);
}
collection.add(value);
}
return collection;
}
@@ -126,4 +97,32 @@ public class ArrayToCollection implements TwoWayConverter {
}
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 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);
}
}
return null;
}
}

View File

@@ -21,13 +21,12 @@ import org.springframework.binding.convert.ConversionExecutor;
import org.springframework.binding.convert.ConversionService;
/**
* Special two-way converter that converts an object to an single-element array. Supports type conversion of the
* individual array elements; for example, the ability to convert a String to an Integer[]. Mainly used internally by
* Special two-way converter that converts an object to an single-element array. Mainly used internally by
* {@link ConversionService} implementations.
*
* @author Keith Donald
*/
public class ObjectToArray implements TwoWayConverter {
public class ObjectToArray implements Converter {
private ConversionService conversionService;
@@ -47,50 +46,10 @@ public class ObjectToArray implements TwoWayConverter {
if (source == null) {
return null;
}
if (source instanceof String) {
String string = (String) source;
String[] elements = string.split(",");
Class componentType = targetClass.getComponentType();
Object array = Array.newInstance(componentType, elements.length);
ConversionExecutor converter = conversionService.getConversionExecutor(String.class, componentType);
for (int i = 0; i < elements.length; i++) {
String element = elements[i].trim();
Array.set(array, i, converter.execute(element));
}
return array;
} else {
Class componentType = targetClass.getComponentType();
Object array = Array.newInstance(componentType, 1);
ConversionExecutor converter = conversionService.getConversionExecutor(source.getClass(), componentType);
Array.set(array, 0, converter.execute(source));
return array;
}
Class componentType = targetClass.getComponentType();
Object array = Array.newInstance(componentType, 1);
ConversionExecutor converter = conversionService.getConversionExecutor(source.getClass(), componentType);
Array.set(array, 0, converter.execute(source));
return array;
}
public Object convertTargetToSourceClass(Object target, Class sourceClass) throws Exception {
if (target == null) {
return null;
}
if (String.class.equals(sourceClass)) {
int length = Array.getLength(target);
Class componentType = target.getClass().getComponentType();
ConversionExecutor converter = conversionService.getConversionExecutor(componentType, String.class);
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < length; i++) {
Object value = Array.get(target, i);
if (value != null) {
buffer.append(converter.execute(value));
}
if (i < length - 1) {
buffer.append(",");
}
}
return buffer.toString();
} else {
Object value = Array.get(target, 0);
Class componentType = target.getClass().getComponentType();
ConversionExecutor converter = conversionService.getConversionExecutor(componentType, sourceClass);
return converter.execute(value);
}
}
}
}

View File

@@ -0,0 +1,98 @@
/*
* 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.binding.convert.converters;
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.binding.convert.ConversionExecutor;
import org.springframework.binding.convert.ConversionService;
import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.JdkVersion;
/**
* 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
*/
public class ObjectToCollection implements Converter {
private ConversionService conversionService;
public ObjectToCollection(ConversionService conversionService) {
this.conversionService = conversionService;
}
public Class getSourceClass() {
return Object.class;
}
public Class getTargetClass() {
return Collection.class;
}
public Object convertSourceToTargetClass(Object source, Class targetClass) throws Exception {
if (source == null) {
return null;
}
Class collectionImplClass = getCollectionImplClass(targetClass);
Constructor constructor = collectionImplClass.getConstructor(null);
Collection collection = (Collection) constructor.newInstance(null);
ConversionExecutor converter = getElementConverter(source, targetClass);
Object value;
if (converter != null) {
value = converter.execute(source);
} else {
value = source;
}
collection.add(value);
return collection;
}
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 (JdkVersion.isAtLeastJava15()) {
Class elementType = GenericCollectionTypeResolver.getCollectionType(targetClass);
if (elementType != null) {
Class componentType = source.getClass().getComponentType();
return conversionService.getConversionExecutor(componentType, elementType);
}
}
return null;
}
}

View File

@@ -20,6 +20,7 @@ import java.math.BigInteger;
import java.util.Date;
import java.util.Locale;
import org.springframework.binding.convert.converters.ObjectToCollection;
import org.springframework.binding.convert.converters.StringToBigDecimal;
import org.springframework.binding.convert.converters.StringToBigInteger;
import org.springframework.binding.convert.converters.StringToBoolean;
@@ -68,6 +69,7 @@ public class DefaultConversionService extends GenericConversionService {
addConverter(new StringToLocale());
addConverter(new StringToDate());
addConverter(new StringToLabeledEnum());
addConverter(new ObjectToCollection(this));
}
protected void addDefaultAliases() {

View File

@@ -134,9 +134,6 @@ public class GenericConversionService implements ConversionService {
+ "request an interface or concrete implementation instead");
}
return new StaticConversionExecutor(sourceClass, targetClass, new ArrayToCollection(this));
} else {
Converter arrayToObject = new ReverseConverter(new ObjectToArray(this));
return new StaticConversionExecutor(sourceClass, targetClass, arrayToObject);
}
}
if (targetClass.isArray()) {
@@ -147,8 +144,7 @@ public class GenericConversionService implements ConversionService {
return new StaticConversionExecutor(sourceClass, targetClass, new ObjectToArray(this));
}
}
Map sourceTargetConverters = findConvertersForSource(sourceClass);
Converter converter = findTargetConverter(sourceTargetConverters, targetClass);
Converter converter = findRegisteredConverter(sourceClass, targetClass);
if (converter != null) {
// we found a converter
return new StaticConversionExecutor(sourceClass, targetClass, converter);
@@ -164,6 +160,27 @@ public class GenericConversionService implements ConversionService {
}
}
private Converter findRegisteredConverter(Class sourceClass, Class targetClass) {
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;
}
public Object executeConversion(Object source, Class targetClass) throws ConversionException {
if (source != null) {
ConversionExecutor conversionExecutor = getConversionExecutor(source.getClass(), targetClass);
@@ -226,47 +243,8 @@ public class GenericConversionService implements ConversionService {
// internal helpers
private Map findConvertersForSource(Class sourceClass) {
if (sourceClass.isInterface()) {
LinkedList classQueue = new LinkedList();
classQueue.addFirst(sourceClass);
while (!classQueue.isEmpty()) {
sourceClass = (Class) classQueue.removeLast();
Map sourceTargetConverters = (Map) sourceClassConverters.get(sourceClass);
if (sourceTargetConverters != null && !sourceTargetConverters.isEmpty()) {
return sourceTargetConverters;
}
// queue up source class's implemented interfaces.
Class[] interfaces = sourceClass.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
classQueue.addFirst(interfaces[i]);
}
}
Map sourceTargetConverters = (Map) sourceClassConverters.get(Object.class);
if (sourceTargetConverters != null && !sourceTargetConverters.isEmpty()) {
return sourceTargetConverters;
} else {
return Collections.EMPTY_MAP;
}
} else {
LinkedList classQueue = new LinkedList();
classQueue.addFirst(sourceClass);
while (!classQueue.isEmpty()) {
sourceClass = (Class) classQueue.removeLast();
Map sourceTargetConverters = (Map) sourceClassConverters.get(sourceClass);
if (sourceTargetConverters != null && !sourceTargetConverters.isEmpty()) {
return sourceTargetConverters;
}
if (sourceClass.getSuperclass() != null) {
classQueue.addFirst(sourceClass.getSuperclass());
}
// queue up source class's implemented interfaces.
Class[] interfaces = sourceClass.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
classQueue.addFirst(interfaces[i]);
}
}
return Collections.EMPTY_MAP;
}
Map sourceConverters = (Map) sourceClassConverters.get(sourceClass);
return sourceConverters != null ? sourceConverters : Collections.EMPTY_MAP;
}
private Converter findTargetConverter(Map sourceTargetConverters, Class targetClass) {