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 17package com.google.inject.throwingproviders; 18 19import static java.lang.annotation.ElementType.METHOD; 20import static java.lang.annotation.RetentionPolicy.RUNTIME; 21 22import com.google.common.base.Function; 23import com.google.common.collect.ImmutableList; 24import com.google.common.collect.ImmutableSet; 25import com.google.common.collect.Iterables; 26import com.google.common.collect.Lists; 27import com.google.inject.AbstractModule; 28import com.google.inject.Asserts; 29import com.google.inject.BindingAnnotation; 30import com.google.inject.CreationException; 31import com.google.inject.Guice; 32import com.google.inject.Inject; 33import com.google.inject.Injector; 34import com.google.inject.Key; 35import com.google.inject.OutOfScopeException; 36import com.google.inject.Provider; 37import com.google.inject.ProvisionException; 38import com.google.inject.Scope; 39import com.google.inject.ScopeAnnotation; 40import com.google.inject.TypeLiteral; 41import com.google.inject.internal.util.Classes; 42import com.google.inject.name.Named; 43import com.google.inject.name.Names; 44import com.google.inject.spi.Dependency; 45import com.google.inject.spi.HasDependencies; 46import com.google.inject.spi.Message; 47import com.google.inject.throwingproviders.ThrowingProviderBinder.Result; 48 49import junit.framework.TestCase; 50 51import java.io.IOException; 52import java.lang.annotation.Annotation; 53import java.lang.annotation.ElementType; 54import java.lang.annotation.Retention; 55import java.lang.annotation.RetentionPolicy; 56import java.lang.annotation.Target; 57import java.net.BindException; 58import java.rmi.AccessException; 59import java.rmi.RemoteException; 60import java.util.ArrayList; 61import java.util.Arrays; 62import java.util.List; 63import java.util.Set; 64import java.util.TooManyListenersException; 65 66/** 67 * @author jmourits@google.com (Jerome Mourits) 68 * @author jessewilson@google.com (Jesse Wilson) 69 * @author sameb@google.com (Sam Berlin) 70 */ 71public class CheckedProviderTest extends TestCase { 72 @Target(METHOD) @Retention(RUNTIME) @BindingAnnotation 73 @interface NotExceptionScoping { }; 74 75 private static final Function<Dependency<?>, Key<?>> DEPENDENCY_TO_KEY = 76 new Function<Dependency<?>, Key<?>>() { 77 public Key<?> apply(Dependency<?> from) { 78 return from.getKey(); 79 } 80 }; 81 82 private final TypeLiteral<RemoteProvider<Foo>> remoteProviderOfFoo 83 = new TypeLiteral<RemoteProvider<Foo>>() { }; 84 private final MockRemoteProvider<Foo> mockRemoteProvider = new MockRemoteProvider<Foo>(); 85 private final TestScope testScope = new TestScope(); 86 87 private Injector bindInjector; 88 private Injector providesInjector; 89 private Injector cxtorInjector; 90 91 @Override 92 protected void setUp() throws Exception { 93 MockFoo.nextToThrow = null; 94 MockFoo.nextToReturn = null; 95 AnotherMockFoo.nextToThrow = null; 96 AnotherMockFoo.nextToReturn = null; 97 98 bindInjector = Guice.createInjector(new AbstractModule() { 99 @Override 100 protected void configure() { 101 ThrowingProviderBinder.create(binder()) 102 .bind(RemoteProvider.class, Foo.class) 103 .to(mockRemoteProvider) 104 .in(testScope); 105 106 ThrowingProviderBinder.create(binder()) 107 .bind(RemoteProvider.class, Foo.class) 108 .annotatedWith(NotExceptionScoping.class) 109 .scopeExceptions(false) 110 .to(mockRemoteProvider) 111 .in(testScope); 112 113 } 114 }); 115 116 providesInjector = Guice.createInjector(new AbstractModule() { 117 @Override 118 protected void configure() { 119 install(ThrowingProviderBinder.forModule(this)); 120 bindScope(TestScope.Scoped.class, testScope); 121 } 122 123 @SuppressWarnings("unused") 124 @CheckedProvides(RemoteProvider.class) 125 @TestScope.Scoped 126 Foo throwOrGet() throws RemoteException, BindException { 127 return mockRemoteProvider.get(); 128 } 129 130 @SuppressWarnings("unused") 131 @CheckedProvides(value = RemoteProvider.class, scopeExceptions = false) 132 @NotExceptionScoping 133 @TestScope.Scoped 134 Foo notExceptionScopingThrowOrGet() throws RemoteException, BindException { 135 return mockRemoteProvider.get(); 136 } 137 138 }); 139 140 cxtorInjector = Guice.createInjector(new AbstractModule() { 141 @Override 142 protected void configure() { 143 ThrowingProviderBinder.create(binder()) 144 .bind(RemoteProvider.class, Foo.class) 145 .providing(MockFoo.class) 146 .in(testScope); 147 148 ThrowingProviderBinder.create(binder()) 149 .bind(RemoteProvider.class, Foo.class) 150 .annotatedWith(NotExceptionScoping.class) 151 .scopeExceptions(false) 152 .providing(MockFoo.class) 153 .in(testScope); 154 155 } 156 }); 157 } 158 159 public void testExceptionsThrown_Bind() throws Exception { 160 tExceptionsThrown(bindInjector); 161 } 162 163 public void testExceptionsThrown_Provides() throws Exception { 164 tExceptionsThrown(providesInjector); 165 } 166 167 public void testExceptionsThrown_Cxtor() throws Exception { 168 tExceptionsThrown(cxtorInjector); 169 } 170 171 private void tExceptionsThrown(Injector injector) throws Exception { 172 RemoteProvider<Foo> remoteProvider = 173 injector.getInstance(Key.get(remoteProviderOfFoo)); 174 175 mockRemoteProvider.throwOnNextGet(new BindException("kaboom!")); 176 MockFoo.nextToThrow = new BindException("kaboom!"); 177 try { 178 remoteProvider.get(); 179 fail(); 180 } catch (BindException expected) { 181 assertEquals("kaboom!", expected.getMessage()); 182 } 183 } 184 185 public void testValuesScoped_Bind() throws Exception { 186 tValuesScoped(bindInjector, null); 187 } 188 189 public void testValuesScoped_Provides() throws Exception { 190 tValuesScoped(providesInjector, null); 191 } 192 193 public void testValuesScopedWhenNotExceptionScoping_Bind() throws Exception { 194 tValuesScoped(bindInjector, NotExceptionScoping.class); 195 } 196 197 public void testValuesScopedWhenNotExceptionScoping_Provides() throws Exception { 198 tValuesScoped(providesInjector, NotExceptionScoping.class); 199 } 200 201 private void tValuesScoped(Injector injector, 202 Class<? extends Annotation> annotation) throws Exception { 203 Key<RemoteProvider<Foo>> key = annotation != null ? 204 Key.get(remoteProviderOfFoo, annotation) : 205 Key.get(remoteProviderOfFoo); 206 RemoteProvider<Foo> remoteProvider = injector.getInstance(key); 207 208 mockRemoteProvider.setNextToReturn(new SimpleFoo("A")); 209 assertEquals("A", remoteProvider.get().s()); 210 211 mockRemoteProvider.setNextToReturn(new SimpleFoo("B")); 212 assertEquals("A", remoteProvider.get().s()); 213 214 testScope.beginNewScope(); 215 assertEquals("B", remoteProvider.get().s()); 216 } 217 218 public void testValuesScoped_Cxtor() throws Exception { 219 RemoteProvider<Foo> remoteProvider = 220 cxtorInjector.getInstance(Key.get(remoteProviderOfFoo)); 221 222 Foo retrieved = remoteProvider.get(); 223 assertSame(retrieved, remoteProvider.get()); // same, not in new scope. 224 225 testScope.beginNewScope(); 226 assertNotSame(retrieved, remoteProvider.get()); // different, new scope. 227 } 228 229 public void testExceptionsScoped_Bind() throws Exception { 230 tExceptionsScoped(bindInjector); 231 } 232 233 public void testExceptionsScoped_Provides() throws Exception { 234 tExceptionsScoped(providesInjector); 235 } 236 237 public void testExceptionScopes_Cxtor() throws Exception { 238 tExceptionsScoped(cxtorInjector); 239 } 240 241 private void tExceptionsScoped(Injector injector) throws Exception { 242 RemoteProvider<Foo> remoteProvider = 243 injector.getInstance(Key.get(remoteProviderOfFoo)); 244 245 mockRemoteProvider.throwOnNextGet(new RemoteException("A")); 246 MockFoo.nextToThrow = new RemoteException("A"); 247 try { 248 remoteProvider.get(); 249 fail(); 250 } catch (RemoteException expected) { 251 assertEquals("A", expected.getMessage()); 252 } 253 254 mockRemoteProvider.throwOnNextGet(new RemoteException("B")); 255 MockFoo.nextToThrow = new RemoteException("B"); 256 try { 257 remoteProvider.get(); 258 fail(); 259 } catch (RemoteException expected) { 260 assertEquals("A", expected.getMessage()); 261 } 262 } 263 264 public void testExceptionsNotScopedWhenNotExceptionScoping_Bind() throws Exception { 265 tExceptionsNotScopedWhenNotExceptionScoping(bindInjector); 266 } 267 268 public void testExceptionsNotScopedWhenNotExceptionScoping_Provides() throws Exception { 269 tExceptionsNotScopedWhenNotExceptionScoping(providesInjector); 270 } 271 272 public void testExceptionNotScopedWhenNotExceptionScoping_Cxtor() throws Exception { 273 tExceptionsNotScopedWhenNotExceptionScoping(cxtorInjector); 274 } 275 276 private void tExceptionsNotScopedWhenNotExceptionScoping(Injector injector) throws Exception { 277 RemoteProvider<Foo> remoteProvider = 278 injector.getInstance(Key.get(remoteProviderOfFoo, NotExceptionScoping.class)); 279 280 mockRemoteProvider.throwOnNextGet(new RemoteException("A")); 281 MockFoo.nextToThrow = new RemoteException("A"); 282 try { 283 remoteProvider.get(); 284 fail(); 285 } catch (RemoteException expected) { 286 assertEquals("A", expected.getMessage()); 287 } 288 289 mockRemoteProvider.throwOnNextGet(new RemoteException("B")); 290 MockFoo.nextToThrow = new RemoteException("B"); 291 try { 292 remoteProvider.get(); 293 fail(); 294 } catch (RemoteException expected) { 295 assertEquals("B", expected.getMessage()); 296 } 297 } 298 299 public void testAnnotations_Bind() throws Exception { 300 final MockRemoteProvider<Foo> mockRemoteProviderA = new MockRemoteProvider<Foo>(); 301 final MockRemoteProvider<Foo> mockRemoteProviderB = new MockRemoteProvider<Foo>(); 302 bindInjector = Guice.createInjector(new AbstractModule() { 303 @Override 304 protected void configure() { 305 ThrowingProviderBinder.create(binder()) 306 .bind(RemoteProvider.class, Foo.class) 307 .annotatedWith(Names.named("a")) 308 .to(mockRemoteProviderA); 309 310 ThrowingProviderBinder.create(binder()) 311 .bind(RemoteProvider.class, Foo.class) 312 .to(mockRemoteProviderB); 313 } 314 }); 315 tAnnotations(bindInjector, mockRemoteProviderA, mockRemoteProviderB); 316 } 317 318 public void testAnnotations_Provides() throws Exception { 319 final MockRemoteProvider<Foo> mockRemoteProviderA = new MockRemoteProvider<Foo>(); 320 final MockRemoteProvider<Foo> mockRemoteProviderB = new MockRemoteProvider<Foo>(); 321 providesInjector = Guice.createInjector(new AbstractModule() { 322 @Override 323 protected void configure() { 324 install(ThrowingProviderBinder.forModule(this)); 325 } 326 327 @SuppressWarnings("unused") 328 @CheckedProvides(RemoteProvider.class) 329 @Named("a") 330 Foo throwOrGet() throws RemoteException, BindException { 331 return mockRemoteProviderA.get(); 332 } 333 334 @SuppressWarnings("unused") 335 @CheckedProvides(RemoteProvider.class) 336 Foo throwOrGet2() throws RemoteException, BindException { 337 return mockRemoteProviderB.get(); 338 } 339 }); 340 tAnnotations(providesInjector, mockRemoteProviderA, mockRemoteProviderB); 341 } 342 343 private void tAnnotations(Injector injector, MockRemoteProvider<Foo> mockA, 344 MockRemoteProvider<Foo> mockB) throws Exception { 345 mockA.setNextToReturn(new SimpleFoo("A")); 346 mockB.setNextToReturn(new SimpleFoo("B")); 347 assertEquals("A", 348 injector.getInstance(Key.get(remoteProviderOfFoo, Names.named("a"))).get().s()); 349 350 assertEquals("B", 351 injector.getInstance(Key.get(remoteProviderOfFoo)).get().s()); 352 } 353 354 public void testAnnotations_Cxtor() throws Exception { 355 cxtorInjector = Guice.createInjector(new AbstractModule() { 356 @Override 357 protected void configure() { 358 ThrowingProviderBinder.create(binder()) 359 .bind(RemoteProvider.class, Foo.class) 360 .annotatedWith(Names.named("a")) 361 .providing(MockFoo.class); 362 363 ThrowingProviderBinder.create(binder()) 364 .bind(RemoteProvider.class, Foo.class) 365 .providing(AnotherMockFoo.class); 366 } 367 }); 368 MockFoo.nextToReturn = "A"; 369 AnotherMockFoo.nextToReturn = "B"; 370 assertEquals("A", 371 cxtorInjector.getInstance(Key.get(remoteProviderOfFoo, Names.named("a"))).get().s()); 372 373 assertEquals("B", 374 cxtorInjector.getInstance(Key.get(remoteProviderOfFoo)).get().s()); 375 } 376 377 public void testUndeclaredExceptions_Bind() throws Exception { 378 tUndeclaredExceptions(bindInjector); 379 } 380 381 public void testUndeclaredExceptions_Provides() throws Exception { 382 tUndeclaredExceptions(providesInjector); 383 } 384 385 public void testUndeclaredExceptions_Cxtor() throws Exception { 386 tUndeclaredExceptions(cxtorInjector); 387 } 388 389 private void tUndeclaredExceptions(Injector injector) throws Exception { 390 RemoteProvider<Foo> remoteProvider = 391 injector.getInstance(Key.get(remoteProviderOfFoo)); 392 mockRemoteProvider.throwOnNextGet(new IndexOutOfBoundsException("A")); 393 MockFoo.nextToThrow = new IndexOutOfBoundsException("A"); 394 try { 395 remoteProvider.get(); 396 fail(); 397 } catch (RuntimeException e) { 398 assertEquals("A", e.getCause().getMessage()); 399 } 400 401 // undeclared exceptions shouldn't be scoped 402 mockRemoteProvider.throwOnNextGet(new IndexOutOfBoundsException("B")); 403 MockFoo.nextToThrow = new IndexOutOfBoundsException("B"); 404 try { 405 remoteProvider.get(); 406 fail(); 407 } catch (RuntimeException e) { 408 assertEquals("B", e.getCause().getMessage()); 409 } 410 } 411 412 public void testThrowingProviderSubclassing() throws Exception { 413 final SubMockRemoteProvider aProvider = new SubMockRemoteProvider(); 414 aProvider.setNextToReturn(new SimpleFoo("A")); 415 416 bindInjector = Guice.createInjector(new AbstractModule() { 417 @Override 418 protected void configure() { 419 ThrowingProviderBinder.create(binder()) 420 .bind(RemoteProvider.class, Foo.class) 421 .to(aProvider); 422 } 423 }); 424 425 assertEquals("A", 426 bindInjector.getInstance(Key.get(remoteProviderOfFoo)).get().s()); 427 } 428 429 static class SubMockRemoteProvider extends MockRemoteProvider<Foo> { } 430 431 public void testBindingToNonInterfaceType_Bind() throws Exception { 432 try { 433 Guice.createInjector(new AbstractModule() { 434 @Override 435 protected void configure() { 436 ThrowingProviderBinder.create(binder()) 437 .bind(MockRemoteProvider.class, Foo.class) 438 .to(mockRemoteProvider); 439 } 440 }); 441 fail(); 442 } catch (CreationException expected) { 443 assertEquals(MockRemoteProvider.class.getName() + " must be an interface", 444 Iterables.getOnlyElement(expected.getErrorMessages()).getMessage()); 445 } 446 } 447 448 public void testBindingToNonInterfaceType_Provides() throws Exception { 449 try { 450 Guice.createInjector(new AbstractModule() { 451 @Override 452 protected void configure() { 453 install(ThrowingProviderBinder.forModule(this)); 454 } 455 456 @SuppressWarnings("unused") 457 @CheckedProvides(MockRemoteProvider.class) 458 Foo foo() { 459 return null; 460 } 461 }); 462 fail(); 463 } catch (CreationException expected) { 464 assertEquals(MockRemoteProvider.class.getName() + " must be an interface", 465 Iterables.getOnlyElement(expected.getErrorMessages()).getMessage()); 466 } 467 } 468 469 public void testBindingToSubSubInterface_Bind() throws Exception { 470 try { 471 bindInjector = Guice.createInjector(new AbstractModule() { 472 @Override 473 protected void configure() { 474 ThrowingProviderBinder.create(binder()) 475 .bind(SubRemoteProvider.class, Foo.class); 476 } 477 }); 478 fail(); 479 } catch (CreationException expected) { 480 assertEquals(SubRemoteProvider.class.getName() + " must extend CheckedProvider (and only CheckedProvider)", 481 Iterables.getOnlyElement(expected.getErrorMessages()).getMessage()); 482 } 483 } 484 485 public void testBindingToSubSubInterface_Provides() throws Exception { 486 try { 487 Guice.createInjector(new AbstractModule() { 488 @Override 489 protected void configure() { 490 install(ThrowingProviderBinder.forModule(this)); 491 } 492 493 @SuppressWarnings("unused") 494 @CheckedProvides(SubRemoteProvider.class) 495 Foo foo() { 496 return null; 497 } 498 }); 499 fail(); 500 } catch (CreationException expected) { 501 assertEquals(SubRemoteProvider.class.getName() + " must extend CheckedProvider (and only CheckedProvider)", 502 Iterables.getOnlyElement(expected.getErrorMessages()).getMessage()); 503 } 504 } 505 506 interface SubRemoteProvider extends RemoteProvider<String> { } 507 508 public void testBindingToInterfaceWithExtraMethod_Bind() throws Exception { 509 try { 510 bindInjector = Guice.createInjector(new AbstractModule() { 511 @Override 512 protected void configure() { 513 ThrowingProviderBinder.create(binder()) 514 .bind(RemoteProviderWithExtraMethod.class, Foo.class); 515 } 516 }); 517 fail(); 518 } catch (CreationException expected) { 519 assertEquals(RemoteProviderWithExtraMethod.class.getName() + " may not declare any new methods, but declared " 520 + RemoteProviderWithExtraMethod.class.getDeclaredMethods()[0].toGenericString(), 521 Iterables.getOnlyElement(expected.getErrorMessages()).getMessage()); 522 } 523 } 524 525 public void testBindingToInterfaceWithExtraMethod_Provides() throws Exception { 526 try { 527 Guice.createInjector(new AbstractModule() { 528 @Override 529 protected void configure() { 530 install(ThrowingProviderBinder.forModule(this)); 531 } 532 533 @SuppressWarnings("unused") 534 @CheckedProvides(RemoteProviderWithExtraMethod.class) 535 Foo foo() { 536 return null; 537 } 538 }); 539 fail(); 540 } catch (CreationException expected) { 541 assertEquals(RemoteProviderWithExtraMethod.class.getName() + " may not declare any new methods, but declared " 542 + RemoteProviderWithExtraMethod.class.getDeclaredMethods()[0].toGenericString(), 543 Iterables.getOnlyElement(expected.getErrorMessages()).getMessage()); 544 } 545 } 546 547 public void testDependencies_Bind() { 548 bindInjector = Guice.createInjector(new AbstractModule() { 549 @Override 550 protected void configure() { 551 bind(String.class).toInstance("Foo"); 552 bind(Integer.class).toInstance(5); 553 bind(Double.class).toInstance(5d); 554 bind(Long.class).toInstance(5L); 555 ThrowingProviderBinder.create(binder()) 556 .bind(RemoteProvider.class, Foo.class) 557 .to(DependentRemoteProvider.class); 558 } 559 }); 560 561 HasDependencies hasDependencies = 562 (HasDependencies)bindInjector.getBinding(Key.get(remoteProviderOfFoo)); 563 hasDependencies = 564 (HasDependencies)bindInjector.getBinding( 565 Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey()); 566 // Make sure that that is dependent on DependentRemoteProvider. 567 assertEquals(Dependency.get(Key.get(DependentRemoteProvider.class)), 568 Iterables.getOnlyElement(hasDependencies.getDependencies())); 569 // And make sure DependentRemoteProvider has the proper dependencies. 570 hasDependencies = (HasDependencies)bindInjector.getBinding(DependentRemoteProvider.class); 571 Set<Key<?>> dependencyKeys = ImmutableSet.copyOf( 572 Iterables.transform(hasDependencies.getDependencies(), DEPENDENCY_TO_KEY)); 573 assertEquals(ImmutableSet.<Key<?>>of(Key.get(String.class), Key.get(Integer.class), 574 Key.get(Long.class), Key.get(Double.class)), dependencyKeys); 575 } 576 577 public void testDependencies_Provides() { 578 providesInjector = Guice.createInjector(new AbstractModule() { 579 @Override 580 protected void configure() { 581 bind(String.class).toInstance("Foo"); 582 bind(Integer.class).toInstance(5); 583 bind(Double.class).toInstance(5d); 584 bind(Long.class).toInstance(5L); 585 install(ThrowingProviderBinder.forModule(this)); 586 } 587 588 @SuppressWarnings("unused") 589 @CheckedProvides(RemoteProvider.class) 590 Foo foo(String s, Integer i, Double d, Long l) { 591 return null; 592 } 593 }); 594 595 HasDependencies hasDependencies = 596 (HasDependencies) providesInjector.getBinding(Key.get(remoteProviderOfFoo)); 597 // RemoteProvider<String> is dependent on the provider method.. 598 hasDependencies = (HasDependencies) providesInjector.getBinding( 599 Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey()); 600 // And the provider method has our real dependencies.. 601 hasDependencies = (HasDependencies)providesInjector.getBinding( 602 Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey()); 603 Set<Key<?>> dependencyKeys = ImmutableSet.copyOf( 604 Iterables.transform(hasDependencies.getDependencies(), DEPENDENCY_TO_KEY)); 605 assertEquals(ImmutableSet.<Key<?>>of(Key.get(String.class), Key.get(Integer.class), 606 Key.get(Long.class), Key.get(Double.class)), dependencyKeys); 607 } 608 609 public void testDependencies_Cxtor() { 610 cxtorInjector = Guice.createInjector(new AbstractModule() { 611 @Override 612 protected void configure() { 613 bind(String.class).toInstance("Foo"); 614 bind(Integer.class).toInstance(5); 615 bind(Double.class).toInstance(5d); 616 bind(Long.class).toInstance(5L); 617 ThrowingProviderBinder.create(binder()) 618 .bind(RemoteProvider.class, Foo.class) 619 .providing(DependentMockFoo.class); 620 } 621 }); 622 623 Key<?> key = Key.get(remoteProviderOfFoo); 624 625 // RemoteProvider<String> is dependent on Result. 626 HasDependencies hasDependencies = (HasDependencies) cxtorInjector.getBinding(key); 627 key = Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey(); 628 assertEquals(Result.class, key.getTypeLiteral().getRawType()); 629 630 // Result is dependent on the fake CheckedProvider impl 631 hasDependencies = (HasDependencies) cxtorInjector.getBinding(key); 632 key = Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey(); 633 assertTrue(CheckedProvider.class.isAssignableFrom(key.getTypeLiteral().getRawType())); 634 635 // And the CheckedProvider is dependent on DependentMockFoo... 636 hasDependencies = (HasDependencies) cxtorInjector.getBinding(key); 637 key = Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey(); 638 assertEquals(DependentMockFoo.class, key.getTypeLiteral().getRawType()); 639 640 // And DependentMockFoo is dependent on the goods. 641 hasDependencies = (HasDependencies) cxtorInjector.getBinding(key); 642 Set<Key<?>> dependencyKeys = ImmutableSet.copyOf( 643 Iterables.transform(hasDependencies.getDependencies(), DEPENDENCY_TO_KEY)); 644 assertEquals(ImmutableSet.<Key<?>>of(Key.get(String.class), Key.get(Integer.class), 645 Key.get(Long.class), Key.get(Double.class)), dependencyKeys); 646 } 647 648 interface RemoteProviderWithExtraMethod<T> extends CheckedProvider<T> { 649 T get(T defaultValue) throws RemoteException, BindException; 650 } 651 652 interface RemoteProvider<T> extends CheckedProvider<T> { 653 public T get() throws RemoteException, BindException; 654 } 655 656 static class DependentMockFoo implements Foo { 657 @Inject double foo; 658 659 @ThrowingInject public DependentMockFoo(String foo, int bar) { 660 } 661 662 @Inject void initialize(long foo) {} 663 664 @Override 665 public String s() { 666 return null; 667 } 668 } 669 670 static class DependentRemoteProvider<T> implements RemoteProvider<T> { 671 @Inject double foo; 672 673 @Inject public DependentRemoteProvider(String foo, int bar) { 674 } 675 676 @Inject void initialize(long foo) {} 677 678 public T get() { 679 return null; 680 } 681 } 682 683 interface Foo { 684 String s(); 685 } 686 687 static class SimpleFoo implements Foo { 688 private String s; 689 690 SimpleFoo(String s) { 691 this.s = s; 692 } 693 694 @Override 695 public String s() { 696 return s; 697 } 698 699 @Override 700 public String toString() { 701 return s; 702 } 703 } 704 705 static class MockFoo implements Foo { 706 static Exception nextToThrow; 707 static String nextToReturn; 708 709 @ThrowingInject 710 MockFoo() throws RemoteException, BindException { 711 if (nextToThrow instanceof RemoteException) { 712 throw (RemoteException) nextToThrow; 713 } else if (nextToThrow instanceof BindException) { 714 throw (BindException) nextToThrow; 715 } else if (nextToThrow instanceof RuntimeException) { 716 throw (RuntimeException) nextToThrow; 717 } else if (nextToThrow == null) { 718 // Do nothing, return this. 719 } else { 720 throw new AssertionError("nextToThrow must be a runtime or remote exception"); 721 } 722 } 723 724 @Override 725 public String s() { 726 return nextToReturn; 727 } 728 729 @Override 730 public String toString() { 731 return nextToReturn; 732 } 733 } 734 735 static class AnotherMockFoo implements Foo { 736 static Exception nextToThrow; 737 static String nextToReturn; 738 739 @ThrowingInject 740 AnotherMockFoo() throws RemoteException, BindException { 741 if (nextToThrow instanceof RemoteException) { 742 throw (RemoteException) nextToThrow; 743 } else if (nextToThrow instanceof BindException) { 744 throw (BindException) nextToThrow; 745 } else if (nextToThrow instanceof RuntimeException) { 746 throw (RuntimeException) nextToThrow; 747 } else if (nextToThrow == null) { 748 // Do nothing, return this. 749 } else { 750 throw new AssertionError("nextToThrow must be a runtime or remote exception"); 751 } 752 } 753 754 @Override 755 public String s() { 756 return nextToReturn; 757 } 758 759 @Override 760 public String toString() { 761 return nextToReturn; 762 } 763 } 764 765 static class MockRemoteProvider<T> implements RemoteProvider<T> { 766 Exception nextToThrow; 767 T nextToReturn; 768 769 public void throwOnNextGet(Exception nextToThrow) { 770 this.nextToThrow = nextToThrow; 771 } 772 773 public void setNextToReturn(T nextToReturn) { 774 this.nextToReturn = nextToReturn; 775 } 776 777 public T get() throws RemoteException, BindException { 778 if (nextToThrow instanceof RemoteException) { 779 throw (RemoteException) nextToThrow; 780 } else if (nextToThrow instanceof BindException) { 781 throw (BindException) nextToThrow; 782 } else if (nextToThrow instanceof RuntimeException) { 783 throw (RuntimeException) nextToThrow; 784 } else if (nextToThrow == null) { 785 return nextToReturn; 786 } else { 787 throw new AssertionError("nextToThrow must be a runtime or remote exception"); 788 } 789 } 790 } 791 792 public void testBindingToInterfaceWithBoundValueType_Bind() throws RemoteException { 793 bindInjector = Guice.createInjector(new AbstractModule() { 794 @Override 795 protected void configure() { 796 ThrowingProviderBinder.create(binder()) 797 .bind(StringRemoteProvider.class, String.class) 798 .to(new StringRemoteProvider() { 799 public String get() { 800 return "A"; 801 } 802 }); 803 } 804 }); 805 806 assertEquals("A", bindInjector.getInstance(StringRemoteProvider.class).get()); 807 } 808 809 public void testBindingToInterfaceWithBoundValueType_Provides() throws RemoteException { 810 providesInjector = Guice.createInjector(new AbstractModule() { 811 @Override 812 protected void configure() { 813 install(ThrowingProviderBinder.forModule(this)); 814 } 815 816 @SuppressWarnings("unused") 817 @CheckedProvides(StringRemoteProvider.class) 818 String foo() throws RemoteException { 819 return "A"; 820 } 821 }); 822 823 assertEquals("A", providesInjector.getInstance(StringRemoteProvider.class).get()); 824 } 825 826 interface StringRemoteProvider extends CheckedProvider<String> { 827 @Override String get() throws RemoteException; 828 } 829 830 @SuppressWarnings("deprecation") 831 public void testBindingToInterfaceWithGeneric_Bind() throws Exception { 832 bindInjector = Guice.createInjector(new AbstractModule() { 833 @Override 834 protected void configure() { 835 ThrowingProviderBinder.create(binder()) 836 .bind(RemoteProvider.class, new TypeLiteral<List<String>>() { }.getType()) 837 .to(new RemoteProvider<List<String>>() { 838 public List<String> get() { 839 return Arrays.asList("A", "B"); 840 } 841 }); 842 } 843 }); 844 845 Key<RemoteProvider<List<String>>> key 846 = Key.get(new TypeLiteral<RemoteProvider<List<String>>>() { }); 847 assertEquals(Arrays.asList("A", "B"), bindInjector.getInstance(key).get()); 848 } 849 850 public void testBindingToInterfaceWithGeneric_BindUsingTypeLiteral() throws Exception { 851 bindInjector = Guice.createInjector(new AbstractModule() { 852 @Override 853 protected void configure() { 854 ThrowingProviderBinder.create(binder()) 855 .bind(RemoteProvider.class, new TypeLiteral<List<String>>() {}) 856 .to(new RemoteProvider<List<String>>() { 857 public List<String> get() { 858 return Arrays.asList("A", "B"); 859 } 860 }); 861 } 862 }); 863 864 Key<RemoteProvider<List<String>>> key 865 = Key.get(new TypeLiteral<RemoteProvider<List<String>>>() { }); 866 assertEquals(Arrays.asList("A", "B"), bindInjector.getInstance(key).get()); 867 } 868 869 public void testBindingToInterfaceWithGeneric_Provides() throws Exception { 870 providesInjector = Guice.createInjector(new AbstractModule() { 871 @Override 872 protected void configure() { 873 install(ThrowingProviderBinder.forModule(this)); 874 } 875 876 @SuppressWarnings("unused") 877 @CheckedProvides(RemoteProvider.class) 878 List<String> foo() throws RemoteException { 879 return Arrays.asList("A", "B"); 880 } 881 }); 882 883 Key<RemoteProvider<List<String>>> key 884 = Key.get(new TypeLiteral<RemoteProvider<List<String>>>() { }); 885 assertEquals(Arrays.asList("A", "B"), providesInjector.getInstance(key).get()); 886 } 887 888 public void testBindingToInterfaceWithGeneric_Cxtor() throws Exception { 889 cxtorInjector = Guice.createInjector(new AbstractModule() { 890 @Override 891 protected void configure() { 892 ThrowingProviderBinder.create(binder()) 893 .bind(RemoteProvider.class, new TypeLiteral<List<String>>() {}) 894 .providing(new TypeLiteral<ThrowingArrayList<String>>() {}); 895 } 896 }); 897 898 Key<RemoteProvider<List<String>>> key 899 = Key.get(new TypeLiteral<RemoteProvider<List<String>>>() { }); 900 assertEquals(Arrays.asList(), cxtorInjector.getInstance(key).get()); 901 } 902 903 private static class ThrowingArrayList<T> extends ArrayList<T> { 904 @SuppressWarnings("unused") 905 @ThrowingInject 906 ThrowingArrayList() {} 907 } 908 909 public void testProviderMethodWithWrongException() { 910 try { 911 Guice.createInjector(new AbstractModule() { 912 @Override 913 protected void configure() { 914 install(ThrowingProviderBinder.forModule(this)); 915 } 916 917 @SuppressWarnings("unused") 918 @CheckedProvides(RemoteProvider.class) 919 String foo() throws InterruptedException { 920 return null; 921 } 922 }); 923 fail(); 924 } catch(CreationException ce) { 925 assertEquals(InterruptedException.class.getName() 926 + " is not compatible with the exceptions ([" 927 + RemoteException.class + ", " + BindException.class 928 + "]) declared in the CheckedProvider interface (" 929 + RemoteProvider.class.getName() 930 + ")", 931 Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); 932 } 933 } 934 935 public void testCxtorWithWrongException() { 936 try { 937 Guice.createInjector(new AbstractModule() { 938 @Override 939 protected void configure() { 940 ThrowingProviderBinder.create(binder()) 941 .bind(RemoteProvider.class, Foo.class) 942 .providing(WrongExceptionFoo.class); 943 } 944 }); 945 fail(); 946 } catch (CreationException ce) { 947 assertEquals(InterruptedException.class.getName() 948 + " is not compatible with the exceptions ([" 949 + RemoteException.class + ", " + BindException.class 950 + "]) declared in the CheckedProvider interface (" 951 + RemoteProvider.class.getName() 952 + ")", 953 Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); 954 } 955 } 956 957 static class WrongExceptionFoo implements Foo { 958 @SuppressWarnings("unused") 959 @ThrowingInject 960 public WrongExceptionFoo() throws InterruptedException { 961 } 962 963 @Override 964 public String s() { return null; } 965 } 966 967 public void testProviderMethodWithSubclassOfExceptionIsOk() throws Exception { 968 providesInjector = Guice.createInjector(new AbstractModule() { 969 @Override 970 protected void configure() { 971 install(ThrowingProviderBinder.forModule(this)); 972 } 973 974 @SuppressWarnings("unused") 975 @CheckedProvides(RemoteProvider.class) 976 Foo foo() throws AccessException { 977 throw new AccessException("boo!"); 978 } 979 }); 980 981 RemoteProvider<Foo> remoteProvider = 982 providesInjector.getInstance(Key.get(remoteProviderOfFoo)); 983 984 try { 985 remoteProvider.get(); 986 fail(); 987 } catch (RemoteException expected) { 988 assertTrue(expected instanceof AccessException); 989 assertEquals("boo!", expected.getMessage()); 990 } 991 } 992 993 public void testCxtorWithSubclassOfExceptionIsOk() throws Exception { 994 cxtorInjector = Guice.createInjector(new AbstractModule() { 995 @Override 996 protected void configure() { 997 ThrowingProviderBinder.create(binder()) 998 .bind(RemoteProvider.class, Foo.class) 999 .providing(SubclassExceptionFoo.class); 1000 } 1001 }); 1002 1003 RemoteProvider<Foo> remoteProvider = 1004 cxtorInjector.getInstance(Key.get(remoteProviderOfFoo)); 1005 1006 try { 1007 remoteProvider.get(); 1008 fail(); 1009 } catch (RemoteException expected) { 1010 assertTrue(expected instanceof AccessException); 1011 assertEquals("boo!", expected.getMessage()); 1012 } 1013 } 1014 1015 static class SubclassExceptionFoo implements Foo { 1016 @ThrowingInject 1017 public SubclassExceptionFoo() throws AccessException { 1018 throw new AccessException("boo!"); 1019 } 1020 1021 @Override 1022 public String s() { return null; } 1023 } 1024 1025 public void testProviderMethodWithSuperclassExceptionFails() { 1026 try { 1027 Guice.createInjector(new AbstractModule() { 1028 @Override 1029 protected void configure() { 1030 install(ThrowingProviderBinder.forModule(this)); 1031 } 1032 1033 @SuppressWarnings("unused") 1034 @CheckedProvides(RemoteProvider.class) 1035 Foo foo() throws IOException { 1036 return null; 1037 } 1038 }); 1039 fail(); 1040 } catch(CreationException ce) { 1041 assertEquals(IOException.class.getName() 1042 + " is not compatible with the exceptions ([" 1043 + RemoteException.class + ", " + BindException.class 1044 + "]) declared in the CheckedProvider interface (" 1045 + RemoteProvider.class.getName() 1046 + ")", 1047 Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); 1048 } 1049 } 1050 1051 public void testCxtorWithSuperclassExceptionFails() { 1052 try { 1053 Guice.createInjector(new AbstractModule() { 1054 @Override 1055 protected void configure() { 1056 ThrowingProviderBinder.create(binder()) 1057 .bind(RemoteProvider.class, Foo.class) 1058 .providing(SuperclassExceptionFoo.class); 1059 } 1060 }); 1061 fail(); 1062 } catch (CreationException ce) { 1063 assertEquals(IOException.class.getName() 1064 + " is not compatible with the exceptions ([" 1065 + RemoteException.class + ", " + BindException.class 1066 + "]) declared in the CheckedProvider interface (" 1067 + RemoteProvider.class.getName() 1068 + ")", 1069 Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); 1070 } 1071 } 1072 1073 static class SuperclassExceptionFoo implements Foo { 1074 @SuppressWarnings("unused") 1075 @ThrowingInject 1076 public SuperclassExceptionFoo() throws IOException { 1077 } 1078 1079 @Override 1080 public String s() { return null; } 1081 } 1082 1083 public void testProviderMethodWithRuntimeExceptionsIsOk() throws Exception { 1084 providesInjector = Guice.createInjector(new AbstractModule() { 1085 @Override 1086 protected void configure() { 1087 install(ThrowingProviderBinder.forModule(this)); 1088 } 1089 1090 @SuppressWarnings("unused") 1091 @CheckedProvides(RemoteProvider.class) 1092 Foo foo() throws RuntimeException { 1093 throw new RuntimeException("boo!"); 1094 } 1095 }); 1096 1097 RemoteProvider<Foo> remoteProvider = 1098 providesInjector.getInstance(Key.get(remoteProviderOfFoo)); 1099 1100 try { 1101 remoteProvider.get(); 1102 fail(); 1103 } catch (RuntimeException expected) { 1104 assertEquals("boo!", expected.getCause().getMessage()); 1105 } 1106 } 1107 1108 public void testCxtorWithRuntimeExceptionsIsOk() throws Exception { 1109 cxtorInjector = Guice.createInjector(new AbstractModule() { 1110 @Override 1111 protected void configure() { 1112 ThrowingProviderBinder.create(binder()) 1113 .bind(RemoteProvider.class, Foo.class) 1114 .providing(RuntimeExceptionFoo.class); 1115 } 1116 }); 1117 1118 RemoteProvider<Foo> remoteProvider = 1119 cxtorInjector.getInstance(Key.get(remoteProviderOfFoo)); 1120 1121 try { 1122 remoteProvider.get(); 1123 fail(); 1124 } catch (RuntimeException expected) { 1125 assertEquals("boo!", expected.getCause().getMessage()); 1126 } 1127 } 1128 1129 static class RuntimeExceptionFoo implements Foo { 1130 @ThrowingInject 1131 public RuntimeExceptionFoo() throws RuntimeException { 1132 throw new RuntimeException("boo!"); 1133 } 1134 1135 @Override 1136 public String s() { return null; } 1137 } 1138 1139 private static class SubBindException extends BindException {} 1140 1141 public void testProviderMethodWithManyExceptions() { 1142 try { 1143 Guice.createInjector(new AbstractModule() { 1144 @Override 1145 protected void configure() { 1146 install(ThrowingProviderBinder.forModule(this)); 1147 } 1148 1149 @SuppressWarnings("unused") 1150 @CheckedProvides(RemoteProvider.class) 1151 String foo() throws InterruptedException, RuntimeException, RemoteException, 1152 AccessException, TooManyListenersException, 1153 BindException, SubBindException { 1154 return null; 1155 } 1156 }); 1157 fail(); 1158 } catch(CreationException ce) { 1159 // The only two that should fail are Interrupted & TooManyListeners.. the rest are OK. 1160 List<Message> errors = ImmutableList.copyOf(ce.getErrorMessages()); 1161 assertEquals(InterruptedException.class.getName() 1162 + " is not compatible with the exceptions ([" 1163 + RemoteException.class + ", " + BindException.class 1164 + "]) declared in the CheckedProvider interface (" 1165 + RemoteProvider.class.getName() 1166 + ")", 1167 errors.get(0).getMessage()); 1168 assertEquals(TooManyListenersException.class.getName() 1169 + " is not compatible with the exceptions ([" 1170 + RemoteException.class + ", " + BindException.class 1171 + "]) declared in the CheckedProvider interface (" 1172 + RemoteProvider.class.getName() 1173 + ")", 1174 errors.get(1).getMessage()); 1175 assertEquals(2, errors.size()); 1176 } 1177 } 1178 1179 public void testCxtorWithManyExceptions() { 1180 try { 1181 Guice.createInjector(new AbstractModule() { 1182 @Override 1183 protected void configure() { 1184 ThrowingProviderBinder.create(binder()) 1185 .bind(RemoteProvider.class, Foo.class) 1186 .providing(ManyExceptionFoo.class); 1187 } 1188 }); 1189 fail(); 1190 } catch (CreationException ce) { 1191 // The only two that should fail are Interrupted & TooManyListeners.. the rest are OK. 1192 List<Message> errors = ImmutableList.copyOf(ce.getErrorMessages()); 1193 assertEquals(InterruptedException.class.getName() 1194 + " is not compatible with the exceptions ([" 1195 + RemoteException.class + ", " + BindException.class 1196 + "]) declared in the CheckedProvider interface (" 1197 + RemoteProvider.class.getName() 1198 + ")", 1199 errors.get(0).getMessage()); 1200 assertEquals(TooManyListenersException.class.getName() 1201 + " is not compatible with the exceptions ([" 1202 + RemoteException.class + ", " + BindException.class 1203 + "]) declared in the CheckedProvider interface (" 1204 + RemoteProvider.class.getName() 1205 + ")", 1206 errors.get(1).getMessage()); 1207 assertEquals(2, errors.size()); 1208 } 1209 } 1210 1211 static class ManyExceptionFoo implements Foo { 1212 @SuppressWarnings("unused") 1213 @ThrowingInject 1214 public ManyExceptionFoo() 1215 throws InterruptedException, 1216 RuntimeException, 1217 RemoteException, 1218 AccessException, 1219 TooManyListenersException, 1220 BindException, 1221 SubBindException { 1222 } 1223 1224 @Override 1225 public String s() { return null; } 1226 } 1227 1228 public void testMoreTypeParameters() { 1229 try { 1230 Guice.createInjector(new AbstractModule() { 1231 @Override 1232 protected void configure() { 1233 install(ThrowingProviderBinder.forModule(this)); 1234 } 1235 1236 @SuppressWarnings("unused") 1237 @CheckedProvides(TooManyTypeParameters.class) 1238 String foo() { 1239 return null; 1240 } 1241 }); 1242 fail(); 1243 } catch(CreationException ce) { 1244 assertEquals(TooManyTypeParameters.class.getName() + " has more than one generic type parameter: [T, P]", 1245 Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); 1246 } 1247 } 1248 1249 public void testWrongThrowingProviderType() { 1250 try { 1251 Guice.createInjector(new AbstractModule() { 1252 @Override 1253 protected void configure() { 1254 install(ThrowingProviderBinder.forModule(this)); 1255 } 1256 1257 @SuppressWarnings("unused") 1258 @CheckedProvides(WrongThrowingProviderType.class) 1259 String foo() { 1260 return null; 1261 } 1262 }); 1263 fail(); 1264 } catch(CreationException ce) { 1265 assertEquals(WrongThrowingProviderType.class.getName() 1266 + " does not properly extend CheckedProvider, the first type parameter of CheckedProvider " 1267 + "(java.lang.String) is not a generic type", 1268 Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); 1269 } 1270 } 1271 1272 public void testOneMethodThatIsntGet() { 1273 try { 1274 Guice.createInjector(new AbstractModule() { 1275 @Override 1276 protected void configure() { 1277 install(ThrowingProviderBinder.forModule(this)); 1278 } 1279 1280 @SuppressWarnings("unused") 1281 @CheckedProvides(OneNoneGetMethod.class) 1282 String foo() { 1283 return null; 1284 } 1285 }); 1286 fail(); 1287 } catch(CreationException ce) { 1288 assertEquals(OneNoneGetMethod.class.getName() 1289 + " may not declare any new methods, but declared " + Classes.toString(OneNoneGetMethod.class.getDeclaredMethods()[0]), 1290 Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); 1291 } 1292 } 1293 1294 public void testManyMethods() { 1295 try { 1296 Guice.createInjector(new AbstractModule() { 1297 @Override 1298 protected void configure() { 1299 install(ThrowingProviderBinder.forModule(this)); 1300 } 1301 1302 @SuppressWarnings("unused") 1303 @CheckedProvides(ManyMethods.class) 1304 String foo() { 1305 return null; 1306 } 1307 }); 1308 fail(); 1309 } catch(CreationException ce) { 1310 assertEquals(ManyMethods.class.getName() 1311 + " may not declare any new methods, but declared " + Arrays.asList(ManyMethods.class.getDeclaredMethods()), 1312 Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); 1313 } 1314 } 1315 1316 public void testIncorrectPredefinedType_Bind() { 1317 try { 1318 Guice.createInjector(new AbstractModule() { 1319 @Override 1320 protected void configure() { 1321 ThrowingProviderBinder.create(binder()) 1322 .bind(StringRemoteProvider.class, Integer.class) 1323 .to(new StringRemoteProvider() { 1324 public String get() { 1325 return "A"; 1326 } 1327 }); 1328 } 1329 }); 1330 fail(); 1331 } catch(CreationException ce) { 1332 assertEquals(StringRemoteProvider.class.getName() 1333 + " expects the value type to be java.lang.String, but it was java.lang.Integer", 1334 Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); 1335 } 1336 } 1337 1338 public void testIncorrectPredefinedType_Provides() { 1339 try { 1340 Guice.createInjector(new AbstractModule() { 1341 @Override 1342 protected void configure() { 1343 install(ThrowingProviderBinder.forModule(this)); 1344 } 1345 1346 @SuppressWarnings("unused") 1347 @CheckedProvides(StringRemoteProvider.class) 1348 Integer foo() { 1349 return null; 1350 } 1351 }); 1352 fail(); 1353 } catch(CreationException ce) { 1354 assertEquals(StringRemoteProvider.class.getName() 1355 + " expects the value type to be java.lang.String, but it was java.lang.Integer", 1356 Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); 1357 } 1358 } 1359 1360 private static interface TooManyTypeParameters<T, P> extends CheckedProvider<T> { 1361 } 1362 1363 private static interface WrongThrowingProviderType<T> extends CheckedProvider<String> { 1364 } 1365 1366 private static interface OneNoneGetMethod<T> extends CheckedProvider<T> { 1367 T bar(); 1368 } 1369 1370 private static interface ManyMethods<T> extends CheckedProvider<T> { 1371 T bar(); 1372 String baz(); 1373 } 1374 1375 public void testResultSerializes() throws Exception { 1376 Result result = Result.forValue("foo"); 1377 result = Asserts.reserialize(result); 1378 assertEquals("foo", result.getOrThrow()); 1379 } 1380 1381 public void testResultExceptionSerializes() throws Exception { 1382 Result result = Result.forException(new Exception("boo")); 1383 result = Asserts.reserialize(result); 1384 try { 1385 result.getOrThrow(); 1386 fail(); 1387 } catch(Exception ex) { 1388 assertEquals("boo", ex.getMessage()); 1389 } 1390 } 1391 1392 public void testEarlyBindingError() { 1393 try { 1394 Guice.createInjector(new AbstractModule() { 1395 @Override 1396 protected void configure() { 1397 ThrowingProviderBinder.create(binder()) 1398 .bind(StringRemoteProvider.class, String.class) 1399 .to(FailingProvider.class); 1400 } 1401 }); 1402 fail(); 1403 } catch(CreationException ce) { 1404 assertEquals("Could not find a suitable constructor in " + FailingProvider.class.getName() 1405 + ". Classes must have either one (and only one) constructor annotated with @Inject" 1406 + " or a zero-argument constructor that is not private.", 1407 Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); 1408 } 1409 } 1410 1411 private static class FailingProvider implements StringRemoteProvider { 1412 // no @Inject. 1413 @SuppressWarnings("unused") 1414 FailingProvider(Integer foo) {} 1415 1416 public String get() { 1417 return null; 1418 } 1419 } 1420 1421 public void testNoInjectionPointForUsing() { 1422 try { 1423 Guice.createInjector(new AbstractModule() { 1424 @Override 1425 protected void configure() { 1426 ThrowingProviderBinder.create(binder()) 1427 .bind(RemoteProvider.class, Foo.class) 1428 .providing(InvalidFoo.class); 1429 } 1430 }); 1431 fail(); 1432 } catch (CreationException ce) { 1433 assertEquals("Could not find a suitable constructor in " + InvalidFoo.class.getName() 1434 + ". Classes must have either one (and only one) constructor annotated with " 1435 + "@ThrowingInject.", 1436 Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); 1437 } 1438 } 1439 1440 static class InvalidFoo implements Foo { 1441 public InvalidFoo(String dep) { 1442 } 1443 1444 @Override public String s() { return null; } 1445 } 1446 1447 public void testNoThrowingInject() { 1448 try { 1449 Guice.createInjector(new AbstractModule() { 1450 @Override 1451 protected void configure() { 1452 ThrowingProviderBinder.create(binder()) 1453 .bind(RemoteProvider.class, Foo.class) 1454 .providing(NormalInjectableFoo.class); 1455 } 1456 }); 1457 fail(); 1458 } catch (CreationException ce) { 1459 assertEquals("Could not find a suitable constructor in " + NormalInjectableFoo.class.getName() 1460 + ". Classes must have either one (and only one) constructor annotated with " 1461 + "@ThrowingInject.", 1462 Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); 1463 } 1464 } 1465 1466 static class NormalInjectableFoo implements Foo { 1467 @Inject 1468 public NormalInjectableFoo() { 1469 } 1470 1471 @Override public String s() { return null; } 1472 } 1473 1474 public void testProvisionExceptionOnDependenciesOfCxtor() throws Exception { 1475 Injector injector = Guice.createInjector(new AbstractModule() { 1476 @Override 1477 protected void configure() { 1478 ThrowingProviderBinder.create(binder()) 1479 .bind(RemoteProvider.class, Foo.class) 1480 .providing(ProvisionExceptionFoo.class); 1481 bindScope(BadScope.class, new Scope() { 1482 @Override 1483 public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) { 1484 return new Provider<T>() { 1485 @Override 1486 public T get() { 1487 throw new OutOfScopeException("failure"); 1488 } 1489 }; 1490 } 1491 }); 1492 } 1493 }); 1494 1495 try { 1496 injector.getInstance(Key.get(remoteProviderOfFoo)).get(); 1497 fail(); 1498 } catch(ProvisionException pe) { 1499 assertEquals(2, pe.getErrorMessages().size()); 1500 List<Message> messages = Lists.newArrayList(pe.getErrorMessages()); 1501 assertEquals("Error in custom provider, com.google.inject.OutOfScopeException: failure", 1502 messages.get(0).getMessage()); 1503 assertEquals("Error in custom provider, com.google.inject.OutOfScopeException: failure", 1504 messages.get(1).getMessage()); 1505 } 1506 } 1507 1508 @ScopeAnnotation 1509 @Target(ElementType.TYPE) 1510 @Retention(RetentionPolicy.RUNTIME) 1511 private @interface BadScope { } 1512 1513 @BadScope private static class Unscoped1 {} 1514 @BadScope private static class Unscoped2 {} 1515 1516 static class ProvisionExceptionFoo implements Foo { 1517 @ThrowingInject 1518 public ProvisionExceptionFoo(Unscoped1 a, Unscoped2 b) { 1519 } 1520 1521 @Override public String s() { return null; } 1522 } 1523 1524 public void testUsingDoesntClashWithBindingsOfSameType() throws Exception { 1525 cxtorInjector = Guice.createInjector(new AbstractModule() { 1526 @Override 1527 protected void configure() { 1528 ThrowingProviderBinder.create(binder()) 1529 .bind(RemoteProvider.class, Foo.class) 1530 .providing(MockFoo.class); 1531 bind(Foo.class).to(MockFoo.class); 1532 bind(MockFoo.class).to(SubMockFoo.class); 1533 } 1534 }); 1535 1536 RemoteProvider<Foo> remoteProvider = 1537 cxtorInjector.getInstance(Key.get(remoteProviderOfFoo)); 1538 Foo providerGot = remoteProvider.get(); 1539 Foo fooGot = cxtorInjector.getInstance(Foo.class); 1540 Foo mockGot = cxtorInjector.getInstance(MockFoo.class); 1541 1542 assertEquals(MockFoo.class, providerGot.getClass()); 1543 assertEquals(SubMockFoo.class, fooGot.getClass()); 1544 assertEquals(SubMockFoo.class, mockGot.getClass()); 1545 } 1546 1547 static class SubMockFoo extends MockFoo { 1548 public SubMockFoo() throws RemoteException, BindException { 1549 } 1550 1551 } 1552} 1553