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

/extensions/throwingproviders/test/com/google/inject/throwingproviders/ThrowingProviderTest.java

https://gitlab.com/metamorphiccode/guice
Java | 878 lines | 740 code | 113 blank | 25 comment | 8 complexity | 20fccaeb1ce496a2069591b214a1e0af 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.throwingproviders;
  17. import static java.lang.annotation.ElementType.METHOD;
  18. import static java.lang.annotation.RetentionPolicy.RUNTIME;
  19. import com.google.common.base.Function;
  20. import com.google.common.collect.ImmutableList;
  21. import com.google.common.collect.ImmutableSet;
  22. import com.google.common.collect.Iterables;
  23. import com.google.inject.AbstractModule;
  24. import com.google.inject.BindingAnnotation;
  25. import com.google.inject.CreationException;
  26. import com.google.inject.Guice;
  27. import com.google.inject.Inject;
  28. import com.google.inject.Injector;
  29. import com.google.inject.Key;
  30. import com.google.inject.TypeLiteral;
  31. import com.google.inject.internal.util.Classes;
  32. import com.google.inject.name.Named;
  33. import com.google.inject.name.Names;
  34. import com.google.inject.spi.Dependency;
  35. import com.google.inject.spi.HasDependencies;
  36. import com.google.inject.spi.Message;
  37. import junit.framework.TestCase;
  38. import java.io.IOException;
  39. import java.lang.annotation.Annotation;
  40. import java.lang.annotation.Retention;
  41. import java.lang.annotation.Target;
  42. import java.rmi.AccessException;
  43. import java.rmi.RemoteException;
  44. import java.util.Arrays;
  45. import java.util.List;
  46. import java.util.Set;
  47. import java.util.TooManyListenersException;
  48. /**
  49. * @author jmourits@google.com (Jerome Mourits)
  50. * @author jessewilson@google.com (Jesse Wilson)
  51. */
  52. @SuppressWarnings("deprecation")
  53. public class ThrowingProviderTest extends TestCase {
  54. @Target(METHOD) @Retention(RUNTIME) @BindingAnnotation
  55. @interface NotExceptionScoping { };
  56. private final TypeLiteral<RemoteProvider<String>> remoteProviderOfString
  57. = new TypeLiteral<RemoteProvider<String>>() { };
  58. private final MockRemoteProvider<String> mockRemoteProvider = new MockRemoteProvider<String>();
  59. private final TestScope testScope = new TestScope();
  60. private Injector bindInjector = Guice.createInjector(new AbstractModule() {
  61. protected void configure() {
  62. ThrowingProviderBinder.create(binder())
  63. .bind(RemoteProvider.class, String.class)
  64. .to(mockRemoteProvider)
  65. .in(testScope);
  66. ThrowingProviderBinder.create(binder())
  67. .bind(RemoteProvider.class, String.class)
  68. .annotatedWith(NotExceptionScoping.class)
  69. .scopeExceptions(false)
  70. .to(mockRemoteProvider)
  71. .in(testScope);
  72. }
  73. });
  74. private Injector providesInjector = Guice.createInjector(new AbstractModule() {
  75. protected void configure() {
  76. install(ThrowingProviderBinder.forModule(this));
  77. bindScope(TestScope.Scoped.class, testScope);
  78. }
  79. @SuppressWarnings("unused")
  80. @CheckedProvides(RemoteProvider.class)
  81. @TestScope.Scoped
  82. String throwOrGet() throws RemoteException {
  83. return mockRemoteProvider.get();
  84. }
  85. @SuppressWarnings("unused")
  86. @CheckedProvides(value = RemoteProvider.class, scopeExceptions = false)
  87. @NotExceptionScoping
  88. @TestScope.Scoped
  89. String notExceptionScopingThrowOrGet() throws RemoteException {
  90. return mockRemoteProvider.get();
  91. }
  92. });
  93. public void testExceptionsThrown_Bind() {
  94. tExceptionsThrown(bindInjector);
  95. }
  96. public void testExceptionsThrown_Provides() {
  97. tExceptionsThrown(providesInjector);
  98. }
  99. private void tExceptionsThrown(Injector injector) {
  100. RemoteProvider<String> remoteProvider =
  101. injector.getInstance(Key.get(remoteProviderOfString));
  102. mockRemoteProvider.throwOnNextGet("kaboom!");
  103. try {
  104. remoteProvider.get();
  105. fail();
  106. } catch (RemoteException expected) {
  107. assertEquals("kaboom!", expected.getMessage());
  108. }
  109. }
  110. public void testValuesScoped_Bind() throws RemoteException {
  111. tValuesScoped(bindInjector, null);
  112. }
  113. public void testValuesScoped_Provides() throws RemoteException {
  114. tValuesScoped(providesInjector, null);
  115. }
  116. public void testValuesScopedWhenNotExceptionScoping_Bind() throws RemoteException {
  117. tValuesScoped(bindInjector, NotExceptionScoping.class);
  118. }
  119. public void testValuesScopedWhenNotExceptionScoping_Provides() throws RemoteException {
  120. tValuesScoped(providesInjector, NotExceptionScoping.class);
  121. }
  122. private void tValuesScoped(Injector injector, Class<? extends Annotation> annotation)
  123. throws RemoteException {
  124. Key<RemoteProvider<String>> key = annotation != null ?
  125. Key.get(remoteProviderOfString, annotation) :
  126. Key.get(remoteProviderOfString);
  127. RemoteProvider<String> remoteProvider = injector.getInstance(key);
  128. mockRemoteProvider.setNextToReturn("A");
  129. assertEquals("A", remoteProvider.get());
  130. mockRemoteProvider.setNextToReturn("B");
  131. assertEquals("A", remoteProvider.get());
  132. testScope.beginNewScope();
  133. assertEquals("B", remoteProvider.get());
  134. }
  135. public void testExceptionsScoped_Bind() {
  136. tExceptionsScoped(bindInjector);
  137. }
  138. public void testExceptionsScoped_Provides() {
  139. tExceptionsScoped(providesInjector);
  140. }
  141. private void tExceptionsScoped(Injector injector) {
  142. RemoteProvider<String> remoteProvider =
  143. injector.getInstance(Key.get(remoteProviderOfString));
  144. mockRemoteProvider.throwOnNextGet("A");
  145. try {
  146. remoteProvider.get();
  147. fail();
  148. } catch (RemoteException expected) {
  149. assertEquals("A", expected.getMessage());
  150. }
  151. mockRemoteProvider.throwOnNextGet("B");
  152. try {
  153. remoteProvider.get();
  154. fail();
  155. } catch (RemoteException expected) {
  156. assertEquals("A", expected.getMessage());
  157. }
  158. }
  159. public void testExceptionsNotScopedWhenNotExceptionScoping_Bind() {
  160. tExceptionsNotScopedWhenNotExceptionScoping(bindInjector);
  161. }
  162. public void testExceptionsNotScopedWhenNotExceptionScoping_Provides() {
  163. tExceptionsNotScopedWhenNotExceptionScoping(providesInjector);
  164. }
  165. private void tExceptionsNotScopedWhenNotExceptionScoping(Injector injector) {
  166. RemoteProvider<String> remoteProvider =
  167. injector.getInstance(Key.get(remoteProviderOfString, NotExceptionScoping.class));
  168. mockRemoteProvider.throwOnNextGet("A");
  169. try {
  170. remoteProvider.get();
  171. fail();
  172. } catch (RemoteException expected) {
  173. assertEquals("A", expected.getMessage());
  174. }
  175. mockRemoteProvider.throwOnNextGet("B");
  176. try {
  177. remoteProvider.get();
  178. fail();
  179. } catch (RemoteException expected) {
  180. assertEquals("B", expected.getMessage());
  181. }
  182. }
  183. public void testAnnotations_Bind() throws RemoteException {
  184. final MockRemoteProvider<String> mockRemoteProviderA = new MockRemoteProvider<String>();
  185. final MockRemoteProvider<String> mockRemoteProviderB = new MockRemoteProvider<String>();
  186. bindInjector = Guice.createInjector(new AbstractModule() {
  187. protected void configure() {
  188. ThrowingProviderBinder.create(binder())
  189. .bind(RemoteProvider.class, String.class)
  190. .annotatedWith(Names.named("a"))
  191. .to(mockRemoteProviderA);
  192. ThrowingProviderBinder.create(binder())
  193. .bind(RemoteProvider.class, String.class)
  194. .to(mockRemoteProviderB);
  195. }
  196. });
  197. tAnnotations(bindInjector, mockRemoteProviderA, mockRemoteProviderB);
  198. }
  199. public void testAnnotations_Provides() throws RemoteException {
  200. final MockRemoteProvider<String> mockRemoteProviderA = new MockRemoteProvider<String>();
  201. final MockRemoteProvider<String> mockRemoteProviderB = new MockRemoteProvider<String>();
  202. providesInjector = Guice.createInjector(new AbstractModule() {
  203. protected void configure() {
  204. install(ThrowingProviderBinder.forModule(this));
  205. }
  206. @SuppressWarnings("unused")
  207. @CheckedProvides(RemoteProvider.class)
  208. @Named("a")
  209. String throwOrGet() throws RemoteException {
  210. return mockRemoteProviderA.get();
  211. }
  212. @SuppressWarnings("unused")
  213. @CheckedProvides(RemoteProvider.class)
  214. String throwOrGet2() throws RemoteException {
  215. return mockRemoteProviderB.get();
  216. }
  217. });
  218. tAnnotations(providesInjector, mockRemoteProviderA, mockRemoteProviderB);
  219. }
  220. private void tAnnotations(Injector injector, MockRemoteProvider<String> mockA,
  221. MockRemoteProvider<String> mockB) throws RemoteException {
  222. mockA.setNextToReturn("A");
  223. mockB.setNextToReturn("B");
  224. assertEquals("A",
  225. injector.getInstance(Key.get(remoteProviderOfString, Names.named("a"))).get());
  226. assertEquals("B",
  227. injector.getInstance(Key.get(remoteProviderOfString)).get());
  228. }
  229. public void testUndeclaredExceptions_Bind() throws RemoteException {
  230. tUndeclaredExceptions(bindInjector);
  231. }
  232. public void testUndeclaredExceptions_Provides() throws RemoteException {
  233. tUndeclaredExceptions(providesInjector);
  234. }
  235. private void tUndeclaredExceptions(Injector injector) throws RemoteException {
  236. RemoteProvider<String> remoteProvider =
  237. injector.getInstance(Key.get(remoteProviderOfString));
  238. mockRemoteProvider.throwOnNextGet(new IndexOutOfBoundsException("A"));
  239. try {
  240. remoteProvider.get();
  241. fail();
  242. } catch (RuntimeException e) {
  243. assertEquals("A", e.getCause().getMessage());
  244. }
  245. // undeclared exceptions shouldn't be scoped
  246. mockRemoteProvider.throwOnNextGet(new IndexOutOfBoundsException("B"));
  247. try {
  248. remoteProvider.get();
  249. fail();
  250. } catch (RuntimeException e) {
  251. assertEquals("B", e.getCause().getMessage());
  252. }
  253. }
  254. public void testThrowingProviderSubclassing() throws RemoteException {
  255. final SubMockRemoteProvider aProvider = new SubMockRemoteProvider();
  256. aProvider.setNextToReturn("A");
  257. bindInjector = Guice.createInjector(new AbstractModule() {
  258. protected void configure() {
  259. ThrowingProviderBinder.create(binder())
  260. .bind(RemoteProvider.class, String.class)
  261. .to(aProvider);
  262. }
  263. });
  264. assertEquals("A",
  265. bindInjector.getInstance(Key.get(remoteProviderOfString)).get());
  266. }
  267. static class SubMockRemoteProvider extends MockRemoteProvider<String> { }
  268. public void testBindingToNonInterfaceType_Bind() throws RemoteException {
  269. try {
  270. Guice.createInjector(new AbstractModule() {
  271. protected void configure() {
  272. ThrowingProviderBinder.create(binder())
  273. .bind(MockRemoteProvider.class, String.class)
  274. .to(mockRemoteProvider);
  275. }
  276. });
  277. fail();
  278. } catch (CreationException expected) {
  279. assertEquals(MockRemoteProvider.class.getName() + " must be an interface",
  280. Iterables.getOnlyElement(expected.getErrorMessages()).getMessage());
  281. }
  282. }
  283. public void testBindingToNonInterfaceType_Provides() throws RemoteException {
  284. try {
  285. Guice.createInjector(new AbstractModule() {
  286. protected void configure() {
  287. install(ThrowingProviderBinder.forModule(this));
  288. }
  289. @SuppressWarnings("unused")
  290. @CheckedProvides(MockRemoteProvider.class)
  291. String foo() {
  292. return null;
  293. }
  294. });
  295. fail();
  296. } catch (CreationException expected) {
  297. assertEquals(MockRemoteProvider.class.getName() + " must be an interface",
  298. Iterables.getOnlyElement(expected.getErrorMessages()).getMessage());
  299. }
  300. }
  301. public void testBindingToSubSubInterface_Bind() throws RemoteException {
  302. try {
  303. bindInjector = Guice.createInjector(new AbstractModule() {
  304. protected void configure() {
  305. ThrowingProviderBinder.create(binder())
  306. .bind(SubRemoteProvider.class, String.class);
  307. }
  308. });
  309. fail();
  310. } catch (CreationException expected) {
  311. assertEquals(SubRemoteProvider.class.getName() + " must extend CheckedProvider (and only CheckedProvider)",
  312. Iterables.getOnlyElement(expected.getErrorMessages()).getMessage());
  313. }
  314. }
  315. public void testBindingToSubSubInterface_Provides() throws RemoteException {
  316. try {
  317. Guice.createInjector(new AbstractModule() {
  318. protected void configure() {
  319. install(ThrowingProviderBinder.forModule(this));
  320. }
  321. @SuppressWarnings("unused")
  322. @CheckedProvides(SubRemoteProvider.class)
  323. String foo() {
  324. return null;
  325. }
  326. });
  327. fail();
  328. } catch (CreationException expected) {
  329. assertEquals(SubRemoteProvider.class.getName() + " must extend CheckedProvider (and only CheckedProvider)",
  330. Iterables.getOnlyElement(expected.getErrorMessages()).getMessage());
  331. }
  332. }
  333. interface SubRemoteProvider extends RemoteProvider<String> { }
  334. public void testBindingToInterfaceWithExtraMethod_Bind() throws RemoteException {
  335. try {
  336. bindInjector = Guice.createInjector(new AbstractModule() {
  337. protected void configure() {
  338. ThrowingProviderBinder.create(binder())
  339. .bind(RemoteProviderWithExtraMethod.class, String.class);
  340. }
  341. });
  342. fail();
  343. } catch (CreationException expected) {
  344. assertEquals(RemoteProviderWithExtraMethod.class.getName() + " may not declare any new methods, but declared "
  345. + RemoteProviderWithExtraMethod.class.getDeclaredMethods()[0].toGenericString(),
  346. Iterables.getOnlyElement(expected.getErrorMessages()).getMessage());
  347. }
  348. }
  349. public void testBindingToInterfaceWithExtraMethod_Provides() throws RemoteException {
  350. try {
  351. Guice.createInjector(new AbstractModule() {
  352. protected void configure() {
  353. install(ThrowingProviderBinder.forModule(this));
  354. }
  355. @SuppressWarnings("unused")
  356. @CheckedProvides(RemoteProviderWithExtraMethod.class)
  357. String foo() {
  358. return null;
  359. }
  360. });
  361. fail();
  362. } catch (CreationException expected) {
  363. assertEquals(RemoteProviderWithExtraMethod.class.getName() + " may not declare any new methods, but declared "
  364. + RemoteProviderWithExtraMethod.class.getDeclaredMethods()[0].toGenericString(),
  365. Iterables.getOnlyElement(expected.getErrorMessages()).getMessage());
  366. }
  367. }
  368. public void testDependencies_Bind() {
  369. bindInjector = Guice.createInjector(new AbstractModule() {
  370. protected void configure() {
  371. bind(String.class).toInstance("Foo");
  372. bind(Integer.class).toInstance(5);
  373. bind(Double.class).toInstance(5d);
  374. bind(Long.class).toInstance(5L);
  375. ThrowingProviderBinder.create(binder())
  376. .bind(RemoteProvider.class, String.class)
  377. .to(DependentRemoteProvider.class);
  378. }
  379. });
  380. HasDependencies hasDependencies =
  381. (HasDependencies)bindInjector.getBinding(Key.get(remoteProviderOfString));
  382. hasDependencies =
  383. (HasDependencies)bindInjector.getBinding(
  384. Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey());
  385. // Make sure that that is dependent on DependentRemoteProvider.
  386. assertEquals(Dependency.get(Key.get(DependentRemoteProvider.class)),
  387. Iterables.getOnlyElement(hasDependencies.getDependencies()));
  388. // And make sure DependentRemoteProvider has the proper dependencies.
  389. hasDependencies = (HasDependencies)bindInjector.getBinding(DependentRemoteProvider.class);
  390. Set<Key<?>> dependencyKeys = ImmutableSet.copyOf(
  391. Iterables.transform(hasDependencies.getDependencies(),
  392. new Function<Dependency<?>, Key<?>>() {
  393. public Key<?> apply(Dependency<?> from) {
  394. return from.getKey();
  395. }
  396. }));
  397. assertEquals(ImmutableSet.<Key<?>>of(Key.get(String.class), Key.get(Integer.class),
  398. Key.get(Long.class), Key.get(Double.class)), dependencyKeys);
  399. }
  400. public void testDependencies_Provides() {
  401. providesInjector = Guice.createInjector(new AbstractModule() {
  402. protected void configure() {
  403. bind(String.class).toInstance("Foo");
  404. bind(Integer.class).toInstance(5);
  405. bind(Double.class).toInstance(5d);
  406. bind(Long.class).toInstance(5L);
  407. install(ThrowingProviderBinder.forModule(this));
  408. }
  409. @SuppressWarnings("unused")
  410. @CheckedProvides(RemoteProvider.class)
  411. String foo(String s, Integer i, Double d, Long l) {
  412. return null;
  413. }
  414. });
  415. HasDependencies hasDependencies =
  416. (HasDependencies)providesInjector.getBinding(Key.get(remoteProviderOfString));
  417. // RemoteProvider<String> is dependent on the provider method..
  418. hasDependencies =
  419. (HasDependencies)providesInjector.getBinding(
  420. Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey());
  421. // And the provider method has our real dependencies..
  422. hasDependencies = (HasDependencies)providesInjector.getBinding(
  423. Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey());
  424. Set<Key<?>> dependencyKeys = ImmutableSet.copyOf(
  425. Iterables.transform(hasDependencies.getDependencies(),
  426. new Function<Dependency<?>, Key<?>>() {
  427. public Key<?> apply(Dependency<?> from) {
  428. return from.getKey();
  429. }
  430. }));
  431. assertEquals(ImmutableSet.<Key<?>>of(Key.get(String.class), Key.get(Integer.class),
  432. Key.get(Long.class), Key.get(Double.class)), dependencyKeys);
  433. }
  434. interface RemoteProviderWithExtraMethod<T> extends ThrowingProvider<T, RemoteException> {
  435. T get(T defaultValue) throws RemoteException;
  436. }
  437. interface RemoteProvider<T> extends ThrowingProvider<T, RemoteException> { }
  438. static class DependentRemoteProvider<T> implements RemoteProvider<T> {
  439. @Inject double foo;
  440. @Inject public DependentRemoteProvider(String foo, int bar) {
  441. }
  442. @Inject void initialize(long foo) {}
  443. public T get() throws RemoteException {
  444. return null;
  445. }
  446. }
  447. static class MockRemoteProvider<T> implements RemoteProvider<T> {
  448. Exception nextToThrow;
  449. T nextToReturn;
  450. public void throwOnNextGet(String message) {
  451. throwOnNextGet(new RemoteException(message));
  452. }
  453. public void throwOnNextGet(Exception nextToThrow) {
  454. this.nextToThrow = nextToThrow;
  455. }
  456. public void setNextToReturn(T nextToReturn) {
  457. this.nextToReturn = nextToReturn;
  458. }
  459. public T get() throws RemoteException {
  460. if (nextToThrow instanceof RemoteException) {
  461. throw (RemoteException) nextToThrow;
  462. } else if (nextToThrow instanceof RuntimeException) {
  463. throw (RuntimeException) nextToThrow;
  464. } else if (nextToThrow == null) {
  465. return nextToReturn;
  466. } else {
  467. throw new AssertionError("nextToThrow must be a runtime or remote exception");
  468. }
  469. }
  470. }
  471. public void testBindingToInterfaceWithBoundValueType_Bind() throws RemoteException {
  472. bindInjector = Guice.createInjector(new AbstractModule() {
  473. protected void configure() {
  474. ThrowingProviderBinder.create(binder())
  475. .bind(StringRemoteProvider.class, String.class)
  476. .to(new StringRemoteProvider() {
  477. public String get() throws RemoteException {
  478. return "A";
  479. }
  480. });
  481. }
  482. });
  483. assertEquals("A", bindInjector.getInstance(StringRemoteProvider.class).get());
  484. }
  485. public void testBindingToInterfaceWithBoundValueType_Provides() throws RemoteException {
  486. providesInjector = Guice.createInjector(new AbstractModule() {
  487. protected void configure() {
  488. install(ThrowingProviderBinder.forModule(this));
  489. }
  490. @SuppressWarnings("unused")
  491. @CheckedProvides(StringRemoteProvider.class)
  492. String foo() throws RemoteException {
  493. return "A";
  494. }
  495. });
  496. assertEquals("A", providesInjector.getInstance(StringRemoteProvider.class).get());
  497. }
  498. interface StringRemoteProvider extends ThrowingProvider<String, RemoteException> { }
  499. public void testBindingToInterfaceWithGeneric_Bind() throws RemoteException {
  500. bindInjector = Guice.createInjector(new AbstractModule() {
  501. protected void configure() {
  502. ThrowingProviderBinder.create(binder())
  503. .bind(RemoteProvider.class, new TypeLiteral<List<String>>() { }.getType())
  504. .to(new RemoteProvider<List<String>>() {
  505. public List<String> get() throws RemoteException {
  506. return Arrays.asList("A", "B");
  507. }
  508. });
  509. }
  510. });
  511. Key<RemoteProvider<List<String>>> key
  512. = Key.get(new TypeLiteral<RemoteProvider<List<String>>>() { });
  513. assertEquals(Arrays.asList("A", "B"), bindInjector.getInstance(key).get());
  514. }
  515. public void testBindingToInterfaceWithGeneric_Provides() throws RemoteException {
  516. providesInjector = Guice.createInjector(new AbstractModule() {
  517. protected void configure() {
  518. install(ThrowingProviderBinder.forModule(this));
  519. }
  520. @SuppressWarnings("unused")
  521. @CheckedProvides(RemoteProvider.class)
  522. List<String> foo() throws RemoteException {
  523. return Arrays.asList("A", "B");
  524. }
  525. });
  526. Key<RemoteProvider<List<String>>> key
  527. = Key.get(new TypeLiteral<RemoteProvider<List<String>>>() { });
  528. assertEquals(Arrays.asList("A", "B"), providesInjector.getInstance(key).get());
  529. }
  530. public void testProviderMethodWithWrongException() {
  531. try {
  532. Guice.createInjector(new AbstractModule() {
  533. protected void configure() {
  534. install(ThrowingProviderBinder.forModule(this));
  535. }
  536. @SuppressWarnings("unused")
  537. @CheckedProvides(RemoteProvider.class)
  538. String foo() throws InterruptedException {
  539. return null;
  540. }
  541. });
  542. fail();
  543. } catch(CreationException ce) {
  544. assertEquals(InterruptedException.class.getName() + " is not compatible with the exceptions (["
  545. + RemoteException.class + "]) declared in the CheckedProvider interface ("
  546. + RemoteProvider.class.getName() + ")",
  547. Iterables.getOnlyElement(ce.getErrorMessages()).getMessage());
  548. }
  549. }
  550. public void testProviderMethodWithSubclassOfExceptionIsOk() {
  551. providesInjector = Guice.createInjector(new AbstractModule() {
  552. protected void configure() {
  553. install(ThrowingProviderBinder.forModule(this));
  554. }
  555. @SuppressWarnings("unused")
  556. @CheckedProvides(RemoteProvider.class)
  557. String foo() throws AccessException {
  558. throw new AccessException("boo!");
  559. }
  560. });
  561. RemoteProvider<String> remoteProvider =
  562. providesInjector.getInstance(Key.get(remoteProviderOfString));
  563. try {
  564. remoteProvider.get();
  565. fail();
  566. } catch (RemoteException expected) {
  567. assertTrue(expected instanceof AccessException);
  568. assertEquals("boo!", expected.getMessage());
  569. }
  570. }
  571. public void testProviderMethodWithSuperclassFails() {
  572. try {
  573. Guice.createInjector(new AbstractModule() {
  574. protected void configure() {
  575. install(ThrowingProviderBinder.forModule(this));
  576. }
  577. @SuppressWarnings("unused")
  578. @CheckedProvides(RemoteProvider.class)
  579. String foo() throws IOException {
  580. return null;
  581. }
  582. });
  583. fail();
  584. } catch(CreationException ce) {
  585. assertEquals(IOException.class.getName() + " is not compatible with the exceptions (["
  586. + RemoteException.class + "]) declared in the CheckedProvider interface ("
  587. + RemoteProvider.class.getName() + ")",
  588. Iterables.getOnlyElement(ce.getErrorMessages()).getMessage());
  589. }
  590. }
  591. public void testProviderMethodWithRuntimeExceptionsIsOk() throws RemoteException {
  592. providesInjector = Guice.createInjector(new AbstractModule() {
  593. protected void configure() {
  594. install(ThrowingProviderBinder.forModule(this));
  595. }
  596. @SuppressWarnings("unused")
  597. @CheckedProvides(RemoteProvider.class)
  598. String foo() throws RuntimeException {
  599. throw new RuntimeException("boo!");
  600. }
  601. });
  602. RemoteProvider<String> remoteProvider =
  603. providesInjector.getInstance(Key.get(remoteProviderOfString));
  604. try {
  605. remoteProvider.get();
  606. fail();
  607. } catch (RuntimeException expected) {
  608. assertEquals("boo!", expected.getCause().getMessage());
  609. }
  610. }
  611. public void testProviderMethodWithManyExceptions() {
  612. try {
  613. Guice.createInjector(new AbstractModule() {
  614. protected void configure() {
  615. install(ThrowingProviderBinder.forModule(this));
  616. }
  617. @SuppressWarnings("unused")
  618. @CheckedProvides(RemoteProvider.class)
  619. String foo() throws InterruptedException, RuntimeException, RemoteException,
  620. AccessException, TooManyListenersException {
  621. return null;
  622. }
  623. });
  624. fail();
  625. } catch(CreationException ce) {
  626. // The only two that should fail are Interrupted & TooManyListeners.. the rest are OK.
  627. List<Message> errors = ImmutableList.copyOf(ce.getErrorMessages());
  628. assertEquals(InterruptedException.class.getName() + " is not compatible with the exceptions (["
  629. + RemoteException.class + "]) declared in the CheckedProvider interface ("
  630. + RemoteProvider.class.getName() + ")",
  631. errors.get(0).getMessage());
  632. assertEquals(TooManyListenersException.class.getName() + " is not compatible with the exceptions (["
  633. + RemoteException.class + "]) declared in the CheckedProvider interface ("
  634. + RemoteProvider.class.getName() + ")",
  635. errors.get(1).getMessage());
  636. assertEquals(2, errors.size());
  637. }
  638. }
  639. public void testMoreTypeParameters() {
  640. try {
  641. Guice.createInjector(new AbstractModule() {
  642. protected void configure() {
  643. install(ThrowingProviderBinder.forModule(this));
  644. }
  645. @SuppressWarnings("unused")
  646. @CheckedProvides(TooManyTypeParameters.class)
  647. String foo() {
  648. return null;
  649. }
  650. });
  651. fail();
  652. } catch(CreationException ce) {
  653. assertEquals(TooManyTypeParameters.class.getName() + " has more than one generic type parameter: [T, P]",
  654. Iterables.getOnlyElement(ce.getErrorMessages()).getMessage());
  655. }
  656. }
  657. public void testWrongThrowingProviderType() {
  658. try {
  659. Guice.createInjector(new AbstractModule() {
  660. protected void configure() {
  661. install(ThrowingProviderBinder.forModule(this));
  662. }
  663. @SuppressWarnings("unused")
  664. @CheckedProvides(WrongThrowingProviderType.class)
  665. String foo() {
  666. return null;
  667. }
  668. });
  669. fail();
  670. } catch(CreationException ce) {
  671. assertEquals(WrongThrowingProviderType.class.getName()
  672. + " does not properly extend CheckedProvider, the first type parameter of CheckedProvider "
  673. + "(java.lang.String) is not a generic type",
  674. Iterables.getOnlyElement(ce.getErrorMessages()).getMessage());
  675. }
  676. }
  677. public void testOneMethodThatIsntGet() {
  678. try {
  679. Guice.createInjector(new AbstractModule() {
  680. protected void configure() {
  681. install(ThrowingProviderBinder.forModule(this));
  682. }
  683. @SuppressWarnings("unused")
  684. @CheckedProvides(OneNoneGetMethod.class)
  685. String foo() {
  686. return null;
  687. }
  688. });
  689. fail();
  690. } catch(CreationException ce) {
  691. assertEquals(OneNoneGetMethod.class.getName()
  692. + " may not declare any new methods, but declared " + Classes.toString(OneNoneGetMethod.class.getDeclaredMethods()[0]),
  693. Iterables.getOnlyElement(ce.getErrorMessages()).getMessage());
  694. }
  695. }
  696. public void testManyMethods() {
  697. try {
  698. Guice.createInjector(new AbstractModule() {
  699. protected void configure() {
  700. install(ThrowingProviderBinder.forModule(this));
  701. }
  702. @SuppressWarnings("unused")
  703. @CheckedProvides(ManyMethods.class)
  704. String foo() {
  705. return null;
  706. }
  707. });
  708. fail();
  709. } catch(CreationException ce) {
  710. assertEquals(ManyMethods.class.getName()
  711. + " may not declare any new methods, but declared " + Arrays.asList(ManyMethods.class.getDeclaredMethods()),
  712. Iterables.getOnlyElement(ce.getErrorMessages()).getMessage());
  713. }
  714. }
  715. public void testIncorrectPredefinedType_Bind() {
  716. try {
  717. Guice.createInjector(new AbstractModule() {
  718. protected void configure() {
  719. ThrowingProviderBinder.create(binder())
  720. .bind(StringRemoteProvider.class, Integer.class)
  721. .to(new StringRemoteProvider() {
  722. public String get() throws RemoteException {
  723. return "A";
  724. }
  725. });
  726. }
  727. });
  728. fail();
  729. } catch(CreationException ce) {
  730. assertEquals(StringRemoteProvider.class.getName()
  731. + " expects the value type to be java.lang.String, but it was java.lang.Integer",
  732. Iterables.getOnlyElement(ce.getErrorMessages()).getMessage());
  733. }
  734. }
  735. public void testIncorrectPredefinedType_Provides() {
  736. try {
  737. Guice.createInjector(new AbstractModule() {
  738. protected void configure() {
  739. install(ThrowingProviderBinder.forModule(this));
  740. }
  741. @SuppressWarnings("unused")
  742. @CheckedProvides(StringRemoteProvider.class)
  743. Integer foo() {
  744. return null;
  745. }
  746. });
  747. fail();
  748. } catch(CreationException ce) {
  749. assertEquals(StringRemoteProvider.class.getName()
  750. + " expects the value type to be java.lang.String, but it was java.lang.Integer",
  751. Iterables.getOnlyElement(ce.getErrorMessages()).getMessage());
  752. }
  753. }
  754. private static interface TooManyTypeParameters<T, P> extends ThrowingProvider<T, Exception> {
  755. }
  756. private static interface WrongThrowingProviderType<T> extends ThrowingProvider<String, Exception> {
  757. }
  758. private static interface OneNoneGetMethod<T> extends ThrowingProvider<T, Exception> {
  759. T bar();
  760. }
  761. private static interface ManyMethods<T> extends ThrowingProvider<T, Exception> {
  762. T bar();
  763. String baz();
  764. }
  765. }