• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.inject.multibindings;
18 
19 import static com.google.inject.internal.RealOptionalBinder.newRealOptionalBinder;
20 
21 import com.google.common.base.Optional;
22 import com.google.inject.Binder;
23 import com.google.inject.Key;
24 import com.google.inject.TypeLiteral;
25 import com.google.inject.binder.LinkedBindingBuilder;
26 import com.google.inject.internal.RealOptionalBinder;
27 
28 /**
29  * An API to bind optional values, optionally with a default value. OptionalBinder fulfills two
30  * roles:
31  *
32  * <ol>
33  * <li>It allows a framework to define an injection point that may or may not be bound by users.
34  * <li>It allows a framework to supply a default value that can be changed by users.
35  * </ol>
36  *
37  * <p>When an OptionalBinder is added, it will always supply the bindings: {@code Optional<T>} and
38  * {@code Optional<Provider<T>>}. If {@link #setBinding} or {@link #setDefault} are called, it will
39  * also bind {@code T}.
40  *
41  * <p>{@code setDefault} is intended for use by frameworks that need a default value. User code can
42  * call {@code setBinding} to override the default. <b>Warning: Even if setBinding is called, the
43  * default binding will still exist in the object graph. If it is a singleton, it will be
44  * instantiated in {@code Stage.PRODUCTION}.</b>
45  *
46  * <p>If setDefault or setBinding are linked to Providers, the Provider may return {@code null}. If
47  * it does, the Optional bindings will be absent. Binding setBinding to a Provider that returns null
48  * will not cause OptionalBinder to fall back to the setDefault binding.
49  *
50  * <p>If neither setDefault nor setBinding are called, it will try to link to a user-supplied
51  * binding of the same type. If no binding exists, the optionals will be absent. Otherwise, if a
52  * user-supplied binding of that type exists, or if setBinding or setDefault are called, the
53  * optionals will return present if they are bound to a non-null value.
54  *
55  * <p>Values are resolved at injection time. If a value is bound to a provider, that provider's get
56  * method will be called each time the optional is injected (unless the binding is also scoped, or
57  * an optional of provider is injected).
58  *
59  * <p>Annotations are used to create different optionals of the same key/value type. Each distinct
60  * annotation gets its own independent binding.
61  *
62  * <pre><code>
63  * public class FrameworkModule extends AbstractModule {
64  *   protected void configure() {
65  *     OptionalBinder.newOptionalBinder(binder(), Renamer.class);
66  *   }
67  * }</code></pre>
68  *
69  * <p>With this module, an {@link Optional}{@code <Renamer>} can now be injected. With no other
70  * bindings, the optional will be absent. Users can specify bindings in one of two ways:
71  *
72  * <p>Option 1:
73  *
74  * <pre><code>
75  * public class UserRenamerModule extends AbstractModule {
76  *   protected void configure() {
77  *     bind(Renamer.class).to(ReplacingRenamer.class);
78  *   }
79  * }</code></pre>
80  *
81  * <p>or Option 2:
82  *
83  * <pre><code>
84  * public class UserRenamerModule extends AbstractModule {
85  *   protected void configure() {
86  *     OptionalBinder.newOptionalBinder(binder(), Renamer.class)
87  *         .setBinding().to(ReplacingRenamer.class);
88  *   }
89  * }</code></pre>
90  *
91  * With both options, the {@code Optional<Renamer>} will be present and supply the ReplacingRenamer.
92  *
93  * <p>Default values can be supplied using:
94  *
95  * <pre><code>
96  * public class FrameworkModule extends AbstractModule {
97  *   protected void configure() {
98  *     OptionalBinder.newOptionalBinder(binder(), Key.get(String.class, LookupUrl.class))
99  *         .setDefault().toInstance(DEFAULT_LOOKUP_URL);
100  *   }
101  * }</code></pre>
102  *
103  * With the above module, code can inject an {@code @LookupUrl String} and it will supply the
104  * DEFAULT_LOOKUP_URL. A user can change this value by binding
105  *
106  * <pre><code>
107  * public class UserLookupModule extends AbstractModule {
108  *   protected void configure() {
109  *     OptionalBinder.newOptionalBinder(binder(), Key.get(String.class, LookupUrl.class))
110  *         .setBinding().toInstance(CUSTOM_LOOKUP_URL);
111  *   }
112  * }</code></pre>
113  *
114  * ... which will override the default value.
115  *
116  * <p>If one module uses setDefault the only way to override the default is to use setBinding. It is
117  * an error for a user to specify the binding without using OptionalBinder if setDefault or
118  * setBinding are called. For example,
119  *
120  * <pre><code>
121  * public class FrameworkModule extends AbstractModule {
122  *   protected void configure() {
123  *     OptionalBinder.newOptionalBinder(binder(), Key.get(String.class, LookupUrl.class))
124  *         .setDefault().toInstance(DEFAULT_LOOKUP_URL);
125  *   }
126  * }
127  * public class UserLookupModule extends AbstractModule {
128  *   protected void configure() {
129  *     bind(Key.get(String.class, LookupUrl.class)).toInstance(CUSTOM_LOOKUP_URL);
130  *   }
131  * }</code></pre>
132  *
133  * ... would generate an error, because both the framework and the user are trying to bind
134  * {@code @LookupUrl String}.
135  *
136  * @author sameb@google.com (Sam Berlin)
137  * @since 4.0
138  */
139 public class OptionalBinder<T> {
140   // This class is non-final due to users mocking this in tests :(
141 
newOptionalBinder(Binder binder, Class<T> type)142   public static <T> OptionalBinder<T> newOptionalBinder(Binder binder, Class<T> type) {
143     return new OptionalBinder<T>(
144         newRealOptionalBinder(binder.skipSources(OptionalBinder.class), Key.get(type)));
145   }
146 
newOptionalBinder(Binder binder, TypeLiteral<T> type)147   public static <T> OptionalBinder<T> newOptionalBinder(Binder binder, TypeLiteral<T> type) {
148     return new OptionalBinder<T>(
149         newRealOptionalBinder(binder.skipSources(OptionalBinder.class), Key.get(type)));
150   }
151 
newOptionalBinder(Binder binder, Key<T> type)152   public static <T> OptionalBinder<T> newOptionalBinder(Binder binder, Key<T> type) {
153     return new OptionalBinder<T>(
154         newRealOptionalBinder(binder.skipSources(OptionalBinder.class), type));
155   }
156 
157   private final RealOptionalBinder<T> delegate;
158 
OptionalBinder(RealOptionalBinder<T> delegate)159   private OptionalBinder(RealOptionalBinder<T> delegate) {
160     this.delegate = delegate;
161   }
162 
163   /**
164    * Returns a binding builder used to set the default value that will be injected. The binding set
165    * by this method will be ignored if {@link #setBinding} is called.
166    *
167    * <p>It is an error to call this method without also calling one of the {@code to} methods on the
168    * returned binding builder.
169    */
setDefault()170   public LinkedBindingBuilder<T> setDefault() {
171     return delegate.setDefault();
172   }
173 
174   /**
175    * Returns a binding builder used to set the actual value that will be injected. This overrides
176    * any binding set by {@link #setDefault}.
177    *
178    * <p>It is an error to call this method without also calling one of the {@code to} methods on the
179    * returned binding builder.
180    */
setBinding()181   public LinkedBindingBuilder<T> setBinding() {
182     return delegate.setBinding();
183   }
184 
185   // Some tests depend on equals/hashCode behavior of OptionalBinder
186 
187   @Override
equals(Object obj)188   public boolean equals(Object obj) {
189     if (obj instanceof OptionalBinder) {
190       return delegate.equals(((OptionalBinder<?>) obj).delegate);
191     }
192     return false;
193   }
194 
195   @Override
hashCode()196   public int hashCode() {
197     return delegate.hashCode();
198   }
199 }
200