This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/master by this push:
     new 2e82c9f5bd GROOVY-10223: support assignment/cast of `Optional` to 
array/collection
2e82c9f5bd is described below

commit 2e82c9f5bd6201ed4724b26714275f4cef9df6e8
Author: Eric Milles <eric.mil...@thomsonreuters.com>
AuthorDate: Fri Jun 24 10:31:23 2022 -0500

    GROOVY-10223: support assignment/cast of `Optional` to array/collection
---
 .../typehandling/DefaultTypeTransformation.java    | 31 ++++----
 .../DefaultTypeTransformationTest.groovy           | 84 ++++++++++++++++++++++
 2 files changed, 101 insertions(+), 14 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 ac816bdf57..173ad5a2c7 100644
--- 
a/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
+++ 
b/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
@@ -50,6 +50,7 @@ import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.function.Supplier;
 import java.util.stream.BaseStream;
 import java.util.stream.DoubleStream;
@@ -271,12 +272,6 @@ public class DefaultTypeTransformation {
             }
         };
 
-        if (object instanceof BaseStream) {
-            Collection answer = newCollection.get();
-            answer.addAll(asCollection(object));
-            return answer;
-        }
-
         if (object.getClass().isArray()) {
             Collection answer = newCollection.get();
             // we cannot just wrap in a List as we support primitive type 
arrays
@@ -287,6 +282,12 @@ public class DefaultTypeTransformation {
             return answer;
         }
 
+        if (object instanceof BaseStream || object instanceof Optional) {
+            Collection answer = newCollection.get();
+            answer.addAll(asCollection(object));
+            return answer;
+        }
+
         return continueCastOnNumber(object, type);
     }
 
@@ -484,22 +485,24 @@ public class DefaultTypeTransformation {
             return arrayAsCollection(value);
         } else if (value instanceof BaseStream) {
             return StreamGroovyMethods.toList((BaseStream) 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 Optional) { // GROOVY-10223
+            return ((Optional<?>) 
value).map(Collections::singleton).orElseGet(Collections::emptySet);
+        } 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 5054fb57a3..fc03274ae2 100644
--- 
a/src/test/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformationTest.groovy
+++ 
b/src/test/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformationTest.groovy
@@ -20,6 +20,7 @@ package org.codehaus.groovy.runtime.typehandling
 
 import org.junit.Test
 
+import static groovy.test.GroovyAssert.assertScript
 import static groovy.test.GroovyAssert.shouldFail
 
 final class DefaultTypeTransformationTest {
@@ -118,6 +119,89 @@ final class DefaultTypeTransformationTest {
         assert result[1] == 1
     }
 
+    @Test // GROOVY-10223
+    void testCastToType5() {
+        def err = shouldFail GroovyCastException, {
+            DefaultTypeTransformation.castToType(Optional.of('123'), Number[])
+        }
+        assert err =~ /Cannot cast object '123' with class 'java.lang.String' 
to class 'java.lang.Number'/
+
+        def nothing = Optional.empty(), something = Optional.of(12345.000)
+        def result
+
+        result = DefaultTypeTransformation.castToType(something, Number[])
+        assert result instanceof Number[]
+        assert result.length == 1
+        assert result[0] == 12345
+        result = DefaultTypeTransformation.castToType(nothing, Number[])
+        assert result instanceof Number[]
+        assert result.length == 0
+
+        result = DefaultTypeTransformation.castToType(something, int[])
+        assert result instanceof int[]
+        assert result.length == 1
+        assert result[0] == 12345
+        result = DefaultTypeTransformation.castToType(nothing, int[])
+        assert result instanceof int[]
+        assert result.length == 0
+
+        result = DefaultTypeTransformation.castToType(something, List)
+        assert result instanceof List
+        assert result.size() == 1
+        assert result[0] == 12345
+        result = DefaultTypeTransformation.castToType(nothing, List)
+        assert result instanceof List
+        assert result.isEmpty()
+
+        result = DefaultTypeTransformation.castToType(something, Set)
+        assert result instanceof Set
+        assert result.size() == 1
+        assert result[0] == 12345
+        result = DefaultTypeTransformation.castToType(nothing, Set)
+        assert result instanceof Set
+        assert result.isEmpty()
+    }
+
+    @Test // GROOVY-10223: interesting emergent properties
+    void testAsCollection() {
+        assertScript '''
+            def nothing = Optional.empty(), something = Optional.of('foo')
+
+            // array assignment
+            Object[] array = nothing
+            assert array.length == 0
+            array = something
+            assert array.length == 1
+            assert array[0] == 'foo'
+
+            // iterator() support
+            def iterator = nothing.iterator()
+            assert !iterator.hasNext()
+            iterator = something.iterator()
+            assert iterator.hasNext()
+            assert iterator.next() == 'foo'
+            assert !iterator.hasNext()
+
+            // for-each supported via iterator()
+            int values = 0
+            for (value in nothing) {
+                values += 1
+            }
+            assert values == 0
+            for (value in something) {
+                assert value == 'foo'
+                values += 1
+            }
+            assert values == 1
+        '''
+
+        shouldFail ''' // requires support in 
ScriptBytecodeAdapter#despreadList
+            def nothing = Optional.empty()
+            def list = [*nothing]
+            assert list.isEmpty()
+        '''
+    }
+
     @Test
     void testCompareTo() {
         // objects

Reply via email to