Author: limpbizkit
Date: Sun Mar 1 12:24:30 2009
New Revision: 879
Added:
wiki/CreatingBindings.wiki
Log:
Created wiki page through web user interface.
Added: wiki/CreatingBindings.wiki
==============================================================================
--- (empty file)
+++ wiki/CreatingBindings.wiki Sun Mar 1 12:24:30 2009
@@ -0,0 +1,177 @@
+#summary How to create bindings and binding annotations
+=Creating Bindings=
+The injector's job is to assemble graphs of objects. You request an
instance of a given type, and it figures out what to build, resolves
dependencies, and wires everything together. To specify how dependencies
are resolved, configure your injector with bindings.
+
+To create bindings, extend `AbstractModule` and override its `configure`
method. In the method body, call `bind()` to specify each binding. These
methods are type checked so the compiler can report errors if you use the
wrong types. Once you've created your modules, pass them as arguments to
`Guice.createInjector()` to build an injector.
+
+
+==Linked Bindings==
+Linked bindings map a type to its implementation. This example maps the
interface `TransactionLog` to the implementation `DatabaseTransationLog`:
+{{{
+public class BillingModule extends AbstractModule {
+ @Override
+ protected void configure() {
+ bind(TransactionLog.class).to(DatabaseTransactionLog.class);
+ }
+}
+}}}
+Now, when you call `injector.getInstance(TransactionLog.class)`, or when
the injector encounters a dependency on `TransactionLog`, it will use a
`DatabaseTransactionLog`. Link from a type to any of its subtypes, such as
an implementing class or an extending class. You can even link the concrete
`DatabaseTransactionLog` class to a subclass:
+{{{
+
bind(DatabaseTransactionLog.class).to(MySqlDatabaseTransactionLog.class);
+}}}
+Linked bindings can also be chained:
+{{{
+public class BillingModule extends AbstractModule {
+ @Override
+ protected void configure() {
+ bind(TransactionLog.class).to(DatabaseTransactionLog.class);
+
bind(DatabaseTransactionLog.class).to(MySqlDatabaseTransactionLog.class);
+ }
+}
+}}}
+In this case, when a `TransactionLog` is requested, the injector will
return a `MySqlDatabaseTransactionLog`.
+
+
+==Binding Annotations==
+Occasionally you'll want multiple bindings for a 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 com.google.inject.BindingAnnotation;
+import java.lang.annotation.Target;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+
+...@bindingannotation @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:
+ * `...@bindingannotation` tells Guice that this is a binding annotation.
Guice will produce an error if ever multiple binding annotations apply to
the same member.
+ * `...@target({FIELD, PARAMETER, METHOD})` is a courtesy to your users. It
prevents `...@paypal` from being 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);
+}}}
+
+
+...@named===
+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,
+ 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(PayPalCreditCardProcessor.class);
+}}}
+Since the compiler can't check the string, we recommend using `...@named`
sparingly.
+
+
+===Binding Annotations with Attributes===
+Guice supports binding annotations that have attribute values. In the rare
case that you need such an annotation:
+ # Create the annotation `...@interface`.
+ # Create a class that implements the annotation interface. Follow the
guidelines for `equals()` and `hashCode()` specified in the
[http://java.sun.com/javase/6/docs/api/java/lang/annotation/Annotation.html
Annotation Javadoc]. Pass an instance of this to the `annotatedWith()`
binding clause.
+
+
+==Instance Bindings==
+You can bind a type to a specific instance of that type. This is usually
only useful only for objects that don't have dependencies of their own,
such as value objects:
+{{{
+ bind(String.class)
+ .annotatedWith(Names.named("JDBC URL"))
+ .toInstance("jdbc:mysql://localhost/pizza");
+ bind(Integer.class)
+ .annotatedWith(Names.named("login timeout seconds"))
+ .toInstance(10);
+}}}
+Avoid using `.toInstance` with objects that are complicated to create,
since it can slow down application startup. You can use an `...@provides`
method instead.
+
+
+...@provides Methods==
+When you need code to create an object, use an `...@provides` method. The
method must be defined within a module, and it must have an `...@provides`
annotation. The method's return type is the bound type. Whenever the
injector needs an instance of that type, it will invoke the method.
+{{{
+public class BillingModule extends AbstractModule {
+ @Override
+ protected void configure() {
+ ...
+ }
+
+ @Provides
+ TransactionLog provideTransactionLog() {
+ DatabaseTransactionLog transactionLog = new DatabaseTransactionLog();
+ transactionLog.setJdbcUrl("jdbc:mysql://localhost/pizza");
+ transactionLog.setThreadPoolSize(30);
+ return transactionLog;
+ }
+}
+}}}
+If the `...@provides` method has a binding annotation like `...@paypal` or
`...@named("Checkout")`, Guice binds the annotated type. Dependencies can be
passed in as parameters to the method. The injector will exercise the
bindings for each of these before invoking the method.
+{{{
+ @Provides @PayPal
+ CreditCardProcessor providePayPalCreditCardProcessor(
+ @Named("PayPal API key") String apiKey) {
+ PayPalCreditCardProcessor processor = new PayPalCreditCardProcessor();
+ processor.setApiKey(apiKey);
+ return processor;
+ }
+}}}
+
+==Provider Bindings==
+When your `...@provides` methods start to grow complex, you may consider
moving them to a class of their own. The provider class implements Guice's
`Provider` interface, which is a simple, general interface for supplying
values:
+{{{
+public interface Provider<T> {
+ T get();
+}
+}}}
+Our provider implementation class has dependencies of its own, which it
receives via its `...@inject`-annotated constructor. It implements the
`Provider` interface to define what's returned with complete type safety:
+{{{
+public class DatabaseTransactionLogProvider implements
Provider<TransactionLog> {
+ private final Connection connection;
+
+ @Inject
+ public DatabaseTransactionLogProvider(Connection connection) {
+ this.connection = connection;
+ }
+
+ public TransactionLog get() {
+ DatabaseTransactionLog transactionLog = new DatabaseTransactionLog();
+ transactionLog.setConnection(connection);
+ return transactionLog;
+ }
+}
+}}}
+Finally we bind to the provider using the `.toProvider` clause:
+{{{
+public class BillingModule extends AbstractModule {
+ @Override
+ protected void configure() {
+ bind(TransactionLog.class)
+ .toProvider(DatabaseTransactionLogProvider.class);
+ }
+}}}
+If your providers are complex, be sure to test them!
\ No newline at end of file
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"google-guice-dev" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/google-guice-dev?hl=en
-~----------~----~----~----~------~----~------~--~---