Class WrapErrFirst

java.lang.Object
org.ores.async.WrapErrFirst

public final class WrapErrFirst extends Object
Helpers that adapt error-first callbacks into more concise call sites.

The library uses Node.js-style error-first callbacks throughout — every continuation receives (err, value) and the caller checks err first. That convention is stable, well-understood, and composes cleanly, but it does mean every callback site has the same five-line error-checking preamble:

   Asyncc.Parallel(tasks, (err, results) -> {
       if (err != null) { handleError(err); return; }
       // ...real work...
   });
 

WrapErrFirst.wrap(...) lets you write just the value handler and either throw on any unhandled error or pass a separate error consumer:

   import static org.ores.async.WrapErrFirst.wrap;

   // (a) throw-on-error: short and loud. Wraps the error in a RuntimeException; useful when
   //     the surrounding context (Vert.x verticle, Akka actor, etc.) already has an
   //     uncaught-exception handler.
   Asyncc.Parallel(tasks, wrap(results -> {
       var scored = score(req, results.get(0), results.get(1));
       reply.send(serialize(scored));
   }));

   // (b) explicit error handler: cleaner than the if/else when the two paths are short.
   Asyncc.Parallel(tasks, wrap(
       results -> reply.send(serialize(score(req, results.get(0), results.get(1)))),
       err     -> reply.error(err)
   ));
 

Why not "error-back" / promise-style chaining instead?

async.java cannot easily be retrofitted to support promise-style "error-back" callbacks (separate onSuccess / onError channels) because the library's at-most-once contract, short-circuit semantics, and 17 combinators are all designed around a single error-first signature. Re-typing every combinator to take two callbacks would double the public surface, double the test matrix, and break every existing caller. WrapErrFirst keeps the canonical error-first signature internally but lets call sites read like promise chains where that ergonomics matters.

The convention used in this library's docs: the continuation parameter is named c (for continuation). wrap(...) produces a continuation just like any other.

Since:
0.2.4
  • Method Details

    • wrap

      public static <V, E> Asyncc.IAsyncCallback<V,E> wrap(Consumer<V> onSuccess)
      Wrap a value-only consumer into an error-first Asyncc.IAsyncCallback. If the continuation is fired with a non-null error, this wrapper throws a RuntimeException carrying the cause (the error itself, if it is a Throwable; otherwise its toString()). If fired with a null error, calls onSuccess.accept(value).

      Use this when the caller does not need to handle the error inline and is happy for it to propagate via the surrounding runtime's uncaught-exception handler. If you want the error to be visible in your own logging or to be turned into an explicit response, use the two-argument form instead.

      Type Parameters:
      V - value type
      E - error type
      Parameters:
      onSuccess - consumer invoked with the successful value; never invoked when an error is present
      Returns:
      an IAsyncCallback suitable for any async.java combinator
    • wrap

      public static <V, E> Asyncc.IAsyncCallback<V,E> wrap(Consumer<V> onSuccess, Consumer<E> onError)
      Wrap two value-only consumers into an error-first Asyncc.IAsyncCallback. Exactly one of onError or onSuccess is invoked per continuation fire.

      This is the recommended form for production code: it never throws on its own (any throw comes from the caller's consumer body) and keeps the two branches visually parallel.

      Type Parameters:
      V - value type
      E - error type
      Parameters:
      onSuccess - consumer invoked when the continuation fires with err == null
      onError - consumer invoked when the continuation fires with a non-null error
      Returns:
      an IAsyncCallback suitable for any async.java combinator