blob: e96a0f3125d932f4c0425f2c27cbca9926547448 [file] [log] [blame]
limpbizkit06828972008-02-18 20:20:45 +00001/**
2 * Copyright (C) 2007 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
limpbizkit1dabcfd2007-08-25 08:06:30 +000017package com.google.inject;
18
limpbizkiteab76472008-05-26 19:45:12 +000019import static com.google.inject.Asserts.assertContains;
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -070020import static com.google.inject.Asserts.getDeclaringSourcePart;
limpbizkit6caa8dc2009-05-19 00:40:02 +000021import static com.google.inject.Asserts.reserialize;
limpbizkit06898062008-11-02 05:14:55 +000022import static java.lang.annotation.ElementType.CONSTRUCTOR;
limpbizkit9bf65852008-11-29 22:01:13 +000023import static java.lang.annotation.ElementType.FIELD;
limpbizkit06898062008-11-02 05:14:55 +000024import static java.lang.annotation.ElementType.METHOD;
limpbizkit9bf65852008-11-29 22:01:13 +000025import static java.lang.annotation.ElementType.PARAMETER;
limpbizkit06898062008-11-02 05:14:55 +000026import static java.lang.annotation.RetentionPolicy.RUNTIME;
sberlinb7a02b02011-07-08 00:34:16 +000027
limpbizkitdf98fcd2008-06-14 05:02:15 +000028import junit.framework.TestCase;
limpbizkiteab76472008-05-26 19:45:12 +000029
sberlinb7a02b02011-07-08 00:34:16 +000030import java.io.IOException;
31import java.lang.annotation.Retention;
32import java.lang.annotation.Target;
33
limpbizkit1dabcfd2007-08-25 08:06:30 +000034/**
limpbizkite4647a62008-05-25 18:03:35 +000035 * @author jessewilson@google.com (Jesse Wilson)
limpbizkit1dabcfd2007-08-25 08:06:30 +000036 */
limpbizkiteab76472008-05-26 19:45:12 +000037@SuppressWarnings("UnusedDeclaration")
limpbizkit1dabcfd2007-08-25 08:06:30 +000038public class ProvisionExceptionTest extends TestCase {
39
40 public void testExceptionsCollapsed() {
41 try {
42 Guice.createInjector().getInstance(A.class);
43 fail();
limpbizkit56400ca2008-05-23 19:20:08 +000044 } catch (ProvisionException e) {
limpbizkit1dabcfd2007-08-25 08:06:30 +000045 assertTrue(e.getCause() instanceof UnsupportedOperationException);
limpbizkit9dc32d42008-06-15 11:29:10 +000046 assertContains(e.getMessage(), "Error injecting constructor",
limpbizkit9dc32d42008-06-15 11:29:10 +000047 "for parameter 0 at com.google.inject.ProvisionExceptionTest$C.setD",
limpbizkit9dc32d42008-06-15 11:29:10 +000048 "for field at com.google.inject.ProvisionExceptionTest$B.c",
limpbizkita6e0e782008-09-03 06:19:56 +000049 "for parameter 0 at com.google.inject.ProvisionExceptionTest$A");
limpbizkit9dc32d42008-06-15 11:29:10 +000050 }
51 }
52
53 /**
54 * There's a pass-through of user code in the scope. We want exceptions thrown by Guice to be
55 * limited to a single exception, even if it passes through user code.
56 */
57 public void testExceptionsCollapsedWithScopes() {
58 try {
59 Guice.createInjector(new AbstractModule() {
60 protected void configure() {
61 bind(B.class).in(Scopes.SINGLETON);
62 }
63 }).getInstance(A.class);
64 fail();
65 } catch (ProvisionException e) {
66 assertTrue(e.getCause() instanceof UnsupportedOperationException);
67 assertFalse(e.getMessage().contains("custom provider"));
68 assertContains(e.getMessage(), "Error injecting constructor",
limpbizkit9dc32d42008-06-15 11:29:10 +000069 "for parameter 0 at com.google.inject.ProvisionExceptionTest$C.setD",
limpbizkit9dc32d42008-06-15 11:29:10 +000070 "for field at com.google.inject.ProvisionExceptionTest$B.c",
limpbizkita6e0e782008-09-03 06:19:56 +000071 "for parameter 0 at com.google.inject.ProvisionExceptionTest$A");
limpbizkit1dabcfd2007-08-25 08:06:30 +000072 }
73 }
74
75 public void testMethodInjectionExceptions() {
76 try {
77 Guice.createInjector().getInstance(E.class);
78 fail();
limpbizkit56400ca2008-05-23 19:20:08 +000079 } catch (ProvisionException e) {
limpbizkit1dabcfd2007-08-25 08:06:30 +000080 assertTrue(e.getCause() instanceof UnsupportedOperationException);
limpbizkita6e0e782008-09-03 06:19:56 +000081 assertContains(e.getMessage(), "Error injecting method",
82 "at " + E.class.getName() + ".setObject(ProvisionExceptionTest.java:");
limpbizkit1dabcfd2007-08-25 08:06:30 +000083 }
84 }
85
limpbizkite4647a62008-05-25 18:03:35 +000086 public void testBindToProviderInstanceExceptions() {
87 try {
88 Guice.createInjector(new AbstractModule() {
89 protected void configure() {
90 bind(D.class).toProvider(new DProvider());
91 }
92 }).getInstance(D.class);
93 fail();
94 } catch (ProvisionException e) {
95 assertTrue(e.getCause() instanceof UnsupportedOperationException);
limpbizkita6e0e782008-09-03 06:19:56 +000096 assertContains(e.getMessage(),
97 "1) Error in custom provider, java.lang.UnsupportedOperationException",
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -070098 "at " + ProvisionExceptionTest.class.getName(),
99 getDeclaringSourcePart(getClass()));
limpbizkite4647a62008-05-25 18:03:35 +0000100 }
101 }
102
limpbizkit60ddbc32008-05-07 06:37:19 +0000103 /**
limpbizkit9dc32d42008-06-15 11:29:10 +0000104 * This test demonstrates that if the user throws a ProvisionException, we wrap it to add context.
limpbizkit60ddbc32008-05-07 06:37:19 +0000105 */
limpbizkit56400ca2008-05-23 19:20:08 +0000106 public void testProvisionExceptionsAreWrappedForBindToType() {
limpbizkit60ddbc32008-05-07 06:37:19 +0000107 try {
108 Guice.createInjector().getInstance(F.class);
109 fail();
110 } catch (ProvisionException e) {
limpbizkit490833f2008-11-02 00:12:39 +0000111 assertContains(e.getMessage(), "1) User Exception",
limpbizkita6e0e782008-09-03 06:19:56 +0000112 "at " + F.class.getName() + ".<init>(ProvisionExceptionTest.java:");
limpbizkit60ddbc32008-05-07 06:37:19 +0000113 }
limpbizkit56400ca2008-05-23 19:20:08 +0000114 }
limpbizkit60ddbc32008-05-07 06:37:19 +0000115
limpbizkit56400ca2008-05-23 19:20:08 +0000116 public void testProvisionExceptionsAreWrappedForBindToProviderType() {
limpbizkit60ddbc32008-05-07 06:37:19 +0000117 try {
118 Guice.createInjector(new AbstractModule() {
119 protected void configure() {
120 bind(F.class).toProvider(FProvider.class);
121 }
122 }).getInstance(F.class);
123 fail();
124 } catch (ProvisionException e) {
limpbizkit490833f2008-11-02 00:12:39 +0000125 assertContains(e.getMessage(), "1) User Exception",
limpbizkit72d11dd2008-11-02 07:59:13 +0000126 "while locating ", FProvider.class.getName(),
127 "while locating ", F.class.getName());
limpbizkit56400ca2008-05-23 19:20:08 +0000128 }
129 }
130
131 public void testProvisionExceptionsAreWrappedForBindToProviderInstance() {
132 try {
133 Guice.createInjector(new AbstractModule() {
134 protected void configure() {
135 bind(F.class).toProvider(new FProvider());
136 }
137 }).getInstance(F.class);
138 fail();
139 } catch (ProvisionException e) {
limpbizkit490833f2008-11-02 00:12:39 +0000140 assertContains(e.getMessage(), "1) User Exception",
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -0700141 "at " + ProvisionExceptionTest.class.getName(),
142 getDeclaringSourcePart(getClass()));
limpbizkiteab76472008-05-26 19:45:12 +0000143 }
144 }
145
146 public void testProvisionExceptionIsSerializable() throws IOException {
147 try {
148 Guice.createInjector().getInstance(A.class);
149 fail();
150 } catch (ProvisionException expected) {
limpbizkit6caa8dc2009-05-19 00:40:02 +0000151 ProvisionException reserialized = reserialize(expected);
152 assertContains(reserialized.getMessage(),
153 "1) Error injecting constructor, java.lang.UnsupportedOperationException",
154 "at com.google.inject.ProvisionExceptionTest$RealD.<init>()",
155 "at Key[type=com.google.inject.ProvisionExceptionTest$RealD, annotation=[none]]",
156 "@com.google.inject.ProvisionExceptionTest$C.setD()[0]",
157 "at Key[type=com.google.inject.ProvisionExceptionTest$C, annotation=[none]]",
158 "@com.google.inject.ProvisionExceptionTest$B.c",
159 "at Key[type=com.google.inject.ProvisionExceptionTest$B, annotation=[none]]",
160 "@com.google.inject.ProvisionExceptionTest$A.<init>()[0]",
161 "at Key[type=com.google.inject.ProvisionExceptionTest$A, annotation=[none]]");
limpbizkit56400ca2008-05-23 19:20:08 +0000162 }
163 }
164
limpbizkit490833f2008-11-02 00:12:39 +0000165 public void testMultipleCauses() {
166 try {
167 Guice.createInjector().getInstance(G.class);
168 fail();
169 } catch (ProvisionException e) {
170 assertContains(e.getMessage(),
171 "1) Error injecting method, java.lang.IllegalArgumentException",
172 "Caused by: java.lang.IllegalArgumentException: java.lang.UnsupportedOperationException",
173 "Caused by: java.lang.UnsupportedOperationException: Unsupported",
174 "2) Error injecting method, java.lang.NullPointerException: can't inject second either",
175 "Caused by: java.lang.NullPointerException: can't inject second either",
176 "2 errors");
177 }
178 }
179
limpbizkit06898062008-11-02 05:14:55 +0000180 public void testInjectInnerClass() throws Exception {
181 Injector injector = Guice.createInjector();
182 try {
183 injector.getInstance(InnerClass.class);
184 fail();
185 } catch (Exception expected) {
186 assertContains(expected.getMessage(),
187 "Injecting into inner classes is not supported.",
limpbizkit72d11dd2008-11-02 07:59:13 +0000188 "while locating " + InnerClass.class.getName());
limpbizkit06898062008-11-02 05:14:55 +0000189 }
190 }
191
192 public void testInjectLocalClass() throws Exception {
193 class LocalClass {}
194
195 Injector injector = Guice.createInjector();
196 try {
197 injector.getInstance(LocalClass.class);
198 fail();
199 } catch (Exception expected) {
200 assertContains(expected.getMessage(),
201 "Injecting into inner classes is not supported.",
limpbizkit72d11dd2008-11-02 07:59:13 +0000202 "while locating " + LocalClass.class.getName());
limpbizkit06898062008-11-02 05:14:55 +0000203 }
204 }
205
206 public void testBindingAnnotationsOnMethodsAndConstructors() {
207 try {
limpbizkit72d11dd2008-11-02 07:59:13 +0000208 Injector injector = Guice.createInjector();
209 injector.getInstance(MethodWithBindingAnnotation.class);
limpbizkit06898062008-11-02 05:14:55 +0000210 fail();
211 } catch (ConfigurationException expected) {
212 assertContains(expected.getMessage(), MethodWithBindingAnnotation.class.getName()
213 + ".injectMe() is annotated with @", Green.class.getName() + "(), ",
214 "but binding annotations should be applied to its parameters instead.",
limpbizkit72d11dd2008-11-02 07:59:13 +0000215 "while locating " + MethodWithBindingAnnotation.class.getName());
limpbizkit06898062008-11-02 05:14:55 +0000216 }
217
218 try {
219 Guice.createInjector().getInstance(ConstructorWithBindingAnnotation.class);
220 fail();
221 } catch (ConfigurationException expected) {
222 assertContains(expected.getMessage(), ConstructorWithBindingAnnotation.class.getName()
223 + ".<init>() is annotated with @", Green.class.getName() + "(), ",
224 "but binding annotations should be applied to its parameters instead.",
225 "at " + ConstructorWithBindingAnnotation.class.getName() + ".class",
limpbizkit72d11dd2008-11-02 07:59:13 +0000226 "while locating " + ConstructorWithBindingAnnotation.class.getName());
limpbizkit06898062008-11-02 05:14:55 +0000227 }
228 }
229
limpbizkit9bf65852008-11-29 22:01:13 +0000230 public void testBindingAnnotationWarningForScala() {
231 Injector injector = Guice.createInjector(new AbstractModule() {
232 protected void configure() {
233 bind(String.class).annotatedWith(Green.class).toInstance("lime!");
234 }
235 });
236 injector.getInstance(LikeScala.class);
237 }
238
limpbizkit06898062008-11-02 05:14:55 +0000239 public void testLinkedBindings() {
240 Injector injector = Guice.createInjector(new AbstractModule() {
241 protected void configure() {
242 bind(D.class).to(RealD.class);
243 }
244 });
245
246 try {
247 injector.getInstance(D.class);
248 fail();
249 } catch (ProvisionException expected) {
250 assertContains(expected.getMessage(),
251 "at " + RealD.class.getName() + ".<init>(ProvisionExceptionTest.java:",
limpbizkit72d11dd2008-11-02 07:59:13 +0000252 "while locating " + RealD.class.getName(),
253 "while locating " + D.class.getName());
limpbizkit06898062008-11-02 05:14:55 +0000254 }
255 }
256
257 public void testProviderKeyBindings() {
258 Injector injector = Guice.createInjector(new AbstractModule() {
259 protected void configure() {
260 bind(D.class).toProvider(DProvider.class);
261 }
262 });
263
264 try {
265 injector.getInstance(D.class);
266 fail();
267 } catch (ProvisionException expected) {
268 assertContains(expected.getMessage(),
limpbizkit72d11dd2008-11-02 07:59:13 +0000269 "while locating " + DProvider.class.getName(),
270 "while locating " + D.class.getName());
limpbizkit06898062008-11-02 05:14:55 +0000271 }
272 }
273
274 private class InnerClass {}
275
limpbizkit1dabcfd2007-08-25 08:06:30 +0000276 static class A {
277 @Inject
278 A(B b) { }
279 }
280 static class B {
281 @Inject C c;
282 }
283 static class C {
284 @Inject
limpbizkit06898062008-11-02 05:14:55 +0000285 void setD(RealD d) { }
limpbizkit1dabcfd2007-08-25 08:06:30 +0000286 }
287 static class E {
288 @Inject void setObject(Object o) {
289 throw new UnsupportedOperationException();
290 }
291 }
limpbizkit06898062008-11-02 05:14:55 +0000292
293 static class MethodWithBindingAnnotation {
294 @Inject @Green void injectMe(String greenString) {}
295 }
296
297 static class ConstructorWithBindingAnnotation {
298 @Inject @Green ConstructorWithBindingAnnotation(String greenString) {}
299 }
300
limpbizkit9bf65852008-11-29 22:01:13 +0000301 /**
302 * In Scala, fields automatically get accessor methods with the same name. So we don't do
303 * misplaced-binding annotation detection if the offending method has a matching field.
304 */
305 static class LikeScala {
306 @Inject @Green String green;
307 @Inject @Green String green() { return green; }
308 }
309
limpbizkit06898062008-11-02 05:14:55 +0000310 @Retention(RUNTIME)
311 @Target({ FIELD, PARAMETER, CONSTRUCTOR, METHOD })
312 @BindingAnnotation
313 @interface Green {}
314
315 interface D {}
316
317 static class RealD implements D {
318 @Inject RealD() {
319 throw new UnsupportedOperationException();
320 }
321 }
322
limpbizkit1dabcfd2007-08-25 08:06:30 +0000323 static class DProvider implements Provider<D> {
324 public D get() {
limpbizkit06898062008-11-02 05:14:55 +0000325 throw new UnsupportedOperationException();
limpbizkit1dabcfd2007-08-25 08:06:30 +0000326 }
327 }
328
limpbizkit60ddbc32008-05-07 06:37:19 +0000329 static class F {
330 @Inject public F() {
limpbizkitdf98fcd2008-06-14 05:02:15 +0000331 throw new ProvisionException("User Exception", new RuntimeException());
limpbizkit60ddbc32008-05-07 06:37:19 +0000332 }
333 }
334
335 static class FProvider implements Provider<F> {
336 public F get() {
337 return new F();
338 }
339 }
limpbizkit490833f2008-11-02 00:12:39 +0000340
341 static class G {
342 @Inject void injectFirst() {
343 throw new IllegalArgumentException(new UnsupportedOperationException("Unsupported"));
344 }
345 @Inject void injectSecond() {
346 throw new NullPointerException("can't inject second either");
347 }
348 }
limpbizkit1dabcfd2007-08-25 08:06:30 +0000349}