PageRenderTime 18ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/core/test/com/google/inject/ProvisionExceptionTest.java

https://gitlab.com/metamorphiccode/guice
Java | 470 lines | 375 code | 64 blank | 31 comment | 2 complexity | dd2e1b6c06266ed33de6027781662a97 MD5 | raw file
  1. /**
  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. package com.google.inject;
  17. import static com.google.inject.Asserts.assertContains;
  18. import static com.google.inject.Asserts.getDeclaringSourcePart;
  19. import static com.google.inject.Asserts.reserialize;
  20. import static java.lang.annotation.ElementType.CONSTRUCTOR;
  21. import static java.lang.annotation.ElementType.FIELD;
  22. import static java.lang.annotation.ElementType.METHOD;
  23. import static java.lang.annotation.ElementType.PARAMETER;
  24. import static java.lang.annotation.RetentionPolicy.RUNTIME;
  25. import com.google.common.base.Throwables;
  26. import com.google.inject.spi.Message;
  27. import junit.framework.TestCase;
  28. import java.io.IOException;
  29. import java.lang.annotation.Retention;
  30. import java.lang.annotation.Target;
  31. /**
  32. * @author jessewilson@google.com (Jesse Wilson)
  33. */
  34. @SuppressWarnings("UnusedDeclaration")
  35. public class ProvisionExceptionTest extends TestCase {
  36. public void testExceptionsCollapsed() {
  37. try {
  38. Guice.createInjector().getInstance(A.class);
  39. fail();
  40. } catch (ProvisionException e) {
  41. assertTrue(e.getCause() instanceof UnsupportedOperationException);
  42. assertContains(e.getMessage(), "Error injecting constructor",
  43. "for parameter 0 at com.google.inject.ProvisionExceptionTest$C.setD",
  44. "for field at com.google.inject.ProvisionExceptionTest$B.c",
  45. "for parameter 0 at com.google.inject.ProvisionExceptionTest$A");
  46. }
  47. }
  48. /**
  49. * There's a pass-through of user code in the scope. We want exceptions thrown by Guice to be
  50. * limited to a single exception, even if it passes through user code.
  51. */
  52. public void testExceptionsCollapsedWithScopes() {
  53. try {
  54. Guice.createInjector(new AbstractModule() {
  55. @Override protected void configure() {
  56. bind(B.class).in(Scopes.SINGLETON);
  57. }
  58. }).getInstance(A.class);
  59. fail();
  60. } catch (ProvisionException e) {
  61. assertTrue(e.getCause() instanceof UnsupportedOperationException);
  62. assertFalse(e.getMessage().contains("custom provider"));
  63. assertContains(e.getMessage(), "Error injecting constructor",
  64. "for parameter 0 at com.google.inject.ProvisionExceptionTest$C.setD",
  65. "for field at com.google.inject.ProvisionExceptionTest$B.c",
  66. "for parameter 0 at com.google.inject.ProvisionExceptionTest$A");
  67. }
  68. }
  69. public void testMethodInjectionExceptions() {
  70. try {
  71. Guice.createInjector().getInstance(E.class);
  72. fail();
  73. } catch (ProvisionException e) {
  74. assertTrue(e.getCause() instanceof UnsupportedOperationException);
  75. assertContains(e.getMessage(), "Error injecting method",
  76. "at " + E.class.getName() + ".setObject(ProvisionExceptionTest.java:");
  77. }
  78. }
  79. public void testBindToProviderInstanceExceptions() {
  80. try {
  81. Guice.createInjector(new AbstractModule() {
  82. @Override protected void configure() {
  83. bind(D.class).toProvider(new DProvider());
  84. }
  85. }).getInstance(D.class);
  86. fail();
  87. } catch (ProvisionException e) {
  88. assertTrue(e.getCause() instanceof UnsupportedOperationException);
  89. assertContains(e.getMessage(),
  90. "1) Error in custom provider, java.lang.UnsupportedOperationException",
  91. "at " + ProvisionExceptionTest.class.getName(),
  92. getDeclaringSourcePart(getClass()));
  93. }
  94. }
  95. /**
  96. * This test demonstrates that if the user throws a ProvisionException, we wrap it to add context.
  97. */
  98. public void testProvisionExceptionsAreWrappedForBindToType() {
  99. try {
  100. Guice.createInjector().getInstance(F.class);
  101. fail();
  102. } catch (ProvisionException e) {
  103. assertContains(e.getMessage(), "1) User Exception",
  104. "at " + F.class.getName() + ".<init>(ProvisionExceptionTest.java:");
  105. }
  106. }
  107. public void testProvisionExceptionsAreWrappedForBindToProviderType() {
  108. try {
  109. Guice.createInjector(new AbstractModule() {
  110. @Override protected void configure() {
  111. bind(F.class).toProvider(FProvider.class);
  112. }
  113. }).getInstance(F.class);
  114. fail();
  115. } catch (ProvisionException e) {
  116. assertContains(e.getMessage(), "1) User Exception",
  117. "while locating ", FProvider.class.getName(),
  118. "while locating ", F.class.getName());
  119. }
  120. }
  121. public void testProvisionExceptionsAreWrappedForBindToProviderInstance() {
  122. try {
  123. Guice.createInjector(new AbstractModule() {
  124. @Override protected void configure() {
  125. bind(F.class).toProvider(new FProvider());
  126. }
  127. }).getInstance(F.class);
  128. fail();
  129. } catch (ProvisionException e) {
  130. assertContains(e.getMessage(), "1) User Exception",
  131. "at " + ProvisionExceptionTest.class.getName(),
  132. getDeclaringSourcePart(getClass()));
  133. }
  134. }
  135. public void testProvisionExceptionIsSerializable() throws IOException {
  136. try {
  137. Guice.createInjector().getInstance(A.class);
  138. fail();
  139. } catch (ProvisionException expected) {
  140. ProvisionException reserialized = reserialize(expected);
  141. assertContains(reserialized.getMessage(),
  142. "1) Error injecting constructor, java.lang.UnsupportedOperationException",
  143. "at com.google.inject.ProvisionExceptionTest$RealD.<init>()",
  144. "at Key[type=com.google.inject.ProvisionExceptionTest$RealD, annotation=[none]]",
  145. "@com.google.inject.ProvisionExceptionTest$C.setD()[0]",
  146. "at Key[type=com.google.inject.ProvisionExceptionTest$C, annotation=[none]]",
  147. "@com.google.inject.ProvisionExceptionTest$B.c",
  148. "at Key[type=com.google.inject.ProvisionExceptionTest$B, annotation=[none]]",
  149. "@com.google.inject.ProvisionExceptionTest$A.<init>()[0]",
  150. "at Key[type=com.google.inject.ProvisionExceptionTest$A, annotation=[none]]");
  151. }
  152. }
  153. public void testMultipleCauses() {
  154. try {
  155. Guice.createInjector().getInstance(G.class);
  156. fail();
  157. } catch (ProvisionException e) {
  158. assertContains(e.getMessage(),
  159. "1) Error injecting method, java.lang.IllegalArgumentException",
  160. "Caused by: java.lang.IllegalArgumentException: java.lang.UnsupportedOperationException",
  161. "Caused by: java.lang.UnsupportedOperationException: Unsupported",
  162. "2) Error injecting method, java.lang.NullPointerException: can't inject second either",
  163. "Caused by: java.lang.NullPointerException: can't inject second either",
  164. "2 errors");
  165. }
  166. }
  167. public void testInjectInnerClass() throws Exception {
  168. Injector injector = Guice.createInjector();
  169. try {
  170. injector.getInstance(InnerClass.class);
  171. fail();
  172. } catch (Exception expected) {
  173. assertContains(expected.getMessage(),
  174. "Injecting into inner classes is not supported.",
  175. "while locating " + InnerClass.class.getName());
  176. }
  177. }
  178. public void testInjectLocalClass() throws Exception {
  179. class LocalClass {}
  180. Injector injector = Guice.createInjector();
  181. try {
  182. injector.getInstance(LocalClass.class);
  183. fail();
  184. } catch (Exception expected) {
  185. assertContains(expected.getMessage(),
  186. "Injecting into inner classes is not supported.",
  187. "while locating " + LocalClass.class.getName());
  188. }
  189. }
  190. public void testBindingAnnotationsOnMethodsAndConstructors() {
  191. try {
  192. Injector injector = Guice.createInjector();
  193. injector.getInstance(MethodWithBindingAnnotation.class);
  194. fail();
  195. } catch (ConfigurationException expected) {
  196. assertContains(expected.getMessage(), MethodWithBindingAnnotation.class.getName()
  197. + ".injectMe() is annotated with @", Green.class.getName() + "(), ",
  198. "but binding annotations should be applied to its parameters instead.",
  199. "while locating " + MethodWithBindingAnnotation.class.getName());
  200. }
  201. try {
  202. Guice.createInjector().getInstance(ConstructorWithBindingAnnotation.class);
  203. fail();
  204. } catch (ConfigurationException expected) {
  205. assertContains(expected.getMessage(), ConstructorWithBindingAnnotation.class.getName()
  206. + ".<init>() is annotated with @", Green.class.getName() + "(), ",
  207. "but binding annotations should be applied to its parameters instead.",
  208. "at " + ConstructorWithBindingAnnotation.class.getName() + ".class",
  209. "while locating " + ConstructorWithBindingAnnotation.class.getName());
  210. }
  211. }
  212. public void testBindingAnnotationWarningForScala() {
  213. Injector injector = Guice.createInjector(new AbstractModule() {
  214. @Override protected void configure() {
  215. bind(String.class).annotatedWith(Green.class).toInstance("lime!");
  216. }
  217. });
  218. injector.getInstance(LikeScala.class);
  219. }
  220. public void testLinkedBindings() {
  221. Injector injector = Guice.createInjector(new AbstractModule() {
  222. @Override protected void configure() {
  223. bind(D.class).to(RealD.class);
  224. }
  225. });
  226. try {
  227. injector.getInstance(D.class);
  228. fail();
  229. } catch (ProvisionException expected) {
  230. assertContains(expected.getMessage(),
  231. "at " + RealD.class.getName() + ".<init>(ProvisionExceptionTest.java:",
  232. "while locating " + RealD.class.getName(),
  233. "while locating " + D.class.getName());
  234. }
  235. }
  236. public void testProviderKeyBindings() {
  237. Injector injector = Guice.createInjector(new AbstractModule() {
  238. @Override protected void configure() {
  239. bind(D.class).toProvider(DProvider.class);
  240. }
  241. });
  242. try {
  243. injector.getInstance(D.class);
  244. fail();
  245. } catch (ProvisionException expected) {
  246. assertContains(expected.getMessage(),
  247. "while locating " + DProvider.class.getName(),
  248. "while locating " + D.class.getName());
  249. }
  250. }
  251. public void testDuplicateCausesCollapsed() {
  252. final RuntimeException sharedException = new RuntimeException("fail");
  253. Injector injector = Guice.createInjector(new AbstractModule() {
  254. @Override protected void configure() {}
  255. @Provides Integer i() { throw sharedException; }
  256. @Provides Double d() { throw sharedException; }
  257. });
  258. try{
  259. injector.getInstance(DoubleFailure.class);
  260. fail();
  261. } catch (ProvisionException pe) {
  262. assertEquals(sharedException, pe.getCause());
  263. assertEquals(2, pe.getErrorMessages().size());
  264. for (Message message : pe.getErrorMessages()) {
  265. assertEquals(sharedException, message.getCause());
  266. }
  267. }
  268. }
  269. public void testMultipleDuplicates() {
  270. final RuntimeException exception1 = new RuntimeException("fail");
  271. final RuntimeException exception2 = new RuntimeException("abort");
  272. Injector injector = Guice.createInjector(new AbstractModule() {
  273. @Override protected void configure() {}
  274. @Provides Integer i() { throw exception1; }
  275. @Provides Double d() { throw exception1; }
  276. @Provides String s() { throw exception2; }
  277. @Provides Number n() { throw exception2; }
  278. });
  279. try{
  280. injector.getInstance(QuadrupleFailure.class);
  281. fail();
  282. } catch (ProvisionException pe) {
  283. assertNull(pe.getCause());
  284. assertEquals(4, pe.getErrorMessages().size());
  285. String e1 = Throwables.getStackTraceAsString(exception1);
  286. String e2 = Throwables.getStackTraceAsString(exception2);
  287. assertContains(pe.getMessage(),
  288. "\n1) ", e1, "\n2) ", "(same stack trace as error #1)",
  289. "\n3) ", e2, "\n4) ", "(same stack trace as error #3)");
  290. }
  291. }
  292. static class DoubleFailure {
  293. @Inject DoubleFailure(Integer i, Double d) { }
  294. }
  295. static class QuadrupleFailure {
  296. @Inject QuadrupleFailure(Integer i, Double d, String s, Number n) { }
  297. }
  298. public void testDuplicatesDifferentInstances() {
  299. Injector injector = Guice.createInjector(new AbstractModule() {
  300. @Override protected void configure() {}
  301. @Provides Integer i() { throw new RuntimeException(); }
  302. });
  303. try{
  304. injector.getInstance(DoubleSameFailure.class);
  305. fail();
  306. } catch (ProvisionException pe) {
  307. assertNotNull(pe.toString(), pe.getCause());
  308. assertEquals(2, pe.getErrorMessages().size());
  309. for (Message message : pe.getErrorMessages()) {
  310. assertNotNull(message.toString(), message.getCause());
  311. }
  312. }
  313. }
  314. public void testMultipleDuplicatesDifferentInstaces() {
  315. Injector injector = Guice.createInjector(new AbstractModule() {
  316. @Override protected void configure() {}
  317. @Provides Integer i() { throw new RuntimeException("fail"); }
  318. @Provides String s() { throw new RuntimeException("abort"); }
  319. });
  320. try{
  321. injector.getInstance(QuadrupleSameFailure.class);
  322. fail();
  323. } catch (ProvisionException pe) {
  324. assertNull(pe.getCause());
  325. assertEquals(4, pe.getErrorMessages().size());
  326. assertContains(pe.getMessage(),
  327. "\n1) ", "Caused by: java.lang.RuntimeException: fail",
  328. "\n2) ", "Caused by: java.lang.RuntimeException (same stack trace as error #1)",
  329. "\n3) ", "Caused by: java.lang.RuntimeException: abort",
  330. "\n4) ", "Caused by: java.lang.RuntimeException (same stack trace as error #3)");
  331. }
  332. }
  333. static class DoubleSameFailure {
  334. @Inject DoubleSameFailure(Integer i1, Integer i2) { }
  335. }
  336. static class QuadrupleSameFailure {
  337. @Inject QuadrupleSameFailure(Integer i1, Integer i2, String s1, String s2) { }
  338. }
  339. private class InnerClass {}
  340. static class A {
  341. @Inject
  342. A(B b) { }
  343. }
  344. static class B {
  345. @Inject C c;
  346. }
  347. static class C {
  348. @Inject
  349. void setD(RealD d) { }
  350. }
  351. static class E {
  352. @Inject void setObject(Object o) {
  353. throw new UnsupportedOperationException();
  354. }
  355. }
  356. static class MethodWithBindingAnnotation {
  357. @Inject @Green void injectMe(String greenString) {}
  358. }
  359. static class ConstructorWithBindingAnnotation {
  360. // Suppress compiler errors by the error-prone checker InjectedConstructorAnnotations,
  361. // which catches injected constructors with binding annotations.
  362. @SuppressWarnings("InjectedConstructorAnnotations")
  363. @Inject @Green ConstructorWithBindingAnnotation(String greenString) {}
  364. }
  365. /**
  366. * In Scala, fields automatically get accessor methods with the same name. So we don't do
  367. * misplaced-binding annotation detection if the offending method has a matching field.
  368. */
  369. static class LikeScala {
  370. @Inject @Green String green;
  371. @Inject @Green String green() { return green; }
  372. }
  373. @Retention(RUNTIME)
  374. @Target({ FIELD, PARAMETER, CONSTRUCTOR, METHOD })
  375. @BindingAnnotation
  376. @interface Green {}
  377. interface D {}
  378. static class RealD implements D {
  379. @Inject RealD() {
  380. throw new UnsupportedOperationException();
  381. }
  382. }
  383. static class DProvider implements Provider<D> {
  384. public D get() {
  385. throw new UnsupportedOperationException();
  386. }
  387. }
  388. static class F {
  389. @Inject public F() {
  390. throw new ProvisionException("User Exception", new RuntimeException());
  391. }
  392. }
  393. static class FProvider implements Provider<F> {
  394. public F get() {
  395. return new F();
  396. }
  397. }
  398. static class G {
  399. @Inject void injectFirst() {
  400. throw new IllegalArgumentException(new UnsupportedOperationException("Unsupported"));
  401. }
  402. @Inject void injectSecond() {
  403. throw new NullPointerException("can't inject second either");
  404. }
  405. }
  406. }