-
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.
Binding annotations are Java annotations that are annotated with meta annotation
@Qualifier or @BindingAnnotation.
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.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
@Qualifier
@Target({ FIELD, PARAMETER, METHOD })
@Retention(RUNTIME)
public @interface PayPal {}
// Older code may still use Guice `BindingAnnotation` in place of the standard
// `@Qualifier` annotation. New code should use `@Qualifier` instead.
@BindingAnnotation
@Target({ FIELD, PARAMETER, METHOD })
@Retention(RUNTIME)
public @interface GoogleCheckout {}You don't need to understand all of these meta-annotations, but if you're curious:
-
@Qualifieris 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@BindingAnnotationis also used for this purpose in older code. - The
@Target({FIELD, PARAMETER, METHOD})annotation prevents the@PayPalannotation from accidentally being applied in places where it serves no purpose. -
@Retention(RUNTIME)makes the annotation available at runtime, which is required in Guice.
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:
final class CreditCardProcessorModule extends AbstractModule {
@Override
protected void configure() {
// This uses the optional `annotatedWith` clause in the `bind()` statement
bind(CreditCardProcessor.class)
.annotatedWith(PayPal.class)
.to(PayPalCreditCardProcessor.class);
}
// This uses binding annotation with a @Provides method
@Provides
@GoogleCheckout
CreditCardProcessor provideCheckoutProcessor(
CheckoutCreditCardProcessor processor) {
return processor;
}
}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:
final class CreditCardProcessorModule extends AbstractModule {
@Override
protected void configure() {
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