-
Notifications
You must be signed in to change notification settings - Fork 1.7k
BindingAnnotations
Occasionally you'll want multiple bindings for the same type. For example, you might want both a PayPal credit card processor and a Google Checkout processor. To enable this, bindings support an optional binding annotation. The annotation and type together uniquely identify a binding. This pair is called a key.
Defining a binding annotation requires two lines of code plus several imports.
Put this in its own .java
file or inside the type that it annotates.
package example.pizza;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import javax.inject.Qualifier;
@Qualifier @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME)
public @interface PayPal {}
You don't need to understand all of these meta-annotations, but if you're curious:
-
@Qualifier
is a JSR-330 meta-annotation that tells Guice that this is a binding annotation. Guice will produce an error if multiple binding annotations are ever applied to the same member. Guice's@BindingAnnotation
is also used for this purpose in older code. -
@Target({FIELD, PARAMETER, METHOD})
is a courtesy to your users. It prevents@PayPal
from accidentally being applied where it serves no purpose. -
@Retention(RUNTIME)
makes the annotation available at runtime.
To depend on the annotated binding, apply the annotation to the injected parameter:
public class RealBillingService implements BillingService {
@Inject
public RealBillingService(@PayPal CreditCardProcessor processor,
TransactionLog transactionLog) {
...
}
Lastly we create a binding that uses the annotation. This uses the optional
annotatedWith
clause in the bind()
statement:
bind(CreditCardProcessor.class)
.annotatedWith(PayPal.class)
.to(PayPalCreditCardProcessor.class);
Guice comes with a built-in binding annotation @Named
that takes a string:
public class RealBillingService implements BillingService {
@Inject
public RealBillingService(@Named("Checkout") CreditCardProcessor processor,
TransactionLog transactionLog) {
...
}
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);
Since the compiler can't check the string, we recommend using @Named
sparingly. Defining your own purpose-built annotations provides better
type-safety.
Guice supports binding annotations that have attribute values (like @Named
).
In the rare case that you need such an annotation (and can't use an @Provides
method) we encourage you to use
@AutoAnnotation
from the Auto/Value project, as properly implementing an annotation is
error-prone. If you do decide to manually create a custom implementation be sure
to properly implement the equals()
and hashCode()
specifications detailed in
the
Annotation
Javadoc.
Pass an instance of this class to the annotatedWith()
binding clause.
-
User's Guide
-
Integration
-
Extensions
-
Internals
-
Releases
-
Community