This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY_3_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_3_0_X by this push:
new db343453d7 GROOVY-10378: coerce iterable to array or collection
db343453d7 is described below
commit db343453d77df2b603a32a35c480e5a2fa808784
Author: Eric Milles <[email protected]>
AuthorDate: Thu May 16 15:44:19 2024 -0500
GROOVY-10378: coerce iterable to array or collection
3_0_X backport
---
.../typehandling/DefaultTypeTransformation.java | 48 +++++++++-------
.../DefaultTypeTransformationTest.groovy | 67 +++++++++++++++++++++-
2 files changed, 93 insertions(+), 22 deletions(-)
diff --git
a/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
b/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
index 3763d1a6e8..3122d5119d 100644
---
a/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
+++
b/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
@@ -23,14 +23,7 @@ import groovy.lang.GString;
import groovy.lang.GroovyRuntimeException;
import org.codehaus.groovy.reflection.ReflectionCache;
import org.codehaus.groovy.reflection.stdclasses.CachedSAMClass;
-import org.codehaus.groovy.runtime.DefaultGroovyMethods;
-import org.codehaus.groovy.runtime.InvokerHelper;
-import org.codehaus.groovy.runtime.InvokerInvocationException;
-import org.codehaus.groovy.runtime.IteratorClosureAdapter;
-import org.codehaus.groovy.runtime.MethodClosure;
-import org.codehaus.groovy.runtime.NullObject;
-import org.codehaus.groovy.runtime.ResourceGroovyMethods;
-import org.codehaus.groovy.runtime.StringGroovyMethods;
+import org.codehaus.groovy.runtime.*;
import java.io.File;
import java.io.IOException;
@@ -49,6 +42,7 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.function.Supplier;
/**
* Class providing various type conversions, coercions and boxing/unboxing
operations.
@@ -248,20 +242,22 @@ public class DefaultTypeTransformation {
return new LinkedHashSet((Collection) object);
}
- if (object.getClass().isArray()) {
- Collection answer;
+ Supplier<Collection> newCollection = () -> {
if (type.isAssignableFrom(ArrayList.class) &&
Modifier.isAbstract(type.getModifiers())) {
- answer = new ArrayList();
+ return new ArrayList();
} else if (type.isAssignableFrom(LinkedHashSet.class) &&
Modifier.isAbstract(type.getModifiers())) {
- answer = new LinkedHashSet();
+ return new LinkedHashSet();
} else {
try {
- answer = (Collection)
type.getDeclaredConstructor().newInstance();
+ return (Collection)
type.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new GroovyCastException("Could not instantiate
instance of: " + type.getName() + ". Reason: " + e);
}
}
+ };
+ if (object.getClass().isArray()) {
+ Collection answer = newCollection.get();
// we cannot just wrap in a List as we support primitive type
arrays
int length = Array.getLength(object);
for (int i = 0; i < length; i += 1) {
@@ -270,6 +266,14 @@ public class DefaultTypeTransformation {
return answer;
}
+ if (object instanceof Iterable // GROOVY-11378
+ && !(object instanceof Collection)) { // GROOVY-7867
+ Collection answer = newCollection.get();
+ Iterator iterator = ((Iterable) object).iterator();
+ while (iterator.hasNext()) answer.add(iterator.next());
+ return answer;
+ }
+
return continueCastOnNumber(object, type);
}
@@ -442,22 +446,24 @@ public class DefaultTypeTransformation {
return map.entrySet();
} else if (value.getClass().isArray()) {
return arrayAsCollection(value);
- } else if (value instanceof MethodClosure) {
- MethodClosure method = (MethodClosure) value;
- IteratorClosureAdapter adapter = new
IteratorClosureAdapter(method.getDelegate());
- method.call(adapter);
- return adapter.asList();
} else if (value instanceof String || value instanceof GString) {
return StringGroovyMethods.toList((CharSequence) value);
+ } else if (value instanceof Iterable) { // GROOVY-10378
+ return DefaultGroovyMethods.toList((Iterable<?>) value);
+ } else if (value instanceof Class && ((Class) value).isEnum()) {
+ Object[] values = (Object[]) InvokerHelper.invokeMethod(value,
"values", EMPTY_OBJECT_ARRAY);
+ return Arrays.asList(values);
} else if (value instanceof File) {
try {
return ResourceGroovyMethods.readLines((File) value);
} catch (IOException e) {
throw new GroovyRuntimeException("Error reading file: " +
value, e);
}
- } else if (value instanceof Class && ((Class) value).isEnum()) {
- Object[] values = (Object[]) InvokerHelper.invokeMethod(value,
"values", EMPTY_OBJECT_ARRAY);
- return Arrays.asList(values);
+ } else if (value instanceof MethodClosure) {
+ MethodClosure method = (MethodClosure) value;
+ IteratorClosureAdapter<?> adapter = new
IteratorClosureAdapter<>(method.getDelegate());
+ method.call(adapter);
+ return adapter.asList();
} else {
// let's assume it's a collection of 1
return Collections.singletonList(value);
diff --git
a/src/test/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformationTest.groovy
b/src/test/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformationTest.groovy
index b5264ff316..944ecdeb2a 100644
---
a/src/test/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformationTest.groovy
+++
b/src/test/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformationTest.groovy
@@ -25,7 +25,7 @@ import static groovy.test.GroovyAssert.shouldFail
final class DefaultTypeTransformationTest {
@Test
- void testCastToType() {
+ void testCastToType1() {
def input = null, result
result = DefaultTypeTransformation.castToType(input, int)
@@ -53,6 +53,71 @@ final class DefaultTypeTransformationTest {
assert result === input
}
+ @Test
+ void testCastToType2() {
+ def input = new int[] {0,1}, result
+
+ result = DefaultTypeTransformation.castToType(input, Number[])
+ assert result instanceof Number[]
+ assert result[0] == 0
+ assert result[1] == 1
+
+ result = DefaultTypeTransformation.castToType(input, List)
+ assert result instanceof List
+ assert result[0] == 0
+ assert result[1] == 1
+
+ result = DefaultTypeTransformation.castToType(input, Set)
+ assert result instanceof Set
+ assert result[0] == 0
+ assert result[1] == 1
+ }
+
+ @Test
+ void testCastToType3() {
+ def input = Arrays.asList(0,1), result
+
+ result = DefaultTypeTransformation.castToType(input, Number[])
+ assert result instanceof Number[]
+ assert result[0] == 0
+ assert result[1] == 1
+
+ result = DefaultTypeTransformation.castToType(input, List)
+ assert result === input
+ assert result[0] == 0
+ assert result[1] == 1
+
+ result = DefaultTypeTransformation.castToType(input, Set)
+ assert result instanceof Set
+ assert result[0] == 0
+ assert result[1] == 1
+ }
+
+ @Test // GROOVY-11378
+ void testCastToType4() {
+ def input = new org.codehaus.groovy.util.ArrayIterable<Integer>(0,1),
result
+
+ result = DefaultTypeTransformation.castToType(input, Number[])
+ assert result instanceof Number[]
+ assert result[0] == 0
+ assert result[1] == 1
+
+ result = DefaultTypeTransformation.castToType(input, int[])
+ assert result instanceof int[]
+ assert result[0] == 0
+ assert result[1] == 1
+
+ result = DefaultTypeTransformation.castToType(input, List)
+ assert result instanceof List
+ assert result[0] == 0
+ assert result[1] == 1
+
+ result = DefaultTypeTransformation.castToType(input, Set)
+ assert result instanceof Set
+ assert result[0] == 0
+ assert result[1] == 1
+ }
+
@Test
void testCompareTo() {
// objects