Skip to content

JustInTimeBindings

Googler edited this page Oct 13, 2023 · 12 revisions

Just-in-time Bindings

Bindings that are created automatically by Guice

When the injector needs an instance of a type, it needs a binding. The bindings in modules are called explicit bindings, and the injector uses them whenever they're available. If a type is needed but there isn't an explicit binding, the injector will attempt to create a Just-In-Time binding. These are also known as JIT bindings or implicit bindings.

@Inject Constructors

Guice can create bindings for concrete types by using the type's injectable constructor. Guice considers a constructor injectable if:

  • (recommended) The constructor is explicitly annotated with @Inject (both com.google.inject.Inject and javax.inject.Inject are supported).
  • or, the constructor takes zero arguments, and
    • the constructor is non-private and defined in a non-private class (Guice supports private constructor only when it is defined in a private class, however, private constructors are not recommended because they can be slow in Guice due to the cost of reflection).
    • the injector has not opted in to require explicit @Inject constructor, see explicit @Inject constructors section below.

Injectable constructor examples:

public final class Foo {
  // An @Inject annotated constructor.
  @Inject
  Foo(Bar bar) {
    ...
  }
}

public final class Bar {
  // A no-arg non private constructor.
  Bar() {}

  private static class Baz {
    // A private constructor to a private class is also usable by Guice, but
    // this is not recommended since it can be slow.
    private Baz() {}
  }
}

A constructor is not injectable if:

  • The constructor takes one or more arguments and is not annotated with @Inject.
  • There are more than one @Inject annotated constructors.
  • The constructor is defined in a non-static nested class. Inner classes have an implicit reference to their enclosing class that cannot be injected.

Non-injectable constructor examples:

public final class Foo {
  // Not injectable because the construct takes an argument and there is no
  // @Inject annotation.
  Foo(Bar bar) {
    ...
  }
}

public final class Bar {
  // Not injectable because the constructor is private
  private Bar() {}

  class Baz {
    // Not injectable because Baz is not a static inner class
    Baz() {}
  }
}

Explicit @Inject constructors feature

An application can opt-in to enforce that Guice only use @Inject annotated constructors by calling binder().requireAtInjectOnConstructors() in a module that is installed in the injector. When opted-in, Guice will only consider @Inject annotated constructors and if there is none then a MISSING_CONSTRUCTOR is reported.

TIP: Install Modules.requireAtInjectOnConstructorsModule() to opt-in for @Inject on constructor requirement.

@ImplementedBy

Annotate types tell the injector what their default implementation type is. The @ImplementedBy annotation acts like a linked binding, specifying the subtype to use when building a type.

@ImplementedBy(PayPalCreditCardProcessor.class)
public interface CreditCardProcessor {
  ChargeResult charge(String amount, CreditCard creditCard)
      throws UnreachableException;
}

The above annotation is equivalent to the following bind() statement:

    bind(CreditCardProcessor.class).to(PayPalCreditCardProcessor.class);

If a type is in both a bind() statement (as the first argument) and has the @ImplementedBy annotation, the bind() statement is used. The annotation suggests a default implementation that can be overridden with a binding. Use @ImplementedBy carefully; it adds a compile-time dependency from the interface to its implementation.

@ProvidedBy

@ProvidedBy tells the injector about a Provider class that produces instances:

@ProvidedBy(DatabaseTransactionLogProvider.class)
public interface TransactionLog {
  void logConnectException(UnreachableException e);
  void logChargeResult(ChargeResult result);
}

The annotation is equivalent to a toProvider() binding:

    bind(TransactionLog.class)
        .toProvider(DatabaseTransactionLogProvider.class);

Like @ImplementedBy, if the type is annotated and used in a bind() statement, the bind() statement will be used.

Enforce Explicit Bindings

New in Guice 3.0

To disable implicit bindings, you can use the requireExplicitBindings API:

final class ExplicitBindingModule extends AbstractModule {
  @Override
  protected void configure() {
    binder().requireExplicitBindings();
  }
}

Installing the above module will cause Guice to enforce that all bindings must be listed in a Module in order to be injected.

Clone this wiki locally