Add Result<T>
This commit is contained in:
parent
1923b849dd
commit
470cd2fc24
5 changed files with 342 additions and 0 deletions
58
src/main/java/net/kemitix/mon/result/Err.java
Normal file
58
src/main/java/net/kemitix/mon/result/Err.java
Normal file
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 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;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* An Error Result.
|
||||
*
|
||||
* @param <T> the type of the value in the Result if it has been a success
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
class Err<T> implements Result<T> {
|
||||
|
||||
private final Throwable error;
|
||||
|
||||
@Override
|
||||
public boolean isError() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOkay() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> Result<R> flatMap(final Function<T, Result<R>> f) {
|
||||
return Result.error(error);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void match(final Consumer<T> onSuccess, final Consumer<Throwable> onError) {
|
||||
onError.accept(error);
|
||||
}
|
||||
}
|
90
src/main/java/net/kemitix/mon/result/Result.java
Normal file
90
src/main/java/net/kemitix/mon/result/Result.java
Normal file
|
@ -0,0 +1,90 @@
|
|||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 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;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* An Either type for holding a result or an error (exception).
|
||||
*
|
||||
* @param <T> the type of the result when a success
|
||||
*
|
||||
* @author Paul Campbell (pcampbell@kemitix.net)
|
||||
*/
|
||||
public interface Result<T> {
|
||||
|
||||
/**
|
||||
* Create a Result for a success.
|
||||
*
|
||||
* @param value the value
|
||||
* @param <T> the type of the value
|
||||
* @return a successful Result
|
||||
*/
|
||||
static <T> Result<T> ok(final T value) {
|
||||
return new Success<T>(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Result for an error.
|
||||
*
|
||||
* @param error the error (exception)
|
||||
* @param <T> the type had the result been a success
|
||||
* @return an error Result
|
||||
*/
|
||||
static <T> Result<T> error(final Throwable error) {
|
||||
return new Err<T>(error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks of the Result is an error.
|
||||
*
|
||||
* @return true if the Result is an error.
|
||||
*/
|
||||
boolean isError();
|
||||
|
||||
/**
|
||||
* Checks of the Result is a success.
|
||||
*
|
||||
* @return true if the Result is a success.
|
||||
*/
|
||||
boolean isOkay();
|
||||
|
||||
/**
|
||||
* Returns a new Result consisting of the result of applying the function to the contents of the Result.
|
||||
*
|
||||
* @param f the mapping function the produces a Result
|
||||
* @param <R> the type of the result of the mapping function
|
||||
*
|
||||
* @return a Result
|
||||
*/
|
||||
<R> Result<R> flatMap(Function<T, Result<R>> f);
|
||||
|
||||
/**
|
||||
* Matches the Result, either success or error, and supplies the appropriate Consumer with the value or error.
|
||||
*
|
||||
* @param onSuccess the Consumer to pass the value of a successful Result to
|
||||
* @param onError the Consumer to pass the error from an error Result to
|
||||
*/
|
||||
void match(Consumer<T> onSuccess, Consumer<Throwable> onError);
|
||||
|
||||
}
|
58
src/main/java/net/kemitix/mon/result/Success.java
Normal file
58
src/main/java/net/kemitix/mon/result/Success.java
Normal file
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 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;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* A Successful Result.
|
||||
*
|
||||
* @param <T> the type of the value in the Result
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
class Success<T> implements Result<T> {
|
||||
|
||||
private final T value;
|
||||
|
||||
@Override
|
||||
public boolean isError() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOkay() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> Result<R> flatMap(final Function<T, Result<R>> f) {
|
||||
return f.apply(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void match(final Consumer<T> onSuccess, final Consumer<Throwable> onError) {
|
||||
onSuccess.accept(value);
|
||||
}
|
||||
}
|
30
src/main/java/net/kemitix/mon/result/package-info.java
Normal file
30
src/main/java/net/kemitix/mon/result/package-info.java
Normal file
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An experiment in creating something similar to a Type-Alias in Java.
|
||||
*
|
||||
* <p>Ideas initially lifted from the Design with Types series at https://fsharpforfunandprofit.com/</p>
|
||||
*
|
||||
* @author Paul Campbell (pcampbell@kemitix.net)
|
||||
*/
|
||||
|
||||
package net.kemitix.mon.result;
|
106
src/test/java/net/kemitix/mon/ResultTest.java
Normal file
106
src/test/java/net/kemitix/mon/ResultTest.java
Normal file
|
@ -0,0 +1,106 @@
|
|||
package net.kemitix.mon;
|
||||
|
||||
import net.kemitix.mon.result.Result;
|
||||
import org.assertj.core.api.WithAssertions;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ResultTest implements WithAssertions {
|
||||
|
||||
@Test
|
||||
public void createSuccess_isSuccess() {
|
||||
//when
|
||||
final Result<String> result = Result.ok("good");
|
||||
//then
|
||||
assertThat(result.isOkay()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createSuccess_isNotError() {
|
||||
//when
|
||||
final Result<String> result = Result.ok("good");
|
||||
//then
|
||||
assertThat(result.isError()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createSuccess_matchSuccess() {
|
||||
//given
|
||||
final Result<String> result = Result.ok("good");
|
||||
//then
|
||||
result.match(
|
||||
success -> assertThat(success).isEqualTo("good"),
|
||||
error -> fail("not an error")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createError_isError() {
|
||||
//when
|
||||
final Result<String> result = Result.error(new Exception());
|
||||
//then
|
||||
assertThat(result.isOkay()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createError_isNotSuccess() {
|
||||
//when
|
||||
final Result<String> result = Result.error(new Exception());
|
||||
//then
|
||||
assertThat(result.isError()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createError_matchError() {
|
||||
//given
|
||||
final Result<Object> result = Result.error(new Exception("bad"));
|
||||
//then
|
||||
result.match(
|
||||
success -> fail("not a success"),
|
||||
error -> assertThat(error.getMessage()).isEqualTo("bad")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void successFlatMap_success_isSuccess() {
|
||||
//given
|
||||
final Result<String> result = Result.ok("good");
|
||||
//when
|
||||
final Result<String> flatMap = result.flatMap(v -> Result.ok(v.toUpperCase()));
|
||||
//then
|
||||
assertThat(flatMap.isOkay()).isTrue();
|
||||
flatMap.match(
|
||||
success -> assertThat(success).isEqualTo("GOOD"),
|
||||
error -> fail("not an error")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void successFlatMap_error_isError() {
|
||||
//given
|
||||
final Result<String> result = Result.ok("good");
|
||||
//when
|
||||
final Result<String> flatMap = result.flatMap(v -> Result.error(new Exception("bad flat map")));
|
||||
//then
|
||||
assertThat(flatMap.isOkay()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void errorFlatMap_success_isError() {
|
||||
//given
|
||||
final Result<String> result = Result.error(new Exception("bad"));
|
||||
//when
|
||||
final Result<String> flatMap = result.flatMap(v -> Result.ok(v.toUpperCase()));
|
||||
//then
|
||||
assertThat(flatMap.isError()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void errorFlatMap_error_isError() {
|
||||
//given
|
||||
final Result<String> result = Result.error(new Exception("bad"));
|
||||
//when
|
||||
final Result<String> flatMap = result.flatMap(v -> Result.error(new Exception("bad flat map")));
|
||||
//then
|
||||
assertThat(flatMap.isError()).isTrue();
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue