You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by jw...@apache.org on 2017/07/18 01:48:56 UTC

[4/6] groovy git commit: GROOVY-8259: add suppressed exceptions for with[Auto]Closeable methods

GROOVY-8259: add suppressed exceptions for with[Auto]Closeable methods


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/daee97c4
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/daee97c4
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/daee97c4

Branch: refs/heads/master
Commit: daee97c40f9fdf316fbc764593c41b7a9f7270a5
Parents: 9d8e433
Author: John Wagenleitner <jw...@apache.org>
Authored: Sun Jul 16 10:55:24 2017 -0700
Committer: John Wagenleitner <jw...@apache.org>
Committed: Mon Jul 17 18:45:24 2017 -0700

----------------------------------------------------------------------
 .../runtime/DefaultGroovyMethodsSupport.java    | 25 ++++++++--
 .../groovy/runtime/IOGroovyMethods.java         | 50 +++++++++++++-------
 .../groovy/runtime/IOGroovyMethodsTest.groovy   | 14 ++++--
 3 files changed, 64 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/daee97c4/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupport.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupport.java b/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupport.java
index dc370d8..69f387a 100644
--- a/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupport.java
+++ b/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupport.java
@@ -83,10 +83,10 @@ public class DefaultGroovyMethodsSupport {
     /**
      * Close the Closeable. Logging a warning if any problems occur.
      *
-     * @param c the thing to close
+     * @param closeable the thing to close
      */
-    public static void closeWithWarning(Closeable c) {
-        closeWithWarning((AutoCloseable) c);
+    public static void closeWithWarning(Closeable closeable) {
+        tryClose(closeable, true); // ignore result
     }
 
     /**
@@ -95,13 +95,30 @@ public class DefaultGroovyMethodsSupport {
      * @param closeable the thing to close
      */
     public static void closeWithWarning(AutoCloseable closeable) {
+        tryClose(closeable, true); // ignore result
+    }
+
+    /**
+     * Attempts to close the closeable returning rather than throwing
+     * any Exception that may occur.
+     *
+     * @param closeable the thing to close
+     * @param logWarning if true will log a warning if an exception occurs
+     * @return throwable Exception from the close method, else null
+     */
+    static Throwable tryClose(AutoCloseable closeable, boolean logWarning) {
+        Throwable thrown = null;
         if (closeable != null) {
             try {
                 closeable.close();
             } catch (Exception e) {
-                LOG.warning("Caught exception during close(): " + e);
+                thrown = e;
+                if (logWarning) {
+                    LOG.warning("Caught exception during close(): " + e);
+                }
             }
         }
+        return thrown;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/groovy/blob/daee97c4/src/main/org/codehaus/groovy/runtime/IOGroovyMethods.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/runtime/IOGroovyMethods.java b/src/main/org/codehaus/groovy/runtime/IOGroovyMethods.java
index 57ea844..789e0fd 100644
--- a/src/main/org/codehaus/groovy/runtime/IOGroovyMethods.java
+++ b/src/main/org/codehaus/groovy/runtime/IOGroovyMethods.java
@@ -1589,6 +1589,10 @@ public class IOGroovyMethods extends DefaultGroovyMethodsSupport {
     /**
      * Allows this closeable to be used within the closure, ensuring that it
      * is closed once the closure has been executed and before this method returns.
+     * <p>
+     * As with the try-with-resources statement, if multiple exceptions are thrown
+     * the exception from the closure will be returned and the exception from closing
+     * will be added as a suppressed exception.
      *
      * @param self the Closeable
      * @param action the closure taking the Closeable as parameter
@@ -1597,22 +1601,31 @@ public class IOGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 2.4.0
      */
     public static <T, U extends Closeable> T withCloseable(U self, @ClosureParams(value=FirstParam.class) Closure<T> action) throws IOException {
+        Throwable thrown = null;
         try {
-            T result = action.call(self);
-
-            Closeable temp = self;
-            self = null;
-            temp.close();
-
-            return result;
+            return action.call(self);
+        } catch (Throwable e) {
+            thrown = e;
+            throw e;
         } finally {
-            DefaultGroovyMethodsSupport.closeWithWarning(self);
+            if (thrown != null) {
+                Throwable suppressed = tryClose(self, true);
+                if (suppressed != null) {
+                    thrown.addSuppressed(suppressed);
+                }
+            } else {
+                self.close();
+            }
         }
     }
 
     /**
      * Allows this AutoCloseable to be used within the closure, ensuring that it
      * is closed once the closure has been executed and before this method returns.
+     * <p>
+     * As with the try-with-resources statement, if multiple exceptions are thrown
+     * the exception from the closure will be returned and the exception from closing
+     * will be added as a suppressed exception.
      *
      * @param self the AutoCloseable
      * @param action the closure taking the AutoCloseable as parameter
@@ -1621,16 +1634,21 @@ public class IOGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 2.5.0
      */
     public static <T, U extends AutoCloseable> T withAutoCloseable(U self, @ClosureParams(value=FirstParam.class) Closure<T> action) throws Exception {
+        Throwable thrown = null;
         try {
-            T result = action.call(self);
-
-            U temp = self;
-            self = null;
-            temp.close();
-
-            return result;
+            return action.call(self);
+        } catch (Throwable e) {
+            thrown = e;
+            throw e;
         } finally {
-            DefaultGroovyMethodsSupport.closeWithWarning(self);
+            if (thrown != null) {
+                Throwable suppressed = tryClose(self, true);
+                if (suppressed != null) {
+                    thrown.addSuppressed(suppressed);
+                }
+            } else {
+                self.close();
+            }
         }
     }
 

http://git-wip-us.apache.org/repos/asf/groovy/blob/daee97c4/src/test/org/codehaus/groovy/runtime/IOGroovyMethodsTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/org/codehaus/groovy/runtime/IOGroovyMethodsTest.groovy b/src/test/org/codehaus/groovy/runtime/IOGroovyMethodsTest.groovy
index b66936c..c5b42d2 100644
--- a/src/test/org/codehaus/groovy/runtime/IOGroovyMethodsTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/IOGroovyMethodsTest.groovy
@@ -18,6 +18,8 @@
  */
 package org.codehaus.groovy.runtime
 
+import groovy.test.GroovyAssert
+
 class IOGroovyMethodsTest extends GroovyTestCase {
 
     void testWithAutoCloseable() {
@@ -34,13 +36,14 @@ class IOGroovyMethodsTest extends GroovyTestCase {
 
     void testWithAutoCloseableDoesNotSuppressException() {
         def closeable = new DummyAutoCloseable(new Exception('close exception'))
-        def message = shouldFail(UnsupportedOperationException) {
+        def throwable = GroovyAssert.shouldFail(UnsupportedOperationException) {
             closeable.withAutoCloseable {
                 throw new UnsupportedOperationException('not a close exception')
             }
         }
         assert closeable.closed
-        assert message == 'not a close exception'
+        assert throwable.message == 'not a close exception'
+        assert throwable.suppressed.find { it.message == 'close exception' }
     }
 
     void testWithAutoCloseableAndException() {
@@ -69,13 +72,14 @@ class IOGroovyMethodsTest extends GroovyTestCase {
 
     void testWithCloseableDoesNotSuppressException() {
         def closeable = new DummyCloseable(new IOException('close ioexception'))
-        def message = shouldFail(UnsupportedOperationException) {
+        def throwable = GroovyAssert.shouldFail(Exception) {
             closeable.withCloseable {
-                throw new UnsupportedOperationException('not a close ioexception')
+                throw new Exception('not a close ioexception')
             }
         }
         assert closeable.closed
-        assert message == 'not a close ioexception'
+        assert throwable.message == 'not a close ioexception'
+        assert throwable.suppressed.find { it.message == 'close ioexception' }
     }
 
     void testWithCloseableAndException() {