You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by Benedikt Ritter <br...@apache.org> on 2015/07/24 17:26:30 UTC

Re: [lang] LANG-1149 Ability to throw checked exceptions without declaring them

Hello,

2015-07-12 0:42 GMT+02:00 <ch...@apache.org>:

> Repository: commons-lang
> Updated Branches:
>   refs/heads/master 1b066eb4f -> 59022fb87
>
>
> LANG-1149
> Ability to throw checked exceptions without declaring them
>
>
> Project: http://git-wip-us.apache.org/repos/asf/commons-lang/repo
> Commit:
> http://git-wip-us.apache.org/repos/asf/commons-lang/commit/59022fb8
> Tree: http://git-wip-us.apache.org/repos/asf/commons-lang/tree/59022fb8
> Diff: http://git-wip-us.apache.org/repos/asf/commons-lang/diff/59022fb8
>
> Branch: refs/heads/master
> Commit: 59022fb870c2c45a27e00943003c5acdeddaeec3
> Parents: 1b066eb
> Author: Chas Honton <ch...@apache.org>
> Authored: Sat Jul 11 15:41:56 2015 -0700
> Committer: Chas Honton <ch...@apache.org>
> Committed: Sat Jul 11 15:42:27 2015 -0700
>
> ----------------------------------------------------------------------
>  src/changes/changes.xml                         |  1 +
>  .../commons/lang3/exception/ExceptionUtils.java | 66 ++++++++++++++++++++
>  .../lang3/exception/ExceptionUtilsTest.java     | 60 ++++++++++++++++--
>  3 files changed, 123 insertions(+), 4 deletions(-)
> ----------------------------------------------------------------------
>
>
>
> http://git-wip-us.apache.org/repos/asf/commons-lang/blob/59022fb8/src/changes/changes.xml
> ----------------------------------------------------------------------
> diff --git a/src/changes/changes.xml b/src/changes/changes.xml
> index 19e7c11..cffa0b3 100644
> --- a/src/changes/changes.xml
> +++ b/src/changes/changes.xml
> @@ -22,6 +22,7 @@
>    <body>
>
>    <release version="3.5" date="tba" description="tba">
> +    <action issue="LANG-1149" type="add" dev="chas" due-to="Gregory
> Zak">Ability to throw checked exceptions without declaring them</action>
>      <action issue="LANG-1002" type="fix" dev="chas" due-to="Michael
> Osipov">Several predefined ISO FastDateFormats in DateFormatUtils are
> incorrect</action>
>      <action issue="LANG-1152" type="fix" dev="chas" due-to="Pas
> Filip">StringIndexOutOfBoundsException or field over-write for large year
> fields in FastDateParser</action>
>      <action issue="LANG-1153" type="add" dev="chas">Implement
> ParsePosition api for FastDateParser</action>
>
>
> http://git-wip-us.apache.org/repos/asf/commons-lang/blob/59022fb8/src/main/java/org/apache/commons/lang3/exception/ExceptionUtils.java
> ----------------------------------------------------------------------
> diff --git
> a/src/main/java/org/apache/commons/lang3/exception/ExceptionUtils.java
> b/src/main/java/org/apache/commons/lang3/exception/ExceptionUtils.java
> index a64357c..8f0898f 100644
> --- a/src/main/java/org/apache/commons/lang3/exception/ExceptionUtils.java
> +++ b/src/main/java/org/apache/commons/lang3/exception/ExceptionUtils.java
> @@ -693,4 +693,70 @@ public class ExceptionUtils {
>          return getMessage(root);
>      }
>
> +    /**
> +     * Throw a checked exception without adding the exception to the
> throws
> +     * clause of the calling method. This method prevents throws clause
> +     * pollution and reduces the clutter of "Caused by" exceptions in the
> +     * stacktrace.
> +     * <p>
> +     * The use of this technique may be controversial, but exceedingly
> useful to
> +     * library developers.
> +     * <code>
> +     *  public int propagateExample { // note that there is no throws
> clause
> +     *      try {
> +     *          return invocation(); // throws IOException
> +     *      } catch (Exception e) {
> +     *          return ExceptionUtils.rethrow(e);  // propagates a
> checked exception
> +     *      }
> +     *  }
> +     * </code>
> +     * <p>
> +     * This is an alternative to the more conservative approach of
> wrapping the
> +     * checked exception in a RuntimeException:
> +     * <code>
> +     *  public int wrapExample { // note that there is no throws clause
> +     *      try {
> +     *          return invocation(); // throws IOException
> +     *      } catch (Exception e) {
> +     *          throw new UndeclaredThrowableException(e);  // wraps a
> checked exception
> +     *      }
> +     *  }
> +     * </code>
> +     * <p>
> +     * One downside to using this approach is that the java compiler will
> not
> +     * allow invoking code to specify a checked exception in a catch
> clause
> +     * unless there is some code path within the try block that has
> invoked a
> +     * method declared with that checked exception. If the invoking site
> wishes
> +     * to catch the shaded checked exception, it must either invoke the
> shaded
> +     * code through a method re-declaring the desired checked exception,
> or
> +     * catch Exception and use the instanceof operator. Either of these
> +     * techniques are required when interacting with non-java jvm code
> such as
> +     * Jyton, Scala, or Groovy, since these languages do not consider any
> +     * exceptions as checked.
> +     *
> +     * @since 3.5
> +     *
> +     * @param throwable
> +     *            The throwable to rethrow.
> +     * @return R Never actually returns, this generic type matches any
> type
> +     *         which the calling site requires. "Returning" the results
> of this
> +     *         method, as done in the propagateExample above, will
> satisfy the
> +     *         java compiler that all code paths return a value.
> +     * @throws throwable
> +     */
> +    public static <R> R rethrow(Throwable throwable) {
> +        // claim that the typeErasure invocation throws a RuntimeException
> +        return ExceptionUtils.<R, RuntimeException>
> typeErasure(throwable);
> +    }
> +
> +    /**
> +     * Claim a Throwable is another Exception type using type erasure.
> This
> +     * hides a checked exception from the java compiler, allowing a
> checked
> +     * exception to be thrown without having the exception in the
> method's throw
> +     * clause.
> +     */
> +    @SuppressWarnings("unchecked")
> +    private static <R, T extends Throwable> R typeErasure(Throwable
> throwable) throws T {
> +        throw (T) throwable;
> +    }
>  }
>
>
> http://git-wip-us.apache.org/repos/asf/commons-lang/blob/59022fb8/src/test/java/org/apache/commons/lang3/exception/ExceptionUtilsTest.java
> ----------------------------------------------------------------------
> diff --git
> a/src/test/java/org/apache/commons/lang3/exception/ExceptionUtilsTest.java
> b/src/test/java/org/apache/commons/lang3/exception/ExceptionUtilsTest.java
> index c8ef1b6..e7d264d 100644
> ---
> a/src/test/java/org/apache/commons/lang3/exception/ExceptionUtilsTest.java
> +++
> b/src/test/java/org/apache/commons/lang3/exception/ExceptionUtilsTest.java
> @@ -16,11 +16,15 @@
>   */
>  package org.apache.commons.lang3.exception;
>
> -import org.junit.After;
> -import org.junit.Test;
> -import org.junit.Before;
> -import static org.junit.Assert.*;
> +import static org.junit.Assert.assertEquals;
> +import static org.junit.Assert.assertFalse;
> +import static org.junit.Assert.assertNotNull;
> +import static org.junit.Assert.assertSame;
> +import static org.junit.Assert.assertTrue;
> +import static org.junit.Assert.fail;
> +
>  import java.io.ByteArrayOutputStream;
> +import java.io.IOException;
>  import java.io.PrintStream;
>  import java.io.PrintWriter;
>  import java.io.StringWriter;
> @@ -28,6 +32,11 @@ import java.lang.reflect.Constructor;
>  import java.lang.reflect.Modifier;
>  import java.util.List;
>
> +import org.junit.After;
> +import org.junit.Assert;
> +import org.junit.Before;
> +import org.junit.Test;
> +
>  /**
>   * Tests {@link org.apache.commons.lang3.exception.ExceptionUtils}.
>   *
> @@ -535,4 +544,47 @@ public class ExceptionUtilsTest {
>          public NestableException(final Throwable t) { super(t); }
>      }
>
> +    @Test
> +    public void testThrow() {
> +        Exception expected = new InterruptedException();
> +        try {
> +            ExceptionUtils.rethrow(expected);
> +            Assert.fail("Exception not thrown");
> +        }
> +        catch(Exception actual) {
> +            Assert.assertSame(expected, actual);
> +        }
> +    }
> +
> +    @Test
> +    public void testCatchTechniques() {
> +        try {
> +            throwsCheckedException();
> +            Assert.fail("Exception not thrown");
> +        }
> +        catch(Exception ioe) {
> +            assertTrue(ioe instanceof IOException);
> +            assertEquals(1, ExceptionUtils.getThrowableCount(ioe));
> +        }
> +
> +        try {
> +            redeclareCheckedException();
> +            Assert.fail("Exception not thrown");
> +        }
> +        catch(IOException ioe) {
> +            assertEquals(1, ExceptionUtils.getThrowableCount(ioe));
> +        }
> +    }
> +
> +    private static int redeclareCheckedException() throws IOException {
> +        return throwsCheckedException();
> +    }
> +
> +    private static int throwsCheckedException() {
> +        try {
> +            throw new IOException();
> +        } catch (Exception e) {
> +            return ExceptionUtils.rethrow(e);
>

This line fails on Java 6, see
https://travis-ci.org/apache/commons-lang/jobs/72455431#L1406
Can we fix this?

Benedikt


> +        }
> +    }
>  }
>
>


-- 
http://people.apache.org/~britter/
http://www.systemoutprintln.de/
http://twitter.com/BenediktRitter
http://github.com/britter

Re: [lang] LANG-1149 Ability to throw checked exceptions without declaring them

Posted by ch...@honton.org.
Done.

Quoting Benedikt Ritter <br...@apache.org>:

>
> This line fails on Java 6, see
> https://travis-ci.org/apache/commons-lang/jobs/72455431#L1406
> Can we fix this?
>
> Benedikt
>




---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org