Reputation: 107
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
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.
- 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
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
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