• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.google.inject;
2 
3 import static com.google.inject.Asserts.assertContains;
4 import static com.google.inject.Asserts.getDeclaringSourcePart;
5 
6 import junit.framework.TestCase;
7 
8 import java.lang.annotation.Documented;
9 import java.lang.annotation.ElementType;
10 import java.lang.annotation.Retention;
11 import java.lang.annotation.RetentionPolicy;
12 import java.lang.annotation.Target;
13 
14 /**
15  * @author jessewilson@google.com (Jesse Wilson)
16  */
17 public class NullableInjectionPointTest extends TestCase {
18 
testInjectNullIntoNotNullableConstructor()19   public void testInjectNullIntoNotNullableConstructor() {
20     try {
21       createInjector().getInstance(FooConstructor.class);
22       fail("Injecting null should fail with an error");
23     }
24     catch (ProvisionException expected) {
25       assertContains(expected.getMessage(),
26           "null returned by binding at " + getClass().getName(),
27           "parameter 0 of " + FooConstructor.class.getName() + ".<init>() is not @Nullable");
28     }
29   }
30 
testInjectNullIntoNotNullableMethod()31   public void testInjectNullIntoNotNullableMethod() {
32     try {
33       createInjector().getInstance(FooMethod.class);
34       fail("Injecting null should fail with an error");
35     }
36     catch (ProvisionException expected) {
37       assertContains(expected.getMessage(),
38           "null returned by binding at " + getClass().getName(),
39           "parameter 0 of " + FooMethod.class.getName() + ".setFoo() is not @Nullable");
40     }
41   }
42 
testInjectNullIntoNotNullableField()43   public void testInjectNullIntoNotNullableField() {
44     try {
45       createInjector().getInstance(FooField.class);
46       fail("Injecting null should fail with an error");
47     }
48     catch (ProvisionException expected) {
49       assertContains(expected.getMessage(),
50           "null returned by binding at " + getClass().getName(),
51           " but " + FooField.class.getName() + ".foo is not @Nullable");
52     }
53   }
54 
55   /**
56    * Provider.getInstance() is allowed to return null via direct calls to
57    * getInstance().
58    */
testGetInstanceOfNull()59   public void testGetInstanceOfNull() {
60     assertNull(createInjector().getInstance(Foo.class));
61   }
62 
testInjectNullIntoNullableConstructor()63   public void testInjectNullIntoNullableConstructor() {
64     NullableFooConstructor nfc
65         = createInjector().getInstance(NullableFooConstructor.class);
66     assertNull(nfc.foo);
67   }
68 
testInjectNullIntoNullableMethod()69   public void testInjectNullIntoNullableMethod() {
70     NullableFooMethod nfm
71         = createInjector().getInstance(NullableFooMethod.class);
72     assertNull(nfm.foo);
73   }
74 
testInjectNullIntoNullableField()75   public void testInjectNullIntoNullableField() {
76     NullableFooField nff
77         = createInjector().getInstance(NullableFooField.class);
78     assertNull(nff.foo);
79   }
80 
testInjectNullIntoCustomNullableConstructor()81   public void testInjectNullIntoCustomNullableConstructor() {
82     CustomNullableFooConstructor nfc
83         = createInjector().getInstance(CustomNullableFooConstructor.class);
84     assertNull(nfc.foo);
85   }
86 
testInjectNullIntoCustomNullableMethod()87   public void testInjectNullIntoCustomNullableMethod() {
88     CustomNullableFooMethod nfm
89         = createInjector().getInstance(CustomNullableFooMethod.class);
90     assertNull(nfm.foo);
91   }
92 
testInjectNullIntoCustomNullableField()93   public void testInjectNullIntoCustomNullableField() {
94     CustomNullableFooField nff
95         = createInjector().getInstance(CustomNullableFooField.class);
96     assertNull(nff.foo);
97   }
98 
createInjector()99   private Injector createInjector() {
100     return Guice.createInjector(
101         new AbstractModule() {
102           protected void configure() {
103             bind(Foo.class).toProvider(new Provider<Foo>() {
104               public Foo get() {
105                 return null;
106               }
107             });
108           }
109         });
110   }
111 
112   /**
113    * We haven't decided on what the desired behaviour of this test should be...
114    */
115   public void testBindNullToInstance() {
116     try {
117       Guice.createInjector(new AbstractModule() {
118         protected void configure() {
119           bind(Foo.class).toInstance(null);
120         }
121       });
122       fail();
123     } catch (CreationException expected) {
124       assertContains(expected.getMessage(),
125           "Binding to null instances is not allowed.",
126           "at " + getClass().getName(), getDeclaringSourcePart(getClass()));
127     }
128   }
129 
130   public void testBindNullToProvider() {
131     Injector injector = Guice.createInjector(new AbstractModule() {
132       protected void configure() {
133         bind(Foo.class).toProvider(new Provider<Foo>() {
134           public Foo get() {
135             return null;
136           }
137         });
138       }
139     });
140     assertNull(injector.getInstance(NullableFooField.class).foo);
141     assertNull(injector.getInstance(CustomNullableFooField.class).foo);
142 
143     try {
144       injector.getInstance(FooField.class);
145     }
146     catch(ProvisionException expected) {
147       assertContains(expected.getMessage(), "null returned by binding at");
148     }
149   }
150 
151   public void testBindScopedNull() {
152     Injector injector = Guice.createInjector(new AbstractModule() {
153       protected void configure() {
154         bind(Foo.class).toProvider(new Provider<Foo>() {
155           public Foo get() {
156             return null;
157           }
158         }).in(Scopes.SINGLETON);
159       }
160     });
161     assertNull(injector.getInstance(NullableFooField.class).foo);
162     assertNull(injector.getInstance(CustomNullableFooField.class).foo);
163 
164     try {
165       injector.getInstance(FooField.class);
166     }
167     catch(ProvisionException expected) {
168       assertContains(expected.getMessage(), "null returned by binding at");
169     }
170   }
171 
172   public void testBindNullAsEagerSingleton() {
173     Injector injector = Guice.createInjector(new AbstractModule() {
174       protected void configure() {
175         bind(Foo.class).toProvider(new Provider<Foo>() {
176           public Foo get() {
177             return null;
178           }
179         }).asEagerSingleton();
180       }
181     });
182     assertNull(injector.getInstance(NullableFooField.class).foo);
183     assertNull(injector.getInstance(CustomNullableFooField.class).foo);
184 
185     try {
186       injector.getInstance(FooField.class);
187       fail();
188     } catch(ProvisionException expected) {
189       assertContains(expected.getMessage(), "null returned by binding "
190           + "at com.google.inject.NullableInjectionPointTest");
191     }
192   }
193 
194   static class Foo { }
195 
196   static class FooConstructor {
197     @Inject FooConstructor(Foo foo) { }
198   }
199   static class FooField {
200     @Inject Foo foo;
201   }
202   static class FooMethod {
203     @Inject
204     void setFoo(Foo foo) { }
205   }
206 
207   static class NullableFooConstructor {
208     Foo foo;
209     @Inject NullableFooConstructor(@Nullable Foo foo) {
210       this.foo = foo;
211     }
212   }
213   static class NullableFooField {
214     @Inject @Nullable Foo foo;
215   }
216   static class NullableFooMethod {
217     Foo foo;
218     @Inject void setFoo(@Nullable Foo foo) {
219       this.foo = foo;
220     }
221   }
222 
223   static class CustomNullableFooConstructor {
224     Foo foo;
225     @Inject CustomNullableFooConstructor(@Namespace.Nullable Foo foo) {
226       this.foo = foo;
227     }
228   }
229 
230   static class CustomNullableFooField {
231     @Inject @Namespace.Nullable Foo foo;
232   }
233   static class CustomNullableFooMethod {
234     Foo foo;
235     @Inject void setFoo(@Namespace.Nullable Foo foo) {
236       this.foo = foo;
237     }
238   }
239 
240   @Documented
241   @Retention(RetentionPolicy.RUNTIME)
242   @Target({ElementType.PARAMETER, ElementType.FIELD})
243   @interface Nullable { }
244 
245   static interface Namespace {
246     @Documented
247     @Retention(RetentionPolicy.RUNTIME)
248     @Target({ElementType.PARAMETER, ElementType.FIELD})
249     @interface Nullable { }
250   }
251 }
252