diff --git a/src/main/java/org/lucidfox/jpromises/gwt/JsPromise.java b/src/main/java/org/lucidfox/jpromises/gwt/JsPromise.java index feeb4ed..082e32b 100644 --- a/src/main/java/org/lucidfox/jpromises/gwt/JsPromise.java +++ b/src/main/java/org/lucidfox/jpromises/gwt/JsPromise.java @@ -24,6 +24,11 @@ import org.lucidfox.jpromises.core.RejectCallback; import org.lucidfox.jpromises.core.ResolveCallback; import org.lucidfox.jpromises.core.Thenable; +import org.lucidfox.jpromises.core.ThrowingRunnable; +import org.lucidfox.jpromises.core.ValueRejectCallback; +import org.lucidfox.jpromises.core.ValueResolveCallback; +import org.lucidfox.jpromises.core.VoidRejectCallback; +import org.lucidfox.jpromises.core.VoidResolveCallback; import com.google.gwt.core.client.JavaScriptException; import com.google.gwt.core.client.JavaScriptObject; @@ -249,4 +254,230 @@ private static Thenable coerceToNativePromise(final Thenable private static Exception toException(final Object jsError) { return new JavaScriptException(jsError); } + + /** + * Same as {@link #then(ResolveCallback, RejectCallback)}. This method is provided for users used to the + * {@code CompletableFuture} API. + * + * @param the value type of the result promise + * @param onResolve the resolve callback (optional) + * @param onReject the reject callback (optional) + * @return a {@link JsPromise} that is chained after the current promise + */ + public JsPromise thenCompose(final ResolveCallback onResolve, + final RejectCallback onReject) { + return then(onResolve, onReject); + } + + /** + * Same as {@link #then(ResolveCallback)}. This method is provided for users used to the + * {@code CompletableFuture} API. + * + * @param the value type of the result promise + * @see #then(ResolveCallback,RejectCallback) + * @param onResolve the resolve callback (optional) + * @return a {@link JsPromise} that is chained after the current promise + */ + public JsPromise thenCompose(final ResolveCallback onResolve) { + return then(onResolve, null); + } + + /** + * Returns a new {@code Promise} that, after this promise is rejected, is resolved with the promise returned by + * {@code onReject}, or after this promise is resolved, is resolved with the value of this promise. + * + * @see #then(ResolveCallback,RejectCallback) + * @param onReject the reject callback (optional) + * @return a {@link JsPromise} that is chained after the current promise + */ + public JsPromise onException(final RejectCallback onReject) { + return then(new ResolveCallback() { + @Override + public Thenable onResolve(final V value) throws Exception { + return JsPromise.this; + } + }, onReject); + } + + /** + * Returns a new {@code Promise} that, after this promise is resolved or rejected, is immediately resolved to the + * value returned by {@code onResolve} if this promise was resolved or by {@code onReject} if this promise was + * rejected. + *

+ * This method works like the regular {@code then} method, except the callbacks passed to it return a flat value + * instead of a promise. + *

+ *

+ * This implementation throws no exceptions. Any exception thrown during execution of {@code onResolve} or + * {@code onReject} causes the resulting promise to be rejected with that exception. + *

+ * + * @see #then(ResolveCallback,RejectCallback) + * @param the value type of the result promise + * @param onResolve the resolve callback (optional) + * @param onReject the reject callback (optional) + * @return a {@link JsPromise} that is chained after the current promise + */ + public JsPromise thenApply(final ValueResolveCallback onResolve, + final ValueRejectCallback onReject) { + return then(onResolve == null ? null : new ResolveCallback() { + @Override + public Thenable onResolve(final V value) throws Exception { + final R result = onResolve.onResolve(value); + return resolve(result); + } + }, onReject == null ? null : new RejectCallback() { + @Override + public Thenable onReject(final Throwable exception) throws Throwable { + final R result = onReject.onReject(exception); + return resolve(result); + } + }); + } + + /** + * Calls {@code thenApply(onResolve, null)}. + * + * @see #thenApply(ValueResolveCallback, ValueRejectCallback) + * @param the value type of the result promise + * @param onResolve the resolve callback (optional) + * @return a {@link JsPromise} that is chained after the current promise + */ + public JsPromise thenApply(final ValueResolveCallback onResolve) { + return thenApply(onResolve, null); + } + + /** + * Returns a promise that, after this promise is rejected, is resolved with the value returned by {@code onReject}, + * or after this promise is resolved, is resolved with the value of this promise. + * + * @see #thenApply(ValueResolveCallback, ValueRejectCallback) + * @param onReject the reject callback (optional) + * @return a {@link JsPromise} that is chained after the current promise + */ + public JsPromise onExceptionApply(final ValueRejectCallback onReject) { + return thenApply(new ValueResolveCallback() { + @Override + public V onResolve(final V value) throws Exception { + return value; + } + }, onReject); + } + + /** + * Returns a new {@code Promise} that, after this promise is resolved or rejected, calls {@code onResolve} and + * becomes resolved to {@code null} if this promise was resolved, or calls {@code onReject} and becomes resolved + * to {@code null} if this promise was rejected. + *

+ * This implementation throws no exceptions. Any exception thrown during execution of {@code onResolve} or + * {@code onReject} causes the resulting promise to be rejected with that exception. + *

+ * + * @see #then(ResolveCallback,RejectCallback) + * @param onResolve the resolve callback (optional) + * @param onReject the reject callback (optional) + * @return a {@link JsPromise} that is chained after the current promise + */ + public JsPromise thenAccept(final VoidResolveCallback onResolve, + final VoidRejectCallback onReject) { + return then(onResolve == null ? null : new ResolveCallback() { + @Override + public Thenable onResolve(final V value) throws Exception { + onResolve.onResolve(value); + return null; + } + }, onReject == null ? null : new RejectCallback() { + @Override + public Thenable onReject(final Throwable exception) throws Throwable { + onReject.onReject(exception); + return null; + } + }); + } + + /** + * Calls {@code thenAccept(onResolve, null)}. + * + * @see #thenAccept(VoidResolveCallback,VoidRejectCallback) + * @param onResolve the resolve callback (optional) + * @return a {@link JsPromise} that is chained after the current promise + */ + public JsPromise thenAccept(final VoidResolveCallback onResolve) { + return thenAccept(onResolve, null); + } + + /** + * Returns a new {@code Promise} that, after this promise is resolved or rejected, calls {@code onResolve} and + * becomes resolved to {@code null} if this promise was resolved, or calls {@code onReject} and becomes resolved + * to {@code null} if this promise was rejected. + *

+ * This implementation throws no exceptions. Any exception thrown during execution of {@code onResolve} or + * {@code onReject} causes the resulting promise to be rejected with that exception. + *

+ * + * @see #then(ResolveCallback,RejectCallback) + * @param onResolve the resolve callback, ignoring the result of the promise (optional) + * @param onReject the reject callback (optional) + * @return a {@link JsPromise} that is chained after the current promise + */ + public JsPromise thenRun(final ThrowingRunnable onResolve, final VoidRejectCallback onReject) { + return then(onResolve == null ? null : new ResolveCallback() { + @Override + public Thenable onResolve(final V value) throws Exception { + onResolve.run(); + return null; + } + }, onReject == null ? null : new RejectCallback() { + @Override + public Thenable onReject(final Throwable exception) throws Throwable { + onReject.onReject(exception); + return null; + } + }); + } + + /** + * Calls {@code thenRun(onResolve, null)}. + * + * @see #thenRun(ThrowingRunnable,VoidRejectCallback) + * @param onResolve the resolve callback (optional) + * @return a {@link JsPromise} that is chained after the current promise + */ + public JsPromise thenRun(final ThrowingRunnable onResolve) { + return thenRun(onResolve, null); + } + + /** + * Returns a promise that, after this promise is rejected, calls {@code onReject} and becomes resolved with + * {@code null}, or after this promise is resolved, is resolved with {@code null}. + * + * @see #thenAccept(VoidResolveCallback,VoidRejectCallback) + * @param onReject the reject callback (optional) + * @return a {@link JsPromise} that is chained after the current promise + */ + public JsPromise onExceptionAccept(final VoidRejectCallback onReject) { + return thenAccept(null, onReject); + } + + /** + * Same as {@link #thenAccept(VoidResolveCallback,VoidRejectCallback)}, but does not return a value, preventing + * any further additions to the then-chain after this promise. + * + * @see #thenAccept(VoidResolveCallback,VoidRejectCallback) + * @param onResolve the resolve callback (optional) + * @param onReject the reject callback (optional) + */ + public void done(final VoidResolveCallback onResolve, final VoidRejectCallback onReject) { + thenAccept(onResolve, onReject); + } + + /** + * Calls {@code done(onResolve, null)}. + * + * @see #done(VoidResolveCallback,VoidRejectCallback) + * @param onResolve the resolve callback (optional) + */ + public void done(final VoidResolveCallback onResolve) { + done(onResolve, null); + } }