diff --git a/src/main/java/net/kemitix/mon/result/Err.java b/src/main/java/net/kemitix/mon/result/Err.java index b22de8a..01bf9b5 100644 --- a/src/main/java/net/kemitix/mon/result/Err.java +++ b/src/main/java/net/kemitix/mon/result/Err.java @@ -73,8 +73,22 @@ class Err implements Result { } @Override - public T orElseThrow() throws MonResultException { - throw MonResultException.with(error); + public T orElseThrow() throws Throwable { + throw error; + } + + @Override + @SuppressWarnings("unchecked") + public T orElseThrow(final Class type) throws E { + if (type.isInstance(error)) { + throw (E) error; + } + throw UnexpectedErrorResultException.with(error); + } + + @Override + public T orElseThrowUnchecked() { + throw ErrorResultException.with(error); } @Override diff --git a/src/main/java/net/kemitix/mon/result/MonResultException.java b/src/main/java/net/kemitix/mon/result/ErrorResultException.java similarity index 74% rename from src/main/java/net/kemitix/mon/result/MonResultException.java rename to src/main/java/net/kemitix/mon/result/ErrorResultException.java index 6611ebd..47e3a90 100644 --- a/src/main/java/net/kemitix/mon/result/MonResultException.java +++ b/src/main/java/net/kemitix/mon/result/ErrorResultException.java @@ -22,13 +22,15 @@ package net.kemitix.mon.result; /** - * An Unchecked wrapper for exceptions thrown within a {@code Result}. + * An unchecked wrapper fot exceptions thrown within a {@link Result}. + * + *

Used by {@link Result#orElseThrowUnchecked()} when the {@link Result} is an error.

* * @author Paul Campbell (pcampbell@kemitix.net) */ -public final class MonResultException extends RuntimeException { +public final class ErrorResultException extends RuntimeException { - private MonResultException(final Throwable cause) { + private ErrorResultException(final Throwable cause) { super(cause); } @@ -36,9 +38,9 @@ public final class MonResultException extends RuntimeException { * Creates a new object. * * @param cause the cause - * @return a MonResultException contain the cause + * @return a {@link ErrorResultException} containing the cause */ - static MonResultException with(final Throwable cause) { - return new MonResultException(cause); + static ErrorResultException with(final Throwable cause) { + return new ErrorResultException(cause); } } diff --git a/src/main/java/net/kemitix/mon/result/Result.java b/src/main/java/net/kemitix/mon/result/Result.java index fcb1022..22a2d81 100644 --- a/src/main/java/net/kemitix/mon/result/Result.java +++ b/src/main/java/net/kemitix/mon/result/Result.java @@ -99,7 +99,7 @@ public interface Result extends Functor> { @SuppressWarnings("illegalcatch") public static Maybe toMaybe(final Result result) { try { - return Maybe.just(result.orElseThrow()); + return Maybe.just(result.orElseThrow(Exception.class)); } catch (final Throwable throwable) { return Maybe.nothing(); } @@ -109,9 +109,28 @@ public interface Result extends Functor> { * Extracts the successful value from the result, or throws the error Throwable. * * @return the value if a success - * @throws MonResultException if the result is an error + * @throws Throwable if the result is an error */ - public abstract T orElseThrow() throws MonResultException; + @SuppressWarnings("illegalthrows") + public abstract T orElseThrow() throws Throwable; + + /** + * Extracts the successful value from the result, or throws the error Throwable. + * + * @param type the type of checked exception that may be thrown + * @param the type of the checked exception to throw + * + * @return the value if a success + * @throws E if the result is an error + */ + public abstract T orElseThrow(Class type) throws E; + + /** + * Extracts the successful value from the result, or throws the error in a {@link UnexpectedErrorResultException}. + * + * @return the value if a success + */ + public abstract T orElseThrowUnchecked(); /** * Swaps the inner Result of a Maybe, so that a Result is on the outside. diff --git a/src/main/java/net/kemitix/mon/result/Success.java b/src/main/java/net/kemitix/mon/result/Success.java index e79e54e..ce49401 100644 --- a/src/main/java/net/kemitix/mon/result/Success.java +++ b/src/main/java/net/kemitix/mon/result/Success.java @@ -75,6 +75,16 @@ class Success implements Result { return value; } + @Override + public T orElseThrow(final Class type) throws E { + return value; + } + + @Override + public T orElseThrowUnchecked() { + return value; + } + @Override public Result peek(final Consumer consumer) { consumer.accept(value); diff --git a/src/main/java/net/kemitix/mon/result/UnexpectedErrorResultException.java b/src/main/java/net/kemitix/mon/result/UnexpectedErrorResultException.java new file mode 100644 index 0000000..ef67f8c --- /dev/null +++ b/src/main/java/net/kemitix/mon/result/UnexpectedErrorResultException.java @@ -0,0 +1,47 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2018 Paul Campbell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package net.kemitix.mon.result; + +/** + * An Unchecked wrapper for unexpected exceptions thrown within a {@link Result}. + * + *

Used by {@link Result#orElseThrow(Class)} when the {@link Result} is an error of a different type to the + * parameter.

+ * + * @author Paul Campbell (pcampbell@kemitix.net) + */ +public final class UnexpectedErrorResultException extends RuntimeException { + + private UnexpectedErrorResultException(final Throwable cause) { + super(cause); + } + + /** + * Creates a new object. + * + * @param cause the cause + * @return a {@link UnexpectedErrorResultException} containing the cause + */ + static UnexpectedErrorResultException with(final Throwable cause) { + return new UnexpectedErrorResultException(cause); + } +} diff --git a/src/test/java/net/kemitix/mon/ResultTest.java b/src/test/java/net/kemitix/mon/ResultTest.java index e15109f..a8cc577 100644 --- a/src/test/java/net/kemitix/mon/ResultTest.java +++ b/src/test/java/net/kemitix/mon/ResultTest.java @@ -2,6 +2,8 @@ package net.kemitix.mon; import lombok.RequiredArgsConstructor; import net.kemitix.mon.maybe.Maybe; +import net.kemitix.mon.result.ErrorResultException; +import net.kemitix.mon.result.UnexpectedErrorResultException; import net.kemitix.mon.result.Result; import org.assertj.core.api.WithAssertions; import org.junit.Test; @@ -292,7 +294,53 @@ public class ResultTest implements WithAssertions { final RuntimeException exception = new RuntimeException(); final Result error = Result.error(exception); //when - assertThatThrownBy(() -> error.orElseThrow()).hasCause(exception); + assertThatThrownBy(() -> error.orElseThrow()).isSameAs(exception); + } + + @Test public void okay_whenOrElseThrowT_isValue() throws Exception { + //given + final Result ok = Result.ok(1); + //when + final Integer value = ok.orElseThrow(Exception.class); + //then + assumeThat(value).isEqualTo(1); + } + + @Test public void errorT_whenOrElseThrowT_throwsT() { + //given + final RuntimeException exception = new RuntimeException(); + final Result error = Result.error(exception); + //then + assertThatThrownBy(() -> error.orElseThrow(RuntimeException.class)).isSameAs(exception); + } + + @Test public void errorR_whenOrElseThrowT_throwsWrappedR() { + //given + final IOException exception = new IOException(); + final Result error = Result.error(exception); + //then + assertThatThrownBy(() -> error.orElseThrow(RuntimeException.class)) + .isInstanceOf(UnexpectedErrorResultException.class) + .hasCause(exception); + } + + @Test public void okay_whenOrElseThrowUnchecked_isValue() { + //given + final Result ok = Result.ok(1); + //when + final Integer value = ok.orElseThrowUnchecked(); + //then + assumeThat(value).isEqualTo(1); + } + + @Test public void error_whenOrElseThrowUnchecked_throwsWrapped() { + //given + final IOException exception = new IOException(); + final Result error = Result.error(exception); + //then + assertThatThrownBy(() -> error.orElseThrowUnchecked()) + .isInstanceOf(ErrorResultException.class) + .hasCause(exception); } @Test