pass1
pass1

Reputation: 107

Guice - Default binding definition

Is there a way to declare default binding in Guice 3.0 ?

Here is an example of what I expected :

//Constructor for Class Impl1
@Inject
public Impl1 (@One IMyOwn own)
{
   ...
}

//Constructor for Class Impl2
@Inject
public Impl2 (@Two IMyOwn own)
{
   ...
}

//Declare a default binding
bind(IMyOwn.class).to(DefaultMyOwn.class);

//Then, if I want to bind a custom implementation for @Two
bind(IMyOwn.class).annotatedWith(Two.class).to(TwoMyOwn.class);

Actually, this example can't works because I must declare a binding for all annotation (@One, @Two).

Are there solutions to do that with Guice ? Thanks.

Upvotes: 2

Views: 7899

Answers (3)

Alexander Oh
Alexander Oh

Reputation: 25661

With Guice 4.X there is Optional Binder.

public class FrameworkModule extends AbstractModule {
  protected void configure() {
    OptionalBinder.newOptionalBinder(binder(), Renamer.class);
  }
}

public class FrameworkModule extends AbstractModule {
  protected void configure() {
    OptionalBinder.newOptionalBinder(
               binder(),
               Key.get(String.class, LookupUrl.class))
                  .setDefault().toInstance(DEFAULT_LOOKUP_URL);
  }
}

In Guice 3.0 you may be able to exploit the automatic binding of the default constructor.

  1. Use a single @Inject or public no-arguments constructor.

But this has constraints, as your default constructor needs to be of the same concrete class so derivation may become cumbersome.

Upvotes: 2

Arpit
Arpit

Reputation: 21

Use the @Named binding.

From Guice Reference on Github:

Guice comes with a built-in binding annotation @Named that uses a string:

public class RealBillingService implements BillingService {
  @Inject
  public RealBillingService(@Named("Checkout") CreditCardProcessor processor) {
    ...
  }

To bind a specific name, use Names.named() to create an instance to pass to annotatedWith:

bind(CreditCardProcessor.class)
    .annotatedWith(Names.named("Checkout"))
    .to(CheckoutCreditCardProcessor.class);

So in your case,

//Constructor for Class Impl1
@Inject
public Impl1 (@Named("One") IMyOwn own)
{
   ...
}

//Constructor for Class Impl2
@Inject
public Impl2 (@Named("Two") IMyOwn own)
{
   ...
}

and your module will look like:

public class MyOwnModule extends AbstractModule {
  @Override 
  protected void configure() {
    bind(IMyOwn.class)
        .annotatedWith(Names.named("One"))
        .to(DefaultMyOwn.class);

    bind(IMyOwn.class)
        .annotatedWith(Names.named("Two"))
        .to(TwoMyOwn.class);
  }
}

Upvotes: 2

A.H.
A.H.

Reputation: 66323

Guice tries to check as much of your configuration (aka. Binding) as possible. This also means, that Guice cannot tell whether a missing binding for @One is an error or should map to some default case.

If you are interested in the details, lookup the BindingResolution sequence in Guice. Since step 4 and step 6 deal with binding annotation and step 6 explicitly forbids default, I think you are out of luck.

.6. If the dependency has a binding annotation, give up. Guice will not create default bindings for annotated dependencies.

So the best you can do is to provide Guice with a hint, that @One should map to the default like this:

bind(IMyOwn.class).annotatedWith(One.class).to(IMyOwn.class);

So you do not need to state the concrete default class DefaultMyOwn multiple times.

Upvotes: 0

Related Questions