Hello, 2015-07-12 0:42 GMT+02:00 <c...@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 <c...@apache.org> > Authored: Sat Jul 11 15:41:56 2015 -0700 > Committer: Chas Honton <c...@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