Skip to content

Commit

Permalink
CheckedFunction*.unchecked() now sneaky throws (#1991)
Browse files Browse the repository at this point in the history
  • Loading branch information
danieldietrich authored May 10, 2017
1 parent dd4a2da commit 7e27b04
Show file tree
Hide file tree
Showing 29 changed files with 441 additions and 303 deletions.
71 changes: 37 additions & 34 deletions vavr/generator/Generator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ def generateMainClasses(): Unit = {
*
${(0 to i).gen(j => if (j == 0) "* @param <R> return type" else s"* @param <T$j> type of the ${j.ordinal} argument")("\n")}
* @param f A method reference
* @return A unchecked wrapper of supplied {@link CheckedFunction$i}
* @return An unchecked wrapper of supplied {@link CheckedFunction$i}
*/
public static $fullGenerics Function$i$fullGenerics unchecked(CheckedFunction$i$fullGenerics f) {
return f.unchecked();
Expand Down Expand Up @@ -1445,6 +1445,8 @@ def generateMainClasses(): Unit = {
case _ => s"$i arguments"
}

im.getStatic(s"io.vavr.${className}Module.sneakyThrow")

xs"""
/**
* Represents a function with ${arguments(i)}.
Expand Down Expand Up @@ -1700,26 +1702,18 @@ def generateMainClasses(): Unit = {
}

/$javadoc
* Return unchecked function that will return this $className result in correct case and throw runtime exception
* wrapped by {@code exceptionMapper} in case of throwable
*
* @param exceptionMapper the function that convert function {@link Throwable} into subclass of {@link RuntimeException}
* @return a new Function$i that wraps this CheckedFunction$i by throwing a {@code RuntimeException} issued by the given {@code exceptionMapper} in the case of a failure
*/
default Function$i$fullGenerics unchecked(${im.getType("java.util.function.Function")}<? super Throwable, ? extends RuntimeException> exceptionMapper) {
return recover(throwable -> {
throw exceptionMapper.apply(throwable);
});
}

/$javadoc
* Return unchecked function that will return this $className result in correct case and throw exception
* wrapped by {@link IllegalStateException} in case of throwable.
* Returns an unchecked function that will <em>sneaky throw</em> if an exceptions occurs when applying the function.
*
* @return a new Function$i that wraps this CheckedFunction$i by throwing an {@code IllegalStateException} in the case of a failure
* @return a new Function$i that throws a {@code Throwable}.
*/
default Function$i$fullGenerics unchecked() {
return unchecked(IllegalStateException::new);
return ($params) -> {
try {
return apply($params);
} catch(Throwable t) {
return sneakyThrow(t);
}
};
}
""")}

Expand Down Expand Up @@ -1753,6 +1747,15 @@ def generateMainClasses(): Unit = {
}
""")}
}

interface ${className}Module {

// DEV-NOTE: we do not plan to expose this as public API
@SuppressWarnings("unchecked")
static <T extends Throwable, R> R sneakyThrow(Throwable t) throws T {
throw (T) t;
}
}
"""
}
})
Expand Down Expand Up @@ -3039,11 +3042,11 @@ def generateTestClasses(): Unit = {
assertThat(md5.getDigestLength()).isEqualTo(16);
}

@$test(expected = IllegalStateException.class)
public void shouldUncheckedThrowIllegalState() {
@$test(expected = ${im.getType("java.security.NoSuchAlgorithmException")}.class)
public void shouldThrowCheckedExceptionWhenUnchecked() {
$name$i<MessageDigest> digest = () -> ${im.getType("java.security.MessageDigest")}.getInstance("Unknown");
Function$i<MessageDigest> unchecked = digest.unchecked();
unchecked.apply();
unchecked.apply(); // Look ma, we throw an undeclared checked exception!
}

@$test
Expand Down Expand Up @@ -3074,8 +3077,8 @@ def generateTestClasses(): Unit = {

@$test
public void shouldRecover() {
Function$i<${(1 to i).gen(j => "String")(", ")}, MessageDigest> recover = digest.recover(throwable -> (${(1 to i).gen(j => s"s$j")(", ")}) -> null);
MessageDigest md5 = recover.apply(${toArgList("MD5")});
final Function$i<${(1 to i).gen(j => "String")(", ")}, MessageDigest> recover = digest.recover(throwable -> (${(1 to i).gen(j => s"s$j")(", ")}) -> null);
final MessageDigest md5 = recover.apply(${toArgList("MD5")});
assertThat(md5).isNotNull();
assertThat(md5.getAlgorithm()).isEqualToIgnoringCase("MD5");
assertThat(md5.getDigestLength()).isEqualTo(16);
Expand All @@ -3084,12 +3087,12 @@ def generateTestClasses(): Unit = {

@$test
public void shouldRecoverNonNull() {
Function$i<${(1 to i).gen(j => "String")(", ")}, MessageDigest> recover = digest.recover(throwable -> null);
MessageDigest md5 = recover.apply(${toArgList("MD5")});
final Function$i<${(1 to i).gen(j => "String")(", ")}, MessageDigest> recover = digest.recover(throwable -> null);
final MessageDigest md5 = recover.apply(${toArgList("MD5")});
assertThat(md5).isNotNull();
assertThat(md5.getAlgorithm()).isEqualToIgnoringCase("MD5");
assertThat(md5.getDigestLength()).isEqualTo(16);
${im.getType("io.vavr.control.Try")}<MessageDigest> unknown = Function$i.liftTry(recover).apply(${toArgList("Unknown")});
final ${im.getType("io.vavr.control.Try")}<MessageDigest> unknown = Function$i.liftTry(recover).apply(${toArgList("Unknown")});
assertThat(unknown).isNotNull();
assertThat(unknown.isFailure()).isTrue();
assertThat(unknown.getCause()).isNotNull().isInstanceOf(NullPointerException.class);
Expand All @@ -3098,28 +3101,28 @@ def generateTestClasses(): Unit = {

@$test
public void shouldUncheckedWork() {
Function$i<${(1 to i).gen(j => "String")(", ")}, MessageDigest> unchecked = digest.unchecked();
MessageDigest md5 = unchecked.apply(${toArgList("MD5")});
final Function$i<${(1 to i).gen(j => "String")(", ")}, MessageDigest> unchecked = digest.unchecked();
final MessageDigest md5 = unchecked.apply(${toArgList("MD5")});
assertThat(md5).isNotNull();
assertThat(md5.getAlgorithm()).isEqualToIgnoringCase("MD5");
assertThat(md5.getDigestLength()).isEqualTo(16);
}

@$test(expected = IllegalStateException.class)
@$test(expected = ${im.getType("java.security.NoSuchAlgorithmException")}.class)
public void shouldUncheckedThrowIllegalState() {
Function$i<${(1 to i).gen(j => "String")(", ")}, MessageDigest> unchecked = digest.unchecked();
unchecked.apply(${toArgList("Unknown")});
final Function$i<${(1 to i).gen(j => "String")(", ")}, MessageDigest> unchecked = digest.unchecked();
unchecked.apply(${toArgList("Unknown")}); // Look ma, we throw an undeclared checked exception!
}

@$test
public void shouldLiftTryPartialFunction() {
Function$i<${(1 to i).gen(j => "String")(", ")}, Try<MessageDigest>> liftTry = $name$i.liftTry(digest);
${im.getType("io.vavr.control.Try")}<MessageDigest> md5 = liftTry.apply(${toArgList("MD5")});
final Function$i<${(1 to i).gen(j => "String")(", ")}, Try<MessageDigest>> liftTry = $name$i.liftTry(digest);
final ${im.getType("io.vavr.control.Try")}<MessageDigest> md5 = liftTry.apply(${toArgList("MD5")});
assertThat(md5.isSuccess()).isTrue();
assertThat(md5.get()).isNotNull();
assertThat(md5.get().getAlgorithm()).isEqualToIgnoringCase("MD5");
assertThat(md5.get().getDigestLength()).isEqualTo(16);
${im.getType("io.vavr.control.Try")}<MessageDigest> unknown = liftTry.apply(${toArgList("Unknown")});
final ${im.getType("io.vavr.control.Try")}<MessageDigest> unknown = liftTry.apply(${toArgList("Unknown")});
assertThat(unknown.isFailure()).isTrue();
assertThat(unknown.getCause()).isNotNull();
assertThat(unknown.getCause().getMessage()).isEqualToIgnoringCase("Unknown MessageDigest not available");
Expand Down
18 changes: 9 additions & 9 deletions vavr/src-gen/main/java/io/vavr/API.java
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ public static <T1, T2, T3, T4, T5, T6, T7, T8, R> CheckedFunction8<T1, T2, T3, T
*
* @param <R> return type
* @param f A method reference
* @return A unchecked wrapper of supplied {@link CheckedFunction0}
* @return An unchecked wrapper of supplied {@link CheckedFunction0}
*/
public static <R> Function0<R> unchecked(CheckedFunction0<R> f) {
return f.unchecked();
Expand All @@ -473,7 +473,7 @@ public static <R> Function0<R> unchecked(CheckedFunction0<R> f) {
* @param <R> return type
* @param <T1> type of the 1st argument
* @param f A method reference
* @return A unchecked wrapper of supplied {@link CheckedFunction1}
* @return An unchecked wrapper of supplied {@link CheckedFunction1}
*/
public static <T1, R> Function1<T1, R> unchecked(CheckedFunction1<T1, R> f) {
return f.unchecked();
Expand All @@ -486,7 +486,7 @@ public static <T1, R> Function1<T1, R> unchecked(CheckedFunction1<T1, R> f) {
* @param <T1> type of the 1st argument
* @param <T2> type of the 2nd argument
* @param f A method reference
* @return A unchecked wrapper of supplied {@link CheckedFunction2}
* @return An unchecked wrapper of supplied {@link CheckedFunction2}
*/
public static <T1, T2, R> Function2<T1, T2, R> unchecked(CheckedFunction2<T1, T2, R> f) {
return f.unchecked();
Expand All @@ -500,7 +500,7 @@ public static <T1, T2, R> Function2<T1, T2, R> unchecked(CheckedFunction2<T1, T2
* @param <T2> type of the 2nd argument
* @param <T3> type of the 3rd argument
* @param f A method reference
* @return A unchecked wrapper of supplied {@link CheckedFunction3}
* @return An unchecked wrapper of supplied {@link CheckedFunction3}
*/
public static <T1, T2, T3, R> Function3<T1, T2, T3, R> unchecked(CheckedFunction3<T1, T2, T3, R> f) {
return f.unchecked();
Expand All @@ -515,7 +515,7 @@ public static <T1, T2, T3, R> Function3<T1, T2, T3, R> unchecked(CheckedFunction
* @param <T3> type of the 3rd argument
* @param <T4> type of the 4th argument
* @param f A method reference
* @return A unchecked wrapper of supplied {@link CheckedFunction4}
* @return An unchecked wrapper of supplied {@link CheckedFunction4}
*/
public static <T1, T2, T3, T4, R> Function4<T1, T2, T3, T4, R> unchecked(CheckedFunction4<T1, T2, T3, T4, R> f) {
return f.unchecked();
Expand All @@ -531,7 +531,7 @@ public static <T1, T2, T3, T4, R> Function4<T1, T2, T3, T4, R> unchecked(Checked
* @param <T4> type of the 4th argument
* @param <T5> type of the 5th argument
* @param f A method reference
* @return A unchecked wrapper of supplied {@link CheckedFunction5}
* @return An unchecked wrapper of supplied {@link CheckedFunction5}
*/
public static <T1, T2, T3, T4, T5, R> Function5<T1, T2, T3, T4, T5, R> unchecked(CheckedFunction5<T1, T2, T3, T4, T5, R> f) {
return f.unchecked();
Expand All @@ -548,7 +548,7 @@ public static <T1, T2, T3, T4, T5, R> Function5<T1, T2, T3, T4, T5, R> unchecked
* @param <T5> type of the 5th argument
* @param <T6> type of the 6th argument
* @param f A method reference
* @return A unchecked wrapper of supplied {@link CheckedFunction6}
* @return An unchecked wrapper of supplied {@link CheckedFunction6}
*/
public static <T1, T2, T3, T4, T5, T6, R> Function6<T1, T2, T3, T4, T5, T6, R> unchecked(CheckedFunction6<T1, T2, T3, T4, T5, T6, R> f) {
return f.unchecked();
Expand All @@ -566,7 +566,7 @@ public static <T1, T2, T3, T4, T5, T6, R> Function6<T1, T2, T3, T4, T5, T6, R> u
* @param <T6> type of the 6th argument
* @param <T7> type of the 7th argument
* @param f A method reference
* @return A unchecked wrapper of supplied {@link CheckedFunction7}
* @return An unchecked wrapper of supplied {@link CheckedFunction7}
*/
public static <T1, T2, T3, T4, T5, T6, T7, R> Function7<T1, T2, T3, T4, T5, T6, T7, R> unchecked(CheckedFunction7<T1, T2, T3, T4, T5, T6, T7, R> f) {
return f.unchecked();
Expand All @@ -585,7 +585,7 @@ public static <T1, T2, T3, T4, T5, T6, T7, R> Function7<T1, T2, T3, T4, T5, T6,
* @param <T7> type of the 7th argument
* @param <T8> type of the 8th argument
* @param f A method reference
* @return A unchecked wrapper of supplied {@link CheckedFunction8}
* @return An unchecked wrapper of supplied {@link CheckedFunction8}
*/
public static <T1, T2, T3, T4, T5, T6, T7, T8, R> Function8<T1, T2, T3, T4, T5, T6, T7, T8, R> unchecked(CheckedFunction8<T1, T2, T3, T4, T5, T6, T7, T8, R> f) {
return f.unchecked();
Expand Down
37 changes: 20 additions & 17 deletions vavr/src-gen/main/java/io/vavr/CheckedFunction0.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
G E N E R A T O R C R A F T E D
\*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

import static io.vavr.CheckedFunction0Module.sneakyThrow;

import io.vavr.control.Option;
import io.vavr.control.Try;
import java.util.Objects;
Expand Down Expand Up @@ -176,26 +178,18 @@ default Function0<R> recover(Function<? super Throwable, ? extends Supplier<? ex
}

/**
* Return unchecked function that will return this CheckedFunction0 result in correct case and throw runtime exception
* wrapped by {@code exceptionMapper} in case of throwable
* Returns an unchecked function that will <em>sneaky throw</em> if an exceptions occurs when applying the function.
*
* @param exceptionMapper the function that convert function {@link Throwable} into subclass of {@link RuntimeException}
* @return a new Function0 that wraps this CheckedFunction0 by throwing a {@code RuntimeException} issued by the given {@code exceptionMapper} in the case of a failure
*/
default Function0<R> unchecked(Function<? super Throwable, ? extends RuntimeException> exceptionMapper) {
return recover(throwable -> {
throw exceptionMapper.apply(throwable);
});
}

/**
* Return unchecked function that will return this CheckedFunction0 result in correct case and throw exception
* wrapped by {@link IllegalStateException} in case of throwable.
*
* @return a new Function0 that wraps this CheckedFunction0 by throwing an {@code IllegalStateException} in the case of a failure
* @return a new Function0 that throws a {@code Throwable}.
*/
default Function0<R> unchecked() {
return unchecked(IllegalStateException::new);
return () -> {
try {
return apply();
} catch(Throwable t) {
return sneakyThrow(t);
}
};
}

/**
Expand All @@ -212,4 +206,13 @@ default <V> CheckedFunction0<V> andThen(CheckedFunction1<? super R, ? extends V>
return () -> after.apply(apply());
}

}

interface CheckedFunction0Module {

// DEV-NOTE: we do not plan to expose this as public API
@SuppressWarnings("unchecked")
static <T extends Throwable, R> R sneakyThrow(Throwable t) throws T {
throw (T) t;
}
}
37 changes: 20 additions & 17 deletions vavr/src-gen/main/java/io/vavr/CheckedFunction1.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
G E N E R A T O R C R A F T E D
\*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

import static io.vavr.CheckedFunction1Module.sneakyThrow;

import io.vavr.control.Option;
import io.vavr.control.Try;
import java.util.HashMap;
Expand Down Expand Up @@ -195,26 +197,18 @@ default Function1<T1, R> recover(Function<? super Throwable, ? extends Function<
}

/**
* Return unchecked function that will return this CheckedFunction1 result in correct case and throw runtime exception
* wrapped by {@code exceptionMapper} in case of throwable
* Returns an unchecked function that will <em>sneaky throw</em> if an exceptions occurs when applying the function.
*
* @param exceptionMapper the function that convert function {@link Throwable} into subclass of {@link RuntimeException}
* @return a new Function1 that wraps this CheckedFunction1 by throwing a {@code RuntimeException} issued by the given {@code exceptionMapper} in the case of a failure
*/
default Function1<T1, R> unchecked(Function<? super Throwable, ? extends RuntimeException> exceptionMapper) {
return recover(throwable -> {
throw exceptionMapper.apply(throwable);
});
}

/**
* Return unchecked function that will return this CheckedFunction1 result in correct case and throw exception
* wrapped by {@link IllegalStateException} in case of throwable.
*
* @return a new Function1 that wraps this CheckedFunction1 by throwing an {@code IllegalStateException} in the case of a failure
* @return a new Function1 that throws a {@code Throwable}.
*/
default Function1<T1, R> unchecked() {
return unchecked(IllegalStateException::new);
return (t1) -> {
try {
return apply(t1);
} catch(Throwable t) {
return sneakyThrow(t);
}
};
}

/**
Expand Down Expand Up @@ -244,4 +238,13 @@ default <V> CheckedFunction1<V, R> compose(CheckedFunction1<? super V, ? extends
Objects.requireNonNull(before, "before is null");
return v -> apply(before.apply(v));
}
}

interface CheckedFunction1Module {

// DEV-NOTE: we do not plan to expose this as public API
@SuppressWarnings("unchecked")
static <T extends Throwable, R> R sneakyThrow(Throwable t) throws T {
throw (T) t;
}
}
Loading

0 comments on commit 7e27b04

Please sign in to comment.