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

Reply via email to