Skip to content

Commit c9607fd

Browse files
committed
CollectionCollection/MapToMapConverter preserve original Collection/Map if no converted elements (SPR-8714)
1 parent 7c108c1 commit c9607fd

File tree

7 files changed

+560
-33
lines changed

7 files changed

+560
-33
lines changed

org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ public TypeDescriptor getElementTypeDescriptor() {
281281
*/
282282
public TypeDescriptor getElementTypeDescriptor(Object element) {
283283
TypeDescriptor elementType = getElementTypeDescriptor();
284-
return (elementType != TypeDescriptor.UNKNOWN ? elementType : forObject(element));
284+
return (!TypeDescriptor.UNKNOWN.equals(elementType) ? elementType : forObject(element));
285285
}
286286

287287
/**

org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToCollectionConverter.java

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2009 the original author or authors.
2+
* Copyright 2002-2011 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -49,7 +49,8 @@ public Set<ConvertiblePair> getConvertibleTypes() {
4949
}
5050

5151
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
52-
return ConversionUtils.canConvertElements(sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor(), this.conversionService);
52+
return ConversionUtils.canConvertElements(
53+
sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor(), this.conversionService);
5354
}
5455

5556
@SuppressWarnings("unchecked")
@@ -58,12 +59,21 @@ public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor t
5859
return null;
5960
}
6061
int length = Array.getLength(source);
61-
Collection target = CollectionFactory.createCollection(targetType.getType(), length);
62-
for (int i = 0; i < length; i++) {
63-
Object sourceElement = Array.get(source, i);
64-
Object targetElement = this.conversionService.convert(sourceElement, sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor(sourceElement));
65-
target.add(targetElement);
62+
Collection<Object> target = CollectionFactory.createCollection(targetType.getType(), length);
63+
if (targetType.getElementTypeDescriptor() == null) {
64+
for (int i = 0; i < length; i++) {
65+
Object sourceElement = Array.get(source, i);
66+
target.add(sourceElement);
67+
}
6668
}
69+
else {
70+
for (int i = 0; i < length; i++) {
71+
Object sourceElement = Array.get(source, i);
72+
Object targetElement = this.conversionService.convert(sourceElement,
73+
sourceType.getElementTypeDescriptor(sourceElement), targetType.getElementTypeDescriptor());
74+
target.add(targetElement);
75+
}
76+
}
6777
return target;
6878
}
6979

org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToCollectionConverter.java

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,23 +49,34 @@ public Set<ConvertiblePair> getConvertibleTypes() {
4949
}
5050

5151
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
52-
return ConversionUtils.canConvertElements(sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor(), conversionService);
52+
return ConversionUtils.canConvertElements(
53+
sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor(), this.conversionService);
5354
}
5455

5556
@SuppressWarnings("unchecked")
5657
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
5758
if (source == null) {
5859
return null;
5960
}
61+
boolean copyRequired = !targetType.getType().isInstance(source);
6062
Collection<?> sourceCollection = (Collection<?>) source;
61-
Collection target = CollectionFactory.createCollection(targetType.getType(), sourceCollection.size());
62-
for (Object sourceElement : sourceCollection) {
63-
Object targetElement = this.conversionService.convert(sourceElement,
64-
sourceType.getElementTypeDescriptor(sourceElement),
65-
targetType.getElementTypeDescriptor(sourceElement));
66-
target.add(targetElement);
63+
Collection<Object> target = CollectionFactory.createCollection(targetType.getType(), sourceCollection.size());
64+
if (targetType.getElementTypeDescriptor() == null) {
65+
for (Object element : sourceCollection) {
66+
target.add(element);
67+
}
6768
}
68-
return target;
69+
else {
70+
for (Object sourceElement : sourceCollection) {
71+
Object targetElement = this.conversionService.convert(sourceElement,
72+
sourceType.getElementTypeDescriptor(sourceElement), targetType.getElementTypeDescriptor());
73+
target.add(targetElement);
74+
if (sourceElement != targetElement) {
75+
copyRequired = true;
76+
}
77+
}
78+
}
79+
return (copyRequired ? target : source);
6980
}
7081

7182
}

org.springframework.core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,8 @@ public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor t
148148
Assert.isTrue(source == null || sourceType.getObjectType().isInstance(source));
149149
GenericConverter converter = getConverter(sourceType, targetType);
150150
if (converter == null) {
151-
if (source == null || targetType.getObjectType().isInstance(source)) {
151+
if (source == null ||
152+
(sourceType.isAssignableTo(targetType) && targetType.getObjectType().isInstance(source))) {
152153
return source;
153154
}
154155
else {

org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToMapConverter.java

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -49,30 +49,54 @@ public Set<ConvertiblePair> getConvertibleTypes() {
4949
}
5050

5151
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
52-
return this.conversionService.canConvert(sourceType.getMapKeyTypeDescriptor(), targetType.getMapKeyTypeDescriptor()) &&
53-
this.conversionService.canConvert(sourceType.getMapValueTypeDescriptor(), targetType.getMapValueTypeDescriptor());
52+
return canConvertKey(sourceType, targetType) && canConvertValue(sourceType, targetType);
5453
}
5554

5655
@SuppressWarnings("unchecked")
5756
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
5857
if (source == null) {
5958
return null;
6059
}
61-
Map<?, ?> sourceMap = (Map<?, ?>) source;
62-
Map targetMap = CollectionFactory.createMap(targetType.getType(), sourceMap.size());
63-
for (Object entry : sourceMap.entrySet()) {
64-
Map.Entry sourceMapEntry = (Map.Entry) entry;
65-
Object sourceKey = sourceMapEntry.getKey();
66-
Object sourceValue = sourceMapEntry.getValue();
67-
Object targetKey = this.conversionService.convert(sourceKey,
68-
sourceType.getMapKeyTypeDescriptor(sourceKey),
69-
targetType.getMapKeyTypeDescriptor(sourceKey));
70-
Object targetValue = this.conversionService.convert(sourceValue,
71-
sourceType.getMapValueTypeDescriptor(sourceValue),
72-
targetType.getMapValueTypeDescriptor(sourceValue));
60+
boolean copyRequired = !targetType.getType().isInstance(source);
61+
Map<Object, Object> sourceMap = (Map<Object, Object>) source;
62+
Map<Object, Object> targetMap = CollectionFactory.createMap(targetType.getType(), sourceMap.size());
63+
for (Map.Entry<Object, Object> entry : sourceMap.entrySet()) {
64+
Object sourceKey = entry.getKey();
65+
Object sourceValue = entry.getValue();
66+
Object targetKey = convertKey(sourceKey, sourceType, targetType.getMapKeyTypeDescriptor());
67+
Object targetValue = convertValue(sourceValue, sourceType, targetType.getMapValueTypeDescriptor());
7368
targetMap.put(targetKey, targetValue);
69+
if (sourceKey != targetKey || sourceValue != targetValue) {
70+
copyRequired = true;
71+
}
7472
}
75-
return targetMap;
73+
return (copyRequired ? targetMap : sourceMap);
7674
}
77-
75+
76+
// internal helpers
77+
78+
private boolean canConvertKey(TypeDescriptor sourceType, TypeDescriptor targetType) {
79+
return ConversionUtils.canConvertElements(sourceType.getMapKeyTypeDescriptor(),
80+
targetType.getMapKeyTypeDescriptor(), this.conversionService);
81+
}
82+
83+
private boolean canConvertValue(TypeDescriptor sourceType, TypeDescriptor targetType) {
84+
return ConversionUtils.canConvertElements(sourceType.getMapValueTypeDescriptor(),
85+
targetType.getMapValueTypeDescriptor(), this.conversionService);
86+
}
87+
88+
private Object convertKey(Object sourceKey, TypeDescriptor sourceType, TypeDescriptor targetType) {
89+
if (targetType == null) {
90+
return sourceKey;
91+
}
92+
return this.conversionService.convert(sourceKey, sourceType.getMapKeyTypeDescriptor(sourceKey), targetType);
93+
}
94+
95+
private Object convertValue(Object sourceValue, TypeDescriptor sourceType, TypeDescriptor targetType) {
96+
if (targetType == null) {
97+
return sourceValue;
98+
}
99+
return this.conversionService.convert(sourceValue, sourceType.getMapValueTypeDescriptor(sourceValue), targetType);
100+
}
101+
78102
}

0 commit comments

Comments
 (0)