-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add result/error return type (#1369)
- Loading branch information
1 parent
572a9f7
commit 279eced
Showing
3 changed files
with
265 additions
and
0 deletions.
There are no files selected for viewing
99 changes: 99 additions & 0 deletions
99
commons/src/main/java/io/github/martinwitt/laughing_train/commons/result/Error.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
package io.github.martinwitt.laughing_train.commons.result; | ||
|
||
import static java.util.Objects.requireNonNull; | ||
|
||
import java.util.Objects; | ||
import java.util.function.Consumer; | ||
import java.util.function.Function; | ||
import java.util.function.Supplier; | ||
|
||
class Error<T> implements Result<T> { | ||
|
||
private final Throwable throwable; | ||
|
||
Error(Throwable throwable) { | ||
this.throwable = throwable; | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
private <E extends Throwable> T propagate(Throwable throwable) throws E { | ||
throw (E) throwable; | ||
} | ||
|
||
@Override | ||
public boolean isOk() { | ||
return false; | ||
} | ||
|
||
@Override | ||
public void ifOk(Consumer<? super T> consumer) { | ||
// Do nothing when trying to consume the value of an Error result. | ||
} | ||
|
||
@Override | ||
public boolean isError() { | ||
return true; | ||
} | ||
|
||
@Override | ||
public void ifError(Consumer<? super Throwable> consumer) { | ||
requireNonNull(consumer, "The error consumer cannot be null"); | ||
consumer.accept(throwable); | ||
} | ||
|
||
@Override | ||
public Result<T> switchIfError(Function<? super Throwable, ? extends Result<T>> fallbackMethod) { | ||
requireNonNull(fallbackMethod, "The fallback method cannot be null"); | ||
return fallbackMethod.apply(throwable); | ||
} | ||
|
||
@Override | ||
public <U> Result<U> map(Function<? super T, ? extends U> mapper) { | ||
return new Error<>(throwable); | ||
} | ||
|
||
@Override | ||
public <U> Result<U> flatMap(Function<? super T, ? extends Result<U>> mapper) { | ||
return new Error<>(throwable); | ||
} | ||
|
||
@Override | ||
public Result<T> mapError(Function<? super Throwable, ? extends Throwable> mapper) { | ||
requireNonNull(mapper, "The error mapper cannot be null"); | ||
return new Error<>(mapper.apply(throwable)); | ||
} | ||
|
||
@Override | ||
public T get() { | ||
return propagate(throwable); | ||
} | ||
|
||
@Override | ||
public T getOrElse(Supplier<? extends T> supplier) { | ||
requireNonNull(supplier); | ||
return supplier.get(); | ||
} | ||
|
||
@Override | ||
public Throwable getError() { | ||
return throwable; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) return true; | ||
if (null == o || getClass() != o.getClass()) return false; | ||
Error<?> error = (Error<?>) o; | ||
return Objects.equals(throwable, error.throwable); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(throwable); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "Error{" + "throwable=" + throwable + '}'; | ||
} | ||
} |
89 changes: 89 additions & 0 deletions
89
commons/src/main/java/io/github/martinwitt/laughing_train/commons/result/Ok.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package io.github.martinwitt.laughing_train.commons.result; | ||
|
||
import static java.util.Objects.requireNonNull; | ||
|
||
import java.util.NoSuchElementException; | ||
import java.util.Objects; | ||
import java.util.function.Consumer; | ||
import java.util.function.Function; | ||
import java.util.function.Supplier; | ||
|
||
class Ok<T> implements Result<T> { | ||
|
||
private final T value; | ||
|
||
Ok(T value) { | ||
this.value = value; | ||
} | ||
|
||
@Override | ||
public boolean isOk() { | ||
return true; | ||
} | ||
|
||
@Override | ||
public void ifOk(Consumer<? super T> consumer) { | ||
requireNonNull(consumer, "The value consumer cannot be null"); | ||
consumer.accept(value); | ||
} | ||
|
||
@Override | ||
public boolean isError() { | ||
return false; | ||
} | ||
|
||
@Override | ||
public void ifError(Consumer<? super Throwable> consumer) { | ||
// Do nothing when trying to consume the error of an Ok result. | ||
} | ||
|
||
@Override | ||
public Result<T> switchIfError(Function<? super Throwable, ? extends Result<T>> fallbackMethod) { | ||
return new Ok<>(value); | ||
} | ||
|
||
@Override | ||
public <U> Result<U> map(Function<? super T, ? extends U> mapper) { | ||
requireNonNull(mapper, "The value mapper cannot be null"); | ||
return new Ok<>(mapper.apply(value)); | ||
} | ||
|
||
@Override | ||
public <U> Result<U> flatMap(Function<? super T, ? extends Result<U>> mapper) { | ||
requireNonNull(mapper, "The value flat-mapper cannot be null"); | ||
return mapper.apply(value); | ||
} | ||
|
||
@Override | ||
public Result<T> mapError(Function<? super Throwable, ? extends Throwable> mapper) { | ||
return new Ok<>(value); | ||
} | ||
|
||
@Override | ||
public T get() { | ||
return value; | ||
} | ||
|
||
@Override | ||
public T getOrElse(Supplier<? extends T> supplier) { | ||
return value; | ||
} | ||
|
||
@Override | ||
public Throwable getError() { | ||
throw new NoSuchElementException("Result contains a value: " + value.toString()); | ||
} | ||
|
||
@Override | ||
public boolean equals(Object obj) { | ||
if (this == obj) return true; | ||
if (null == obj || getClass() != obj.getClass()) return false; | ||
Ok<?> ok = (Ok<?>) obj; | ||
return Objects.equals(value, ok.value); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(value); | ||
} | ||
} |
77 changes: 77 additions & 0 deletions
77
commons/src/main/java/io/github/martinwitt/laughing_train/commons/result/Result.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package io.github.martinwitt.laughing_train.commons.result; | ||
|
||
import static java.util.Objects.nonNull; | ||
import static java.util.Objects.requireNonNull; | ||
|
||
import java.util.NoSuchElementException; | ||
import java.util.Optional; | ||
import java.util.function.Consumer; | ||
import java.util.function.Function; | ||
import java.util.function.Supplier; | ||
|
||
public interface Result<T> { | ||
|
||
static <T> Result<T> ok(T value) { | ||
requireNonNull(value, "The value of a Result cannot be null"); | ||
return new Ok<>(value); | ||
} | ||
|
||
static <T, E extends Throwable> Result<T> error(E throwable) { | ||
requireNonNull(throwable, "The error of a Result cannot be null"); | ||
return new Error<>(throwable); | ||
} | ||
|
||
static <T> Result<T> of(Supplier<T> supplier) { | ||
requireNonNull(supplier, "The value supplier cannot be null"); | ||
|
||
try { | ||
return ok(supplier.get()); | ||
} catch (Exception error) { | ||
return error(error); | ||
} | ||
} | ||
|
||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType") | ||
static <T> Result<T> of(Optional<T> optional) { | ||
requireNonNull(optional, "The optional value cannot be null"); | ||
|
||
return optional | ||
.map(Result::ok) | ||
.orElseGet( | ||
() -> | ||
error(new NoSuchElementException("No value present when unwrapping the optional"))); | ||
} | ||
|
||
static <T> Result<T> ofNullable(T value) { | ||
return ofNullable( | ||
value, () -> new NullPointerException("The result was initialized with a null value")); | ||
} | ||
|
||
static <T> Result<T> ofNullable(T value, Supplier<? extends Throwable> errorSupplier) { | ||
requireNonNull(errorSupplier, "The error supplier cannot be null"); | ||
|
||
return nonNull(value) ? ok(value) : error(errorSupplier.get()); | ||
} | ||
|
||
boolean isOk(); | ||
|
||
void ifOk(Consumer<? super T> consumer); | ||
|
||
boolean isError(); | ||
|
||
void ifError(Consumer<? super Throwable> consumer); | ||
|
||
Result<T> switchIfError(Function<? super Throwable, ? extends Result<T>> fallbackMethod); | ||
|
||
<U> Result<U> map(Function<? super T, ? extends U> mapper); | ||
|
||
<U> Result<U> flatMap(Function<? super T, ? extends Result<U>> mapper); | ||
|
||
Result<T> mapError(Function<? super Throwable, ? extends Throwable> mapper); | ||
|
||
T get(); | ||
|
||
T getOrElse(Supplier<? extends T> supplier); | ||
|
||
Throwable getError(); | ||
} |