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