added object to collection; refined converter lookup algorithm
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user