Skip to content

"Eventual Provides" aka "Future Injection" is an experimental (from 2015) Guice add-on for injection and asynchronous resolution of future dependencies

License

Notifications You must be signed in to change notification settings

immutables/eventual

Repository files navigation

Build Status

Eventual Providers

Guice add-ons to resolve future-provided dependencies.

<dependency>
  <groupId>org.immutables</groupId>
  <artifactId>eventual</artifactId>
  <version>1.1</version>
</dependency>

Creates special mix-in module created from defining class with special asynchronous transformation methods annotated with @EventuallyProvides, which is asynchronous analog to Guice's @Provides. Used to annotate asynchronous provider methods used to describe transformation of async values.

@Eventually.Provides
C combine(A a, B b) {
  return new C(a.a(), b.b());
}

In this provider method above we created binding for ListenableFuture<C> that will be functionally equivalent to the following regular @Provides method:

@Provides
ListenableFuture<C> combine(ListenableFuture<A> a, ListenableFuture<B> b) {
  return Futures.transform(Futures.allAsList(Arrays.asList(a, b)),
      (List<Object> input) -> {
        A a = (A) input.get(0);
        B b = (B) input.get(1);
        return new C(a.a(), b.b());
      });
}

Here's more involved example

@Singleton // all futures will be singletons
public class Providers { // no need to extend AbstractModule or implement Module

  @Eventually.Provides
  A createA() {
    return ...;
  }

  @Eventually.Provides
  ListenableFuture<B> loadB() {
    // loading of B is itself asyncronous, so we return future
    return ...;
  }

  @Eventually.Provides
  C combine(A a, B b) {
    // when A and B ready, we calculate C
    return new C(a.value(), b.calculate());
  }

  // Only exposed values can be injected between modules,
  // All other are hidden inside private module
  @Exposed
  @Eventually.Provides
  Z transformed(C c) {
    // when C is ready, we calculate Z from it
    return c.transformed();
  }
}

Module futureModule = EventualModules.definedBy(new Providers());

ListenableFuture<Module> completedModule =
    EventualModules.completedFrom(Guice.createInjector(futureModule));

// inject Z when all futures completed
Z z = Guice.createInjector(completedModule.get()).getInstance(Z.class);

Having dependency on ListenableFuture<A> and ListenableFuture<B>, this module exposed combined and transformed ListenableFuture<Z> available to injector.

While super-classes could be used and will be scanned for such methods, method overriding is not handled properly so avoid overriding provider methods. Use delegation to regular methods if some functionality should be implemented or overridden.

In order to customize dispatching, injector could provided with binding to @Eventually.Async Executor. So you need to mix in

On the very abstract level this library achieves transformation: P(A, B... Z) -> I(A, B... Z):

  • Define providers P(A, B... Z)
  • and use it create (definedBy) a module M(F[A], F[B]... F[Z]),
  • then use it to create (createInjector) injector I(F[A], F[B]... F[Z])
  • use injector to get future (completedFrom) module F[M(A, B... Z)]
  • when future is fulfilled, you create injector I(A, B... Z) from the dereferenced module.

Builder was introduced to somewhat simplify composition of eventual provider modules.

// Here's equivalent to the example above
Injector resulting = new EventualModules.Builder()
    .add(new Providers())
    .joinInjector();

// Other builder methods:
//  .skipFailed()
//  .executor(Executor)
//  .toFuture()

The alternative to the solution would be to use plain composition of futures. But even with java 8 lambdas, it's still might be cumbersome to reason about complicated chains of transformation. Definitely, this kind of utility might be also be built specifically for Java 8 without using Guice. This is built with Guava's ListenableFuture and not with CompletableFuture, sorry.

Examples

See FutureJection slides and sample "Barbican" project

About

"Eventual Provides" aka "Future Injection" is an experimental (from 2015) Guice add-on for injection and asynchronous resolution of future dependencies

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages