Merge branch 'result' into 'master'
Add Result<T> See merge request kemitix/mon!33
This commit is contained in:
commit
7cae02bc58
6 changed files with 343 additions and 1 deletions
|
@ -4,7 +4,7 @@ CHANGELOG
|
||||||
0.7.0
|
0.7.0
|
||||||
-----
|
-----
|
||||||
|
|
||||||
*
|
* Add `Result`
|
||||||
|
|
||||||
0.6.0
|
0.6.0
|
||||||
-----
|
-----
|
||||||
|
|
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