public interface Promise<T>
This library hopes to improve developer QoL by improving flexibility "out of the box", with minimal additional
complexity, when writing code or libraries that require asynchronous operation. It is deliberately simplistic, in
contrast to the somewhat similar, native Java 8 CompletionStage
implementation.
A promise must have a state PromiseState
, and can be resolved at most once. A PENDING
promise
is considered unresolved, and may transition to either FULFILLED
, on success, resolving with a value of
either type T
or null
, OR it may resolve as REJECTED
on failure, with a non-null
Throwable
.
When a promise changes from it's initial PENDING
state, it resolves, which will cause it to either
fulfill or reject, into either states FULFILLED
or REJECTED
, respectively. Naming a
method or callback parameter "fulfill" implies it is an action that can be taken that will always
resolve the promise as FULFILLED
, unless an error occurs. The name "reject" follows the same guidelines, and
the name "resolve" should have the possibility of performing either action, but may always fulfill.
When a promise's value is referred to, within this interface, it refers to either the FULFILLED
value, returned by thenSync()
, for example, OR, if the promise REJECTED
, it refers to a non-null
Throwable
, which could be accessed via exceptSync()
. A PENDING
promise has no value.
Promises should implement this interface in full, in whatever manner suits the application, in addition to a
corresponding PromiseFactory
, which can be coupled with extending PromiseApi
. Doing this will allow
the implementer to simply pass a factory/api instance into the provided abstract PromiseTest
,
PromiseFactoryTest
, and PromiseApiTest
classes, and run the provided JUnit 4 tests.
Beyond these guidelines there are no restrictions. It should be noted that this interface does not guarantee the
execution order of (promise) state associated asynchronous code, like CompletionStage
,
and unlike the JavaScript A+ promise specification (e.g. then callbacks).
All methods that are part of this interface must be thread-safe.
Note: It is part of the contract of this interface that no method may block unless the method name ends in "sync", OR due to an INTERNAL lock in place to allow thread-safety.
If a null
object argument is passed to any method, then a NullPointerException
will be thrown.
Modifier and Type | Method and Description |
---|---|
<U> Promise<U> |
always(java.util.function.BiFunction<? super T,java.lang.Throwable,? extends Promise<? extends U>> callback)
Specify a callback that will always run on resolution, or as soon as possible if
this is already in
a resolved state. |
Promise<T> |
except(java.util.function.BiConsumer<java.lang.Throwable,java.util.function.Consumer<? super T>> callback)
Specify a callback to be run if this resolves with a failed state
REJECTED , and return a new promise,
that will fulfill with the value accepted within the callback, into it's second argument, a Consumer . |
Promise<T> |
except(java.util.function.Function<java.lang.Throwable,? extends Promise<? extends T>> callback)
Specify a callback to be run if this resolves with a failed state
REJECTED , and return a new promise,
that will resolve with the same state and value as the callback's returned promise, after the callback
promise resolves. |
java.lang.Throwable |
exceptSync()
Calling this method will block until the promise is resolved, returning a value if it resolved with
REJECTED , otherwise returning null . |
PromiseState |
getState()
Get the current state of the promise.
|
void |
sync()
Calling this method will block the current thread until
this is resolved (not PENDING ). |
<U> Promise<U> |
then(java.util.function.BiConsumer<? super T,java.util.function.Consumer<? super U>> callback)
Specify a callback to be run on successful resolution
FULFILLED of this, and return a new promise,
that will fulfill with the value accepted within the callback, into it's second argument, a Consumer . |
<U> Promise<U> |
then(java.util.function.Function<? super T,? extends Promise<? extends U>> callback)
Specify a callback to be run on successful resolution
FULFILLED of this, and return a new promise,
that will resolve with the same state and value as the callback's returned promise, after the callback
promise resolves. |
T |
thenSync()
Calling this method will block until the promise is resolved, returning a value if it resolved with
FULFILLED , otherwise returning null . |
PromiseState getState()
A promise's initial state is PENDING
, will change at most once, to either resolved states,
FULFILLED
or REJECTED
.
<U> Promise<U> then(java.util.function.Function<? super T,? extends Promise<? extends U>> callback)
FULFILLED
of this, and return a new promise,
that will resolve with the same state and value as the callback's returned promise, after the callback
promise resolves. The input parameter will be the FULFILLED
value of this
.
The callback will be run as soon as possible (but not inline) if this
is already FULFILLED
.
If the callback returns a null
value, then the returned promise will resolve as FULFILLED
with
value null
.
If an exception is thrown within the callback, then the returned promise will be REJECTED
, with that
exception.
If this
resolved with the REJECTED
state, then the returned promise will reflect the state and
value of this
, and the callback will not be run.
U
- The return type of the new promise, dictated by the callback promise's return type.callback
- The operation which will be performed if this
resolves successfully.java.lang.NullPointerException
- If callback is null.<U> Promise<U> then(java.util.function.BiConsumer<? super T,java.util.function.Consumer<? super U>> callback)
FULFILLED
of this, and return a new promise,
that will fulfill with the value accepted within the callback, into it's second argument, a Consumer
.
The callback will be run as soon as possible (but not inline) if this
is already FULFILLED
.
If no call is made to this second argument within the callback, then the resolved value of the returned
promise will be null
, and the state FULFILLED
.
If this
resolves as REJECTED
callback will not be called, and the returned promise will
reject with the same Throwable
.
If an exception is thrown within the callback, then the returned promise will be REJECTED
with that
exception, provided that it has not already resolved.
For example:
Promise<Integer> input = // some async operation which eventually fulfills with int(5)
Promise<Integer> output = input.then((inputValue, fulfill) -> fulfill.accept(inputValue + 10));
// will output 15
System.out.println(output.thenSync());
U
- The return type of the new promise.callback
- The operation which will be performed if the promise resolves successfully.java.lang.NullPointerException
- If callback is null.Promise<T> except(java.util.function.Function<java.lang.Throwable,? extends Promise<? extends T>> callback)
REJECTED
, and return a new promise,
that will resolve with the same state and value as the callback's returned promise, after the callback
promise resolves. The input parameter will be the REJECTED
value of this
(a Throwable
).
To preserve type safety, the returned type of promise within the callback is restricted to things which can be
cast to the type of T
, unlike then(Function)
, which can allow any type, due to the fact that the
no-callback case will only ever result in a Throwable
.
The callback will be run as soon as possible (but not inline) if this
is already REJECTED
.
If the callback returns a null
value, then the returned promise will resolve as FULFILLED
with
value null
.
If an exception is thrown within the callback, then the returned promise will be REJECTED
, with that
exception.
If this
resolved with the FULFILLED
state, then the returned promise will reflect the state and
value of this
, and the callback will not be run.
callback
- The operation which will be performed if the promise resolves exceptionally.java.lang.NullPointerException
- If callback is null.Promise<T> except(java.util.function.BiConsumer<java.lang.Throwable,java.util.function.Consumer<? super T>> callback)
REJECTED
, and return a new promise,
that will fulfill with the value accepted within the callback, into it's second argument, a Consumer
.
To preserve type safety, the type of fulfillment value within the callback is restricted, to things which can be
cast to the type of T
, unlike then(BiConsumer)
, which can allow any type, due to the fact that
the no-callback case will only ever result in a Throwable
.
The callback will be run as soon as possible (but not inline) if this
is already REJECTED
.
If no call is made to this second argument within the callback, then the resolved value of the returned
promise will be null
, and the state FULFILLED
.
If this
resolves as FULFILLED
callback will not be called, and the returned promise will
fulfill with the same value.
If an exception is thrown within the callback, then the returned promise will be REJECTED
with that
exception, provided that it has not already resolved.
For example:
Promise<Object> input = // some async operation which eventually rejects with an exception
Promise<Object> output = input.except((exception, fulfill) -> fulfill.accept(exception));
// will output the string representation of the FULFILLED exception originally REJECTED by input
System.out.println(output.thenSync());
callback
- The operation which will be performed if the promise resolves exceptionally.java.lang.NullPointerException
- If callback is null.<U> Promise<U> always(java.util.function.BiFunction<? super T,java.lang.Throwable,? extends Promise<? extends U>> callback)
this
is already in
a resolved state. Returns a new promise, that will resolve with the same state and value as the callback's return
value (a promise), after the returned promise resolves.
The right input parameter will be the REJECTED
exception (not null
), if this
rejected,
otherwise it can be assumed that the state was FULFILLED
, and the left input parameter will be set, if
the fulfillment value was non-null.
The callback will be run as soon as possible (but not inline) if this
is already resolved.
If the callback returns a null
value, then the returned promise will resolve as FULFILLED
with
value null
.
If an exception is thrown within the callback, then the returned promise will be REJECTED
, with that
exception.
U
- The return type of the new promise, dictated by the callback promise's return type.callback
- The operation to perform when the promise resolves.java.lang.NullPointerException
- If callback is null.void sync()
this
is resolved (not PENDING
).
All responsibility for sane use of this method lies with the caller.
T thenSync()
FULFILLED
, otherwise returning null
.null
if REJECTED
.sync()
java.lang.Throwable exceptSync()
REJECTED
, otherwise returning null
.null
if FULFILLED
.sync()