crazyboblee | f33d23e | 2007-02-12 04:17:48 +0000 | [diff] [blame] | 1 | /** |
| 2 | * Copyright (C) 2006 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 | |
| 17 | package com.google.inject; |
| 18 | |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 19 | import static com.google.inject.Asserts.asModuleChain; |
limpbizkit | 185d2a2 | 2008-06-16 07:22:47 +0000 | [diff] [blame] | 20 | import static com.google.inject.Asserts.assertContains; |
Christian Edward Gruber | ba5acdf | 2013-10-05 14:05:39 -0700 | [diff] [blame^] | 21 | import static com.google.inject.Asserts.getDeclaringSourcePart; |
sberlin | b7a02b0 | 2011-07-08 00:34:16 +0000 | [diff] [blame] | 22 | import static com.google.inject.name.Names.named; |
| 23 | import static java.lang.annotation.RetentionPolicy.RUNTIME; |
| 24 | |
sberlin | d9c913a | 2011-06-26 21:02:54 +0000 | [diff] [blame] | 25 | import com.google.common.collect.ImmutableMap; |
| 26 | import com.google.common.collect.Maps; |
limpbizkit | 52aad3b | 2009-06-23 03:16:48 +0000 | [diff] [blame] | 27 | import com.google.inject.name.Named; |
limpbizkit | 52aad3b | 2009-06-23 03:16:48 +0000 | [diff] [blame] | 28 | import com.google.inject.spi.Element; |
| 29 | import com.google.inject.spi.Elements; |
sberlin | 09ab5f9 | 2010-10-25 00:41:10 +0000 | [diff] [blame] | 30 | import com.google.inject.spi.PrivateElements; |
limpbizkit | 52aad3b | 2009-06-23 03:16:48 +0000 | [diff] [blame] | 31 | import com.google.inject.util.Providers; |
sberlin | b7a02b0 | 2011-07-08 00:34:16 +0000 | [diff] [blame] | 32 | |
| 33 | import junit.framework.TestCase; |
| 34 | |
limpbizkit | f530b25 | 2008-05-27 23:03:42 +0000 | [diff] [blame] | 35 | import java.io.IOException; |
limpbizkit | 9266b99 | 2008-06-04 01:57:08 +0000 | [diff] [blame] | 36 | import java.lang.annotation.ElementType; |
| 37 | import java.lang.annotation.Retention; |
limpbizkit | 05a6c5e | 2008-06-05 00:29:11 +0000 | [diff] [blame] | 38 | import java.lang.annotation.Target; |
| 39 | import java.util.ArrayList; |
limpbizkit | b206d20 | 2008-12-02 06:16:53 +0000 | [diff] [blame] | 40 | import java.util.Arrays; |
| 41 | import java.util.Iterator; |
limpbizkit | 9266b99 | 2008-06-04 01:57:08 +0000 | [diff] [blame] | 42 | import java.util.List; |
limpbizkit | 05a6c5e | 2008-06-05 00:29:11 +0000 | [diff] [blame] | 43 | import java.util.Map; |
limpbizkit | f530b25 | 2008-05-27 23:03:42 +0000 | [diff] [blame] | 44 | |
crazyboblee | f33d23e | 2007-02-12 04:17:48 +0000 | [diff] [blame] | 45 | /** |
| 46 | * @author crazybob@google.com (Bob Lee) |
| 47 | */ |
| 48 | public class ScopesTest extends TestCase { |
| 49 | |
limpbizkit | e81cf1b | 2008-06-02 16:41:22 +0000 | [diff] [blame] | 50 | private final AbstractModule singletonsModule = new AbstractModule() { |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 51 | @Override protected void configure() { |
limpbizkit | e81cf1b | 2008-06-02 16:41:22 +0000 | [diff] [blame] | 52 | bind(BoundAsSingleton.class).in(Scopes.SINGLETON); |
| 53 | bind(AnnotatedSingleton.class); |
| 54 | bind(EagerSingleton.class).asEagerSingleton(); |
| 55 | bind(LinkedSingleton.class).to(RealLinkedSingleton.class); |
| 56 | bind(DependsOnJustInTimeSingleton.class); |
| 57 | bind(NotASingleton.class); |
limpbizkit | 27fc50d | 2008-08-08 07:43:39 +0000 | [diff] [blame] | 58 | bind(ImplementedBySingleton.class).in(Scopes.SINGLETON); |
| 59 | bind(ProvidedBySingleton.class).in(Scopes.SINGLETON); |
limpbizkit | e81cf1b | 2008-06-02 16:41:22 +0000 | [diff] [blame] | 60 | } |
| 61 | }; |
| 62 | |
limpbizkit | 349f6f2 | 2008-06-02 06:05:54 +0000 | [diff] [blame] | 63 | @Override protected void setUp() throws Exception { |
| 64 | AnnotatedSingleton.nextInstanceId = 0; |
| 65 | BoundAsSingleton.nextInstanceId = 0; |
| 66 | EagerSingleton.nextInstanceId = 0; |
| 67 | RealLinkedSingleton.nextInstanceId = 0; |
limpbizkit | e81cf1b | 2008-06-02 16:41:22 +0000 | [diff] [blame] | 68 | JustInTimeSingleton.nextInstanceId = 0; |
| 69 | NotASingleton.nextInstanceId = 0; |
limpbizkit | 27fc50d | 2008-08-08 07:43:39 +0000 | [diff] [blame] | 70 | Implementation.nextInstanceId = 0; |
| 71 | ProvidedBySingleton.nextInstanceId = 0; |
limpbizkit | 1f1fca7 | 2009-07-23 17:46:52 +0000 | [diff] [blame] | 72 | ThrowingSingleton.nextInstanceId = 0; |
crazyboblee | f33d23e | 2007-02-12 04:17:48 +0000 | [diff] [blame] | 73 | } |
| 74 | |
limpbizkit | 349f6f2 | 2008-06-02 06:05:54 +0000 | [diff] [blame] | 75 | public void testSingletons() { |
limpbizkit | e81cf1b | 2008-06-02 16:41:22 +0000 | [diff] [blame] | 76 | Injector injector = Guice.createInjector(singletonsModule); |
limpbizkit | f530b25 | 2008-05-27 23:03:42 +0000 | [diff] [blame] | 77 | |
| 78 | assertSame( |
| 79 | injector.getInstance(BoundAsSingleton.class), |
| 80 | injector.getInstance(BoundAsSingleton.class)); |
limpbizkit | 349f6f2 | 2008-06-02 06:05:54 +0000 | [diff] [blame] | 81 | |
| 82 | assertSame( |
| 83 | injector.getInstance(AnnotatedSingleton.class), |
| 84 | injector.getInstance(AnnotatedSingleton.class)); |
| 85 | |
| 86 | assertSame( |
| 87 | injector.getInstance(EagerSingleton.class), |
| 88 | injector.getInstance(EagerSingleton.class)); |
| 89 | |
| 90 | assertSame( |
| 91 | injector.getInstance(LinkedSingleton.class), |
| 92 | injector.getInstance(LinkedSingleton.class)); |
limpbizkit | e81cf1b | 2008-06-02 16:41:22 +0000 | [diff] [blame] | 93 | |
limpbizkit | e81cf1b | 2008-06-02 16:41:22 +0000 | [diff] [blame] | 94 | assertSame( |
| 95 | injector.getInstance(JustInTimeSingleton.class), |
| 96 | injector.getInstance(JustInTimeSingleton.class)); |
| 97 | |
| 98 | assertNotSame( |
| 99 | injector.getInstance(NotASingleton.class), |
| 100 | injector.getInstance(NotASingleton.class)); |
limpbizkit | 27fc50d | 2008-08-08 07:43:39 +0000 | [diff] [blame] | 101 | |
| 102 | assertSame( |
| 103 | injector.getInstance(ImplementedBySingleton.class), |
| 104 | injector.getInstance(ImplementedBySingleton.class)); |
| 105 | |
| 106 | assertSame( |
| 107 | injector.getInstance(ProvidedBySingleton.class), |
| 108 | injector.getInstance(ProvidedBySingleton.class)); |
limpbizkit | f530b25 | 2008-05-27 23:03:42 +0000 | [diff] [blame] | 109 | } |
| 110 | |
| 111 | public void testJustInTimeAnnotatedSingleton() { |
| 112 | Injector injector = Guice.createInjector(); |
| 113 | |
| 114 | assertSame( |
| 115 | injector.getInstance(AnnotatedSingleton.class), |
| 116 | injector.getInstance(AnnotatedSingleton.class)); |
| 117 | } |
| 118 | |
| 119 | public void testSingletonIsPerInjector() { |
| 120 | assertNotSame( |
| 121 | Guice.createInjector().getInstance(AnnotatedSingleton.class), |
| 122 | Guice.createInjector().getInstance(AnnotatedSingleton.class)); |
| 123 | } |
| 124 | |
| 125 | public void testOverriddingAnnotation() { |
| 126 | Injector injector = Guice.createInjector(new AbstractModule() { |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 127 | @Override protected void configure() { |
limpbizkit | f530b25 | 2008-05-27 23:03:42 +0000 | [diff] [blame] | 128 | bind(AnnotatedSingleton.class).in(Scopes.NO_SCOPE); |
limpbizkit | 3d58d6b | 2008-03-08 16:11:47 +0000 | [diff] [blame] | 129 | } |
| 130 | }); |
| 131 | |
kevinb9n | b605482 | 2007-03-19 03:17:47 +0000 | [diff] [blame] | 132 | assertNotSame( |
limpbizkit | f530b25 | 2008-05-27 23:03:42 +0000 | [diff] [blame] | 133 | injector.getInstance(AnnotatedSingleton.class), |
| 134 | injector.getInstance(AnnotatedSingleton.class)); |
| 135 | } |
| 136 | |
limpbizkit | 96d2164 | 2008-07-18 23:49:43 +0000 | [diff] [blame] | 137 | public void testScopingAnnotationsOnAbstractTypeViaBind() { |
limpbizkit | 185d2a2 | 2008-06-16 07:22:47 +0000 | [diff] [blame] | 138 | try { |
| 139 | Guice.createInjector(new AbstractModule() { |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 140 | @Override protected void configure() { |
limpbizkit | 185d2a2 | 2008-06-16 07:22:47 +0000 | [diff] [blame] | 141 | bind(A.class).to(AImpl.class); |
| 142 | } |
| 143 | }); |
| 144 | fail(); |
| 145 | } catch (CreationException expected) { |
| 146 | assertContains(expected.getMessage(), |
limpbizkit | 185d2a2 | 2008-06-16 07:22:47 +0000 | [diff] [blame] | 147 | A.class.getName() + " is annotated with " + Singleton.class.getName(), |
limpbizkit | a6e0e78 | 2008-09-03 06:19:56 +0000 | [diff] [blame] | 148 | "but scope annotations are not supported for abstract types.", |
| 149 | "at " + A.class.getName() + ".class(ScopesTest.java:"); |
limpbizkit | 185d2a2 | 2008-06-16 07:22:47 +0000 | [diff] [blame] | 150 | } |
| 151 | } |
| 152 | |
| 153 | @Singleton |
| 154 | interface A {} |
| 155 | static class AImpl implements A {} |
limpbizkit | 96d2164 | 2008-07-18 23:49:43 +0000 | [diff] [blame] | 156 | |
| 157 | public void testScopingAnnotationsOnAbstractTypeViaImplementedBy() { |
| 158 | try { |
| 159 | Guice.createInjector().getInstance(D.class); |
| 160 | fail(); |
limpbizkit | 490833f | 2008-11-02 00:12:39 +0000 | [diff] [blame] | 161 | } catch (ConfigurationException expected) { |
limpbizkit | 96d2164 | 2008-07-18 23:49:43 +0000 | [diff] [blame] | 162 | assertContains(expected.getMessage(), |
limpbizkit | 96d2164 | 2008-07-18 23:49:43 +0000 | [diff] [blame] | 163 | D.class.getName() + " is annotated with " + Singleton.class.getName(), |
limpbizkit | a6e0e78 | 2008-09-03 06:19:56 +0000 | [diff] [blame] | 164 | "but scope annotations are not supported for abstract types.", |
| 165 | "at " + D.class.getName() + ".class(ScopesTest.java:"); |
limpbizkit | 96d2164 | 2008-07-18 23:49:43 +0000 | [diff] [blame] | 166 | } |
| 167 | } |
| 168 | |
| 169 | @Singleton @ImplementedBy(DImpl.class) |
| 170 | interface D {} |
| 171 | static class DImpl implements D {} |
| 172 | |
| 173 | public void testScopingAnnotationsOnAbstractTypeViaProvidedBy() { |
| 174 | try { |
| 175 | Guice.createInjector().getInstance(E.class); |
| 176 | fail(); |
limpbizkit | 490833f | 2008-11-02 00:12:39 +0000 | [diff] [blame] | 177 | } catch (ConfigurationException expected) { |
limpbizkit | 96d2164 | 2008-07-18 23:49:43 +0000 | [diff] [blame] | 178 | assertContains(expected.getMessage(), |
limpbizkit | 96d2164 | 2008-07-18 23:49:43 +0000 | [diff] [blame] | 179 | E.class.getName() + " is annotated with " + Singleton.class.getName(), |
limpbizkit | a6e0e78 | 2008-09-03 06:19:56 +0000 | [diff] [blame] | 180 | "but scope annotations are not supported for abstract types.", |
| 181 | "at " + E.class.getName() + ".class(ScopesTest.java:"); |
limpbizkit | 96d2164 | 2008-07-18 23:49:43 +0000 | [diff] [blame] | 182 | } |
| 183 | } |
| 184 | |
| 185 | @Singleton @ProvidedBy(EProvider.class) |
| 186 | interface E {} |
| 187 | static class EProvider implements Provider<E> { |
| 188 | public E get() { |
| 189 | return null; |
| 190 | } |
| 191 | } |
| 192 | |
limpbizkit | 185d2a2 | 2008-06-16 07:22:47 +0000 | [diff] [blame] | 193 | public void testScopeUsedButNotBound() { |
| 194 | try { |
| 195 | Guice.createInjector(new AbstractModule() { |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 196 | @Override protected void configure() { |
limpbizkit | 185d2a2 | 2008-06-16 07:22:47 +0000 | [diff] [blame] | 197 | bind(B.class).in(CustomScoped.class); |
| 198 | bind(C.class); |
| 199 | } |
| 200 | }); |
| 201 | fail(); |
| 202 | } catch (CreationException expected) { |
| 203 | assertContains(expected.getMessage(), |
limpbizkit | a6e0e78 | 2008-09-03 06:19:56 +0000 | [diff] [blame] | 204 | "1) No scope is bound to " + CustomScoped.class.getName(), |
Christian Edward Gruber | ba5acdf | 2013-10-05 14:05:39 -0700 | [diff] [blame^] | 205 | "at " + getClass().getName(), getDeclaringSourcePart(getClass()), |
limpbizkit | a6e0e78 | 2008-09-03 06:19:56 +0000 | [diff] [blame] | 206 | "2) No scope is bound to " + CustomScoped.class.getName(), |
| 207 | "at " + C.class.getName() + ".class"); |
limpbizkit | 185d2a2 | 2008-06-16 07:22:47 +0000 | [diff] [blame] | 208 | } |
| 209 | } |
| 210 | |
| 211 | static class B {} |
| 212 | |
| 213 | @CustomScoped |
| 214 | static class C {} |
| 215 | |
limpbizkit | 349f6f2 | 2008-06-02 06:05:54 +0000 | [diff] [blame] | 216 | public void testSingletonsInProductionStage() { |
limpbizkit | e81cf1b | 2008-06-02 16:41:22 +0000 | [diff] [blame] | 217 | Guice.createInjector(Stage.PRODUCTION, singletonsModule); |
limpbizkit | f530b25 | 2008-05-27 23:03:42 +0000 | [diff] [blame] | 218 | |
limpbizkit | 349f6f2 | 2008-06-02 06:05:54 +0000 | [diff] [blame] | 219 | assertEquals(1, AnnotatedSingleton.nextInstanceId); |
| 220 | assertEquals(1, BoundAsSingleton.nextInstanceId); |
| 221 | assertEquals(1, EagerSingleton.nextInstanceId); |
| 222 | assertEquals(1, RealLinkedSingleton.nextInstanceId); |
limpbizkit | e81cf1b | 2008-06-02 16:41:22 +0000 | [diff] [blame] | 223 | assertEquals(1, JustInTimeSingleton.nextInstanceId); |
| 224 | assertEquals(0, NotASingleton.nextInstanceId); |
limpbizkit | f530b25 | 2008-05-27 23:03:42 +0000 | [diff] [blame] | 225 | } |
| 226 | |
limpbizkit | 349f6f2 | 2008-06-02 06:05:54 +0000 | [diff] [blame] | 227 | public void testSingletonsInDevelopmentStage() { |
limpbizkit | e81cf1b | 2008-06-02 16:41:22 +0000 | [diff] [blame] | 228 | Guice.createInjector(Stage.DEVELOPMENT, singletonsModule); |
limpbizkit | f530b25 | 2008-05-27 23:03:42 +0000 | [diff] [blame] | 229 | |
limpbizkit | 349f6f2 | 2008-06-02 06:05:54 +0000 | [diff] [blame] | 230 | assertEquals(0, AnnotatedSingleton.nextInstanceId); |
| 231 | assertEquals(0, BoundAsSingleton.nextInstanceId); |
| 232 | assertEquals(1, EagerSingleton.nextInstanceId); |
| 233 | assertEquals(0, RealLinkedSingleton.nextInstanceId); |
limpbizkit | e81cf1b | 2008-06-02 16:41:22 +0000 | [diff] [blame] | 234 | assertEquals(0, JustInTimeSingleton.nextInstanceId); |
| 235 | assertEquals(0, NotASingleton.nextInstanceId); |
limpbizkit | f530b25 | 2008-05-27 23:03:42 +0000 | [diff] [blame] | 236 | } |
| 237 | |
| 238 | public void testSingletonScopeIsNotSerializable() throws IOException { |
| 239 | Asserts.assertNotSerializable(Scopes.SINGLETON); |
| 240 | } |
| 241 | |
| 242 | public void testNoScopeIsNotSerializable() throws IOException { |
| 243 | Asserts.assertNotSerializable(Scopes.NO_SCOPE); |
| 244 | } |
| 245 | |
limpbizkit | 9266b99 | 2008-06-04 01:57:08 +0000 | [diff] [blame] | 246 | public void testUnscopedProviderWorksOutsideOfRequestedScope() { |
| 247 | final RememberProviderScope scope = new RememberProviderScope(); |
sberlin | b7a02b0 | 2011-07-08 00:34:16 +0000 | [diff] [blame] | 248 | |
limpbizkit | 9266b99 | 2008-06-04 01:57:08 +0000 | [diff] [blame] | 249 | Injector injector = Guice.createInjector(new AbstractModule() { |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 250 | @Override protected void configure() { |
limpbizkit | 9266b99 | 2008-06-04 01:57:08 +0000 | [diff] [blame] | 251 | bindScope(CustomScoped.class, scope); |
| 252 | bind(List.class).to(ArrayList.class).in(CustomScoped.class); |
| 253 | } |
| 254 | }); |
| 255 | |
| 256 | injector.getInstance(List.class); |
| 257 | Provider<?> listProvider = scope.providers.get(Key.get(List.class)); |
| 258 | |
| 259 | // this line fails with a NullPointerException because the Providers |
| 260 | // passed to Scope.scope() don't work outside of the scope() method. |
| 261 | assertTrue(listProvider.get() instanceof ArrayList); |
| 262 | } |
| 263 | |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 264 | static class OuterRuntimeModule extends AbstractModule { |
| 265 | @Override protected void configure() { |
| 266 | install(new InnerRuntimeModule()); |
| 267 | } |
| 268 | } |
| 269 | static class InnerRuntimeModule extends AbstractModule { |
| 270 | @Override protected void configure() { |
| 271 | bindScope(NotRuntimeRetainedScoped.class, Scopes.NO_SCOPE); |
| 272 | } |
| 273 | } |
limpbizkit | 5789ef4 | 2008-08-04 06:44:30 +0000 | [diff] [blame] | 274 | public void testScopeAnnotationWithoutRuntimeRetention() { |
| 275 | try { |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 276 | Guice.createInjector(new OuterRuntimeModule()); |
limpbizkit | 5789ef4 | 2008-08-04 06:44:30 +0000 | [diff] [blame] | 277 | fail(); |
| 278 | } catch (CreationException expected) { |
| 279 | assertContains(expected.getMessage(), |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 280 | "1) Please annotate " + NotRuntimeRetainedScoped.class.getName() |
| 281 | + " with @Retention(RUNTIME).", |
Christian Edward Gruber | ba5acdf | 2013-10-05 14:05:39 -0700 | [diff] [blame^] | 282 | "at " + InnerRuntimeModule.class.getName() + getDeclaringSourcePart(getClass()), |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 283 | asModuleChain(OuterRuntimeModule.class, InnerRuntimeModule.class)); |
limpbizkit | 5789ef4 | 2008-08-04 06:44:30 +0000 | [diff] [blame] | 284 | } |
| 285 | } |
| 286 | |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 287 | static class OuterDeprecatedModule extends AbstractModule { |
| 288 | @Override protected void configure() { |
| 289 | install(new InnerDeprecatedModule()); |
| 290 | } |
| 291 | } |
| 292 | static class InnerDeprecatedModule extends AbstractModule { |
| 293 | @Override protected void configure() { |
| 294 | bindScope(Deprecated.class, Scopes.NO_SCOPE); |
| 295 | } |
| 296 | } |
limpbizkit | d6becac | 2008-08-07 08:16:32 +0000 | [diff] [blame] | 297 | public void testBindScopeToAnnotationWithoutScopeAnnotation() { |
| 298 | try { |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 299 | Guice.createInjector(new OuterDeprecatedModule()); |
limpbizkit | d6becac | 2008-08-07 08:16:32 +0000 | [diff] [blame] | 300 | fail(); |
| 301 | } catch (CreationException expected) { |
| 302 | assertContains(expected.getMessage(), |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 303 | "1) Please annotate " + Deprecated.class.getName() + " with @ScopeAnnotation.", |
Christian Edward Gruber | ba5acdf | 2013-10-05 14:05:39 -0700 | [diff] [blame^] | 304 | "at " + InnerDeprecatedModule.class.getName() + getDeclaringSourcePart(getClass()), |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 305 | asModuleChain(OuterDeprecatedModule.class, InnerDeprecatedModule.class)); |
| 306 | } |
| 307 | } |
| 308 | |
| 309 | static class OuterScopeModule extends AbstractModule { |
| 310 | @Override protected void configure() { |
| 311 | install(new CustomNoScopeModule()); |
| 312 | install(new CustomSingletonModule()); |
| 313 | } |
| 314 | } |
| 315 | static class CustomNoScopeModule extends AbstractModule { |
| 316 | @Override protected void configure() { |
| 317 | bindScope(CustomScoped.class, Scopes.NO_SCOPE); |
| 318 | } |
| 319 | } |
| 320 | static class CustomSingletonModule extends AbstractModule { |
| 321 | @Override protected void configure() { |
| 322 | bindScope(CustomScoped.class, Scopes.SINGLETON); |
limpbizkit | d6becac | 2008-08-07 08:16:32 +0000 | [diff] [blame] | 323 | } |
| 324 | } |
| 325 | |
| 326 | public void testBindScopeTooManyTimes() { |
| 327 | try { |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 328 | Guice.createInjector(new OuterScopeModule()); |
limpbizkit | d6becac | 2008-08-07 08:16:32 +0000 | [diff] [blame] | 329 | fail(); |
| 330 | } catch (CreationException expected) { |
| 331 | assertContains(expected.getMessage(), |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 332 | "1) Scope Scopes.NO_SCOPE is already bound to " + CustomScoped.class.getName() |
Christian Edward Gruber | ba5acdf | 2013-10-05 14:05:39 -0700 | [diff] [blame^] | 333 | + " at " + CustomNoScopeModule.class.getName() + getDeclaringSourcePart(getClass()), |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 334 | asModuleChain(OuterScopeModule.class, CustomNoScopeModule.class), |
limpbizkit | a6e0e78 | 2008-09-03 06:19:56 +0000 | [diff] [blame] | 335 | "Cannot bind Scopes.SINGLETON.", |
Christian Edward Gruber | ba5acdf | 2013-10-05 14:05:39 -0700 | [diff] [blame^] | 336 | "at " + ScopesTest.class.getName(), getDeclaringSourcePart(getClass()), |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 337 | asModuleChain(OuterScopeModule.class, CustomSingletonModule.class)); |
limpbizkit | d6becac | 2008-08-07 08:16:32 +0000 | [diff] [blame] | 338 | } |
| 339 | } |
| 340 | |
| 341 | public void testDuplicateScopeAnnotations() { |
limpbizkit | b3a8f0b | 2008-09-05 22:30:40 +0000 | [diff] [blame] | 342 | Injector injector = Guice.createInjector(new AbstractModule() { |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 343 | @Override protected void configure() { |
limpbizkit | b3a8f0b | 2008-09-05 22:30:40 +0000 | [diff] [blame] | 344 | bindScope(CustomScoped.class, Scopes.NO_SCOPE); |
| 345 | } |
| 346 | }); |
| 347 | |
limpbizkit | d6becac | 2008-08-07 08:16:32 +0000 | [diff] [blame] | 348 | try { |
limpbizkit | b3a8f0b | 2008-09-05 22:30:40 +0000 | [diff] [blame] | 349 | injector.getInstance(SingletonAndCustomScoped.class); |
limpbizkit | d6becac | 2008-08-07 08:16:32 +0000 | [diff] [blame] | 350 | fail(); |
limpbizkit | 490833f | 2008-11-02 00:12:39 +0000 | [diff] [blame] | 351 | } catch (ConfigurationException expected) { |
limpbizkit | d6becac | 2008-08-07 08:16:32 +0000 | [diff] [blame] | 352 | assertContains(expected.getMessage(), |
limpbizkit | a6e0e78 | 2008-09-03 06:19:56 +0000 | [diff] [blame] | 353 | "1) More than one scope annotation was found: ", |
limpbizkit | 8ba9788 | 2008-11-04 02:52:54 +0000 | [diff] [blame] | 354 | "while locating " + SingletonAndCustomScoped.class.getName()); |
limpbizkit | d6becac | 2008-08-07 08:16:32 +0000 | [diff] [blame] | 355 | } |
| 356 | } |
| 357 | |
limpbizkit | b206d20 | 2008-12-02 06:16:53 +0000 | [diff] [blame] | 358 | public void testNullScopedAsASingleton() { |
| 359 | Provider<String> unscoped = new Provider<String>() { |
| 360 | final Iterator<String> values = Arrays.asList(null, "A").iterator(); |
| 361 | public String get() { |
| 362 | return values.next(); |
| 363 | } |
| 364 | }; |
| 365 | |
| 366 | Provider<String> scoped = Scopes.SINGLETON.scope(Key.get(String.class), unscoped); |
| 367 | assertNull(scoped.get()); |
| 368 | assertNull(scoped.get()); |
| 369 | assertNull(scoped.get()); |
| 370 | } |
| 371 | |
limpbizkit | 9266b99 | 2008-06-04 01:57:08 +0000 | [diff] [blame] | 372 | class RememberProviderScope implements Scope { |
limpbizkit | 185d2a2 | 2008-06-16 07:22:47 +0000 | [diff] [blame] | 373 | final Map<Key<?>, Provider<?>> providers = Maps.newHashMap(); |
limpbizkit | 9266b99 | 2008-06-04 01:57:08 +0000 | [diff] [blame] | 374 | public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) { |
| 375 | providers.put(key, unscoped); |
| 376 | return unscoped; |
| 377 | } |
| 378 | } |
| 379 | |
limpbizkit | 29ccacf | 2009-01-25 20:51:11 +0000 | [diff] [blame] | 380 | public void testSingletonAnnotationOnParameterizedType() { |
| 381 | Injector injector = Guice.createInjector(); |
| 382 | assertSame(injector.getInstance(new Key<Injected<String>>() {}), |
| 383 | injector.getInstance(new Key<Injected<String>>() {})); |
| 384 | assertSame(injector.getInstance(new Key<In<Integer>>() {}), |
| 385 | injector.getInstance(new Key<In<Short>>() {})); |
| 386 | } |
| 387 | |
| 388 | @ImplementedBy(Injected.class) public interface In<T> {} |
| 389 | @Singleton public static class Injected<T> implements In<T> {} |
| 390 | |
limpbizkit | 9266b99 | 2008-06-04 01:57:08 +0000 | [diff] [blame] | 391 | @Target({ ElementType.TYPE, ElementType.METHOD }) |
| 392 | @Retention(RUNTIME) |
| 393 | @ScopeAnnotation |
| 394 | public @interface CustomScoped {} |
| 395 | |
Sam Berlin | 66094fb | 2012-01-13 18:21:27 -0500 | [diff] [blame] | 396 | static final Scope CUSTOM_SCOPE = new Scope() { |
| 397 | public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) { |
| 398 | return Scopes.SINGLETON.scope(key, unscoped); |
| 399 | } |
| 400 | }; |
| 401 | |
limpbizkit | 5789ef4 | 2008-08-04 06:44:30 +0000 | [diff] [blame] | 402 | @Target({ ElementType.TYPE, ElementType.METHOD }) |
| 403 | @ScopeAnnotation |
| 404 | public @interface NotRuntimeRetainedScoped {} |
| 405 | |
Sam Berlin | 66094fb | 2012-01-13 18:21:27 -0500 | [diff] [blame] | 406 | @CustomScoped |
| 407 | static class AnnotatedCustomScoped {} |
| 408 | |
limpbizkit | f530b25 | 2008-05-27 23:03:42 +0000 | [diff] [blame] | 409 | @Singleton |
| 410 | static class AnnotatedSingleton { |
limpbizkit | 349f6f2 | 2008-06-02 06:05:54 +0000 | [diff] [blame] | 411 | static int nextInstanceId; |
| 412 | final int instanceId = nextInstanceId++; |
limpbizkit | f530b25 | 2008-05-27 23:03:42 +0000 | [diff] [blame] | 413 | } |
| 414 | |
| 415 | static class BoundAsSingleton { |
limpbizkit | 349f6f2 | 2008-06-02 06:05:54 +0000 | [diff] [blame] | 416 | static int nextInstanceId; |
| 417 | final int instanceId = nextInstanceId++; |
| 418 | } |
| 419 | |
| 420 | static class EagerSingleton { |
| 421 | static int nextInstanceId; |
| 422 | final int instanceId = nextInstanceId++; |
| 423 | } |
| 424 | |
| 425 | interface LinkedSingleton {} |
| 426 | |
| 427 | @Singleton |
| 428 | static class RealLinkedSingleton implements LinkedSingleton { |
| 429 | static int nextInstanceId; |
| 430 | final int instanceId = nextInstanceId++; |
crazyboblee | f33d23e | 2007-02-12 04:17:48 +0000 | [diff] [blame] | 431 | } |
limpbizkit | e81cf1b | 2008-06-02 16:41:22 +0000 | [diff] [blame] | 432 | |
| 433 | static class DependsOnJustInTimeSingleton { |
| 434 | @Inject JustInTimeSingleton justInTimeSingleton; |
| 435 | } |
| 436 | |
| 437 | @Singleton |
| 438 | static class JustInTimeSingleton { |
| 439 | static int nextInstanceId; |
| 440 | final int instanceId = nextInstanceId++; |
| 441 | } |
| 442 | |
| 443 | static class NotASingleton { |
| 444 | static int nextInstanceId; |
| 445 | final int instanceId = nextInstanceId++; |
| 446 | } |
limpbizkit | d6becac | 2008-08-07 08:16:32 +0000 | [diff] [blame] | 447 | |
Christian Edward Gruber | 33736ec | 2013-09-18 10:59:00 -0700 | [diff] [blame] | 448 | @SuppressWarnings("MoreThanOneScopeAnnotationOnClass") // suppress compiler error for testing |
| 449 | @Singleton |
| 450 | @CustomScoped |
limpbizkit | d6becac | 2008-08-07 08:16:32 +0000 | [diff] [blame] | 451 | static class SingletonAndCustomScoped {} |
limpbizkit | 27fc50d | 2008-08-08 07:43:39 +0000 | [diff] [blame] | 452 | |
| 453 | @ImplementedBy(Implementation.class) |
| 454 | static interface ImplementedBySingleton {} |
| 455 | |
| 456 | @ProvidedBy(ImplementationProvider.class) |
| 457 | static class ProvidedBySingleton { |
| 458 | static int nextInstanceId; |
| 459 | final int instanceId = nextInstanceId++; |
| 460 | } |
| 461 | |
| 462 | static class Implementation implements ImplementedBySingleton { |
| 463 | static int nextInstanceId; |
| 464 | final int instanceId = nextInstanceId++; |
| 465 | } |
| 466 | |
| 467 | static class ImplementationProvider implements Provider<ProvidedBySingleton> { |
| 468 | public ProvidedBySingleton get() { |
| 469 | return new ProvidedBySingleton(); |
| 470 | } |
| 471 | } |
limpbizkit | 0afda9a | 2009-06-23 00:29:43 +0000 | [diff] [blame] | 472 | |
| 473 | public void testScopeThatGetsAnUnrelatedObject() { |
| 474 | Injector injector = Guice.createInjector(new AbstractModule() { |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 475 | @Override protected void configure() { |
limpbizkit | 0afda9a | 2009-06-23 00:29:43 +0000 | [diff] [blame] | 476 | bind(B.class); |
| 477 | bind(C.class); |
| 478 | ProviderGetScope providerGetScope = new ProviderGetScope(); |
| 479 | requestInjection(providerGetScope); |
| 480 | bindScope(CustomScoped.class, providerGetScope); |
| 481 | } |
| 482 | }); |
| 483 | |
| 484 | injector.getInstance(C.class); |
| 485 | } |
| 486 | |
| 487 | class ProviderGetScope implements Scope { |
| 488 | @Inject Provider<B> bProvider; |
| 489 | |
| 490 | public <T> Provider<T> scope(Key<T> key, final Provider<T> unscoped) { |
| 491 | return new Provider<T>() { |
| 492 | public T get() { |
| 493 | bProvider.get(); |
| 494 | return unscoped.get(); |
| 495 | } |
| 496 | }; |
| 497 | } |
| 498 | } |
limpbizkit | 52aad3b | 2009-06-23 03:16:48 +0000 | [diff] [blame] | 499 | |
| 500 | public void testIsSingletonPositive() { |
| 501 | final Key<String> a = Key.get(String.class, named("A")); |
| 502 | final Key<String> b = Key.get(String.class, named("B")); |
| 503 | final Key<String> c = Key.get(String.class, named("C")); |
| 504 | final Key<String> d = Key.get(String.class, named("D")); |
| 505 | final Key<String> e = Key.get(String.class, named("E")); |
| 506 | final Key<String> f = Key.get(String.class, named("F")); |
| 507 | final Key<String> g = Key.get(String.class, named("G")); |
| 508 | final Key<Object> h = Key.get(Object.class, named("H")); |
sberlin | 09ab5f9 | 2010-10-25 00:41:10 +0000 | [diff] [blame] | 509 | final Key<String> i = Key.get(String.class, named("I")); |
limpbizkit | 52aad3b | 2009-06-23 03:16:48 +0000 | [diff] [blame] | 510 | |
| 511 | Module singletonBindings = new AbstractModule() { |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 512 | @Override protected void configure() { |
limpbizkit | 52aad3b | 2009-06-23 03:16:48 +0000 | [diff] [blame] | 513 | bind(a).to(b); |
| 514 | bind(b).to(c); |
| 515 | bind(c).toProvider(Providers.of("c")).in(Scopes.SINGLETON); |
| 516 | bind(d).toInstance("d"); |
| 517 | bind(e).toProvider(Providers.of("e")).asEagerSingleton(); |
| 518 | bind(f).toProvider(Providers.of("f")).in(Singleton.class); |
| 519 | bind(h).to(AnnotatedSingleton.class); |
sberlin | b7a02b0 | 2011-07-08 00:34:16 +0000 | [diff] [blame] | 520 | install(new PrivateModule() { |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 521 | @Override protected void configure() { |
sberlin | 09ab5f9 | 2010-10-25 00:41:10 +0000 | [diff] [blame] | 522 | bind(i).toProvider(Providers.of("i")).in(Singleton.class); |
| 523 | expose(i); |
| 524 | } |
| 525 | }); |
limpbizkit | 52aad3b | 2009-06-23 03:16:48 +0000 | [diff] [blame] | 526 | } |
| 527 | |
| 528 | @Provides @Named("G") @Singleton String provideG() { |
| 529 | return "g"; |
| 530 | } |
| 531 | }; |
| 532 | |
| 533 | @SuppressWarnings("unchecked") // we know the module contains only bindings |
| 534 | List<Element> moduleBindings = Elements.getElements(singletonBindings); |
| 535 | ImmutableMap<Key<?>, Binding<?>> map = indexBindings(moduleBindings); |
| 536 | assertFalse(Scopes.isSingleton(map.get(a))); // linked bindings are not followed by modules |
| 537 | assertFalse(Scopes.isSingleton(map.get(b))); |
| 538 | assertTrue(Scopes.isSingleton(map.get(c))); |
| 539 | assertTrue(Scopes.isSingleton(map.get(d))); |
| 540 | assertTrue(Scopes.isSingleton(map.get(e))); |
| 541 | assertTrue(Scopes.isSingleton(map.get(f))); |
| 542 | assertTrue(Scopes.isSingleton(map.get(g))); |
| 543 | assertFalse(Scopes.isSingleton(map.get(h))); // annotated classes are not followed by modules |
sberlin | 09ab5f9 | 2010-10-25 00:41:10 +0000 | [diff] [blame] | 544 | assertTrue(Scopes.isSingleton(map.get(i))); |
limpbizkit | 52aad3b | 2009-06-23 03:16:48 +0000 | [diff] [blame] | 545 | |
| 546 | Injector injector = Guice.createInjector(singletonBindings); |
| 547 | assertTrue(Scopes.isSingleton(injector.getBinding(a))); |
| 548 | assertTrue(Scopes.isSingleton(injector.getBinding(b))); |
| 549 | assertTrue(Scopes.isSingleton(injector.getBinding(c))); |
| 550 | assertTrue(Scopes.isSingleton(injector.getBinding(d))); |
| 551 | assertTrue(Scopes.isSingleton(injector.getBinding(e))); |
| 552 | assertTrue(Scopes.isSingleton(injector.getBinding(f))); |
| 553 | assertTrue(Scopes.isSingleton(injector.getBinding(g))); |
| 554 | assertTrue(Scopes.isSingleton(injector.getBinding(h))); |
sberlin | 09ab5f9 | 2010-10-25 00:41:10 +0000 | [diff] [blame] | 555 | assertTrue(Scopes.isSingleton(injector.getBinding(i))); |
limpbizkit | 52aad3b | 2009-06-23 03:16:48 +0000 | [diff] [blame] | 556 | } |
sberlin | b7a02b0 | 2011-07-08 00:34:16 +0000 | [diff] [blame] | 557 | |
limpbizkit | 52aad3b | 2009-06-23 03:16:48 +0000 | [diff] [blame] | 558 | public void testIsSingletonNegative() { |
| 559 | final Key<String> a = Key.get(String.class, named("A")); |
| 560 | final Key<String> b = Key.get(String.class, named("B")); |
| 561 | final Key<String> c = Key.get(String.class, named("C")); |
| 562 | final Key<String> d = Key.get(String.class, named("D")); |
| 563 | final Key<String> e = Key.get(String.class, named("E")); |
sberlin | 09ab5f9 | 2010-10-25 00:41:10 +0000 | [diff] [blame] | 564 | final Key<String> f = Key.get(String.class, named("F")); |
limpbizkit | 52aad3b | 2009-06-23 03:16:48 +0000 | [diff] [blame] | 565 | |
| 566 | Module singletonBindings = new AbstractModule() { |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 567 | @Override protected void configure() { |
limpbizkit | 52aad3b | 2009-06-23 03:16:48 +0000 | [diff] [blame] | 568 | bind(a).to(b); |
| 569 | bind(b).to(c); |
| 570 | bind(c).toProvider(Providers.of("c")).in(Scopes.NO_SCOPE); |
| 571 | bind(d).toProvider(Providers.of("d")).in(CustomScoped.class); |
| 572 | bindScope(CustomScoped.class, Scopes.NO_SCOPE); |
sberlin | b7a02b0 | 2011-07-08 00:34:16 +0000 | [diff] [blame] | 573 | install(new PrivateModule() { |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 574 | @Override protected void configure() { |
sberlin | 09ab5f9 | 2010-10-25 00:41:10 +0000 | [diff] [blame] | 575 | bind(f).toProvider(Providers.of("f")).in(CustomScoped.class); |
| 576 | expose(f); |
| 577 | } |
| 578 | }); |
limpbizkit | 52aad3b | 2009-06-23 03:16:48 +0000 | [diff] [blame] | 579 | } |
| 580 | |
| 581 | @Provides @Named("E") @CustomScoped String provideE() { |
| 582 | return "e"; |
| 583 | } |
| 584 | }; |
| 585 | |
| 586 | @SuppressWarnings("unchecked") // we know the module contains only bindings |
| 587 | List<Element> moduleBindings = Elements.getElements(singletonBindings); |
| 588 | ImmutableMap<Key<?>, Binding<?>> map = indexBindings(moduleBindings); |
| 589 | assertFalse(Scopes.isSingleton(map.get(a))); |
| 590 | assertFalse(Scopes.isSingleton(map.get(b))); |
| 591 | assertFalse(Scopes.isSingleton(map.get(c))); |
| 592 | assertFalse(Scopes.isSingleton(map.get(d))); |
| 593 | assertFalse(Scopes.isSingleton(map.get(e))); |
sberlin | 09ab5f9 | 2010-10-25 00:41:10 +0000 | [diff] [blame] | 594 | assertFalse(Scopes.isSingleton(map.get(f))); |
limpbizkit | 52aad3b | 2009-06-23 03:16:48 +0000 | [diff] [blame] | 595 | |
| 596 | Injector injector = Guice.createInjector(singletonBindings); |
| 597 | assertFalse(Scopes.isSingleton(injector.getBinding(a))); |
| 598 | assertFalse(Scopes.isSingleton(injector.getBinding(b))); |
| 599 | assertFalse(Scopes.isSingleton(injector.getBinding(c))); |
| 600 | assertFalse(Scopes.isSingleton(injector.getBinding(d))); |
| 601 | assertFalse(Scopes.isSingleton(injector.getBinding(e))); |
sberlin | 09ab5f9 | 2010-10-25 00:41:10 +0000 | [diff] [blame] | 602 | assertFalse(Scopes.isSingleton(injector.getBinding(f))); |
limpbizkit | 52aad3b | 2009-06-23 03:16:48 +0000 | [diff] [blame] | 603 | } |
| 604 | |
Sam Berlin | 66094fb | 2012-01-13 18:21:27 -0500 | [diff] [blame] | 605 | public void testIsScopedPositive() { |
| 606 | final Key<String> a = Key.get(String.class, named("A")); |
| 607 | final Key<String> b = Key.get(String.class, named("B")); |
| 608 | final Key<String> c = Key.get(String.class, named("C")); |
| 609 | final Key<String> d = Key.get(String.class, named("D")); |
| 610 | final Key<String> e = Key.get(String.class, named("E")); |
| 611 | final Key<Object> f = Key.get(Object.class, named("F")); |
| 612 | final Key<String> g = Key.get(String.class, named("G")); |
| 613 | |
| 614 | Module customBindings = new AbstractModule() { |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 615 | @Override protected void configure() { |
Sam Berlin | 66094fb | 2012-01-13 18:21:27 -0500 | [diff] [blame] | 616 | bindScope(CustomScoped.class, CUSTOM_SCOPE); |
| 617 | bind(a).to(b); |
| 618 | bind(b).to(c); |
| 619 | bind(c).toProvider(Providers.of("c")).in(CUSTOM_SCOPE); |
| 620 | bind(d).toProvider(Providers.of("d")).in(CustomScoped.class); |
| 621 | bind(f).to(AnnotatedCustomScoped.class); |
| 622 | install(new PrivateModule() { |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 623 | @Override protected void configure() { |
Sam Berlin | 66094fb | 2012-01-13 18:21:27 -0500 | [diff] [blame] | 624 | bind(g).toProvider(Providers.of("g")).in(CustomScoped.class); |
| 625 | expose(g); |
| 626 | } |
| 627 | }); |
| 628 | } |
| 629 | |
| 630 | @Provides @Named("E") @CustomScoped String provideE() { |
| 631 | return "e"; |
| 632 | } |
| 633 | }; |
| 634 | |
| 635 | @SuppressWarnings("unchecked") // we know the module contains only bindings |
| 636 | List<Element> moduleBindings = Elements.getElements(customBindings); |
| 637 | ImmutableMap<Key<?>, Binding<?>> map = indexBindings(moduleBindings); |
| 638 | assertFalse(isCustomScoped(map.get(a))); // linked bindings are not followed by modules |
| 639 | assertFalse(isCustomScoped(map.get(b))); |
| 640 | assertTrue(isCustomScoped(map.get(c))); |
| 641 | assertTrue(isCustomScoped(map.get(d))); |
| 642 | assertTrue(isCustomScoped(map.get(e))); |
| 643 | assertFalse(isCustomScoped(map.get(f))); // annotated classes are not followed by modules |
| 644 | assertTrue(isCustomScoped(map.get(g))); |
| 645 | |
| 646 | Injector injector = Guice.createInjector(customBindings); |
| 647 | assertTrue(isCustomScoped(injector.getBinding(a))); |
| 648 | assertTrue(isCustomScoped(injector.getBinding(b))); |
| 649 | assertTrue(isCustomScoped(injector.getBinding(c))); |
| 650 | assertTrue(isCustomScoped(injector.getBinding(d))); |
| 651 | assertTrue(isCustomScoped(injector.getBinding(e))); |
| 652 | assertTrue(isCustomScoped(injector.getBinding(f))); |
| 653 | assertTrue(isCustomScoped(injector.getBinding(g))); |
| 654 | } |
| 655 | |
| 656 | public void testIsScopedNegative() { |
| 657 | final Key<String> a = Key.get(String.class, named("A")); |
| 658 | final Key<String> b = Key.get(String.class, named("B")); |
| 659 | final Key<String> c = Key.get(String.class, named("C")); |
| 660 | final Key<String> d = Key.get(String.class, named("D")); |
| 661 | final Key<String> e = Key.get(String.class, named("E")); |
| 662 | final Key<String> f = Key.get(String.class, named("F")); |
| 663 | final Key<String> g = Key.get(String.class, named("G")); |
| 664 | final Key<String> h = Key.get(String.class, named("H")); |
| 665 | |
| 666 | Module customBindings = new AbstractModule() { |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 667 | @Override protected void configure() { |
Sam Berlin | 66094fb | 2012-01-13 18:21:27 -0500 | [diff] [blame] | 668 | bind(a).to(b); |
| 669 | bind(b).to(c); |
| 670 | bind(c).toProvider(Providers.of("c")).in(Scopes.NO_SCOPE); |
| 671 | bind(d).toProvider(Providers.of("d")).in(Singleton.class); |
| 672 | install(new PrivateModule() { |
Christian Edward Gruber | 2e39ef7 | 2013-10-05 14:04:53 -0700 | [diff] [blame] | 673 | @Override protected void configure() { |
Sam Berlin | 66094fb | 2012-01-13 18:21:27 -0500 | [diff] [blame] | 674 | bind(f).toProvider(Providers.of("f")).in(Singleton.class); |
| 675 | expose(f); |
| 676 | } |
| 677 | }); |
| 678 | bind(g).toInstance("g"); |
| 679 | bind(h).toProvider(Providers.of("h")).asEagerSingleton(); |
| 680 | } |
| 681 | |
| 682 | @Provides @Named("E") @Singleton String provideE() { |
| 683 | return "e"; |
| 684 | } |
| 685 | }; |
| 686 | |
| 687 | @SuppressWarnings("unchecked") // we know the module contains only bindings |
| 688 | List<Element> moduleBindings = Elements.getElements(customBindings); |
| 689 | ImmutableMap<Key<?>, Binding<?>> map = indexBindings(moduleBindings); |
| 690 | assertFalse(isCustomScoped(map.get(a))); |
| 691 | assertFalse(isCustomScoped(map.get(b))); |
| 692 | assertFalse(isCustomScoped(map.get(c))); |
| 693 | assertFalse(isCustomScoped(map.get(d))); |
| 694 | assertFalse(isCustomScoped(map.get(e))); |
| 695 | assertFalse(isCustomScoped(map.get(f))); |
| 696 | assertFalse(isCustomScoped(map.get(g))); |
| 697 | assertFalse(isCustomScoped(map.get(h))); |
| 698 | |
| 699 | Injector injector = Guice.createInjector(customBindings); |
| 700 | assertFalse(isCustomScoped(injector.getBinding(a))); |
| 701 | assertFalse(isCustomScoped(injector.getBinding(b))); |
| 702 | assertFalse(isCustomScoped(injector.getBinding(c))); |
| 703 | assertFalse(isCustomScoped(injector.getBinding(d))); |
| 704 | assertFalse(isCustomScoped(injector.getBinding(e))); |
| 705 | assertFalse(isCustomScoped(injector.getBinding(f))); |
| 706 | assertFalse(isCustomScoped(injector.getBinding(g))); |
| 707 | assertFalse(isCustomScoped(injector.getBinding(h))); |
| 708 | } |
| 709 | |
| 710 | private boolean isCustomScoped(Binding<?> binding) { |
| 711 | return Scopes.isScoped(binding, CUSTOM_SCOPE, CustomScoped.class); |
| 712 | } |
| 713 | |
limpbizkit | 52aad3b | 2009-06-23 03:16:48 +0000 | [diff] [blame] | 714 | ImmutableMap<Key<?>, Binding<?>> indexBindings(Iterable<Element> elements) { |
| 715 | ImmutableMap.Builder<Key<?>, Binding<?>> builder = ImmutableMap.builder(); |
| 716 | for (Element element : elements) { |
| 717 | if (element instanceof Binding) { |
| 718 | Binding<?> binding = (Binding<?>) element; |
| 719 | builder.put(binding.getKey(), binding); |
sberlin | 09ab5f9 | 2010-10-25 00:41:10 +0000 | [diff] [blame] | 720 | } else if (element instanceof PrivateElements) { |
| 721 | PrivateElements privateElements = (PrivateElements)element; |
| 722 | Map<Key<?>, Binding<?>> privateBindings = indexBindings(privateElements.getElements()); |
| 723 | for(Key<?> exposed : privateElements.getExposedKeys()) { |
| 724 | builder.put(exposed, privateBindings.get(exposed)); |
| 725 | } |
limpbizkit | 52aad3b | 2009-06-23 03:16:48 +0000 | [diff] [blame] | 726 | } |
| 727 | } |
| 728 | return builder.build(); |
| 729 | } |
limpbizkit | 1f1fca7 | 2009-07-23 17:46:52 +0000 | [diff] [blame] | 730 | |
| 731 | @Singleton |
| 732 | static class ThrowingSingleton { |
| 733 | static int nextInstanceId; |
| 734 | final int instanceId = nextInstanceId++; |
| 735 | |
| 736 | ThrowingSingleton() { |
| 737 | if (instanceId == 0) { |
| 738 | throw new RuntimeException(); |
| 739 | } |
| 740 | } |
| 741 | } |
| 742 | |
| 743 | public void testSingletonConstructorThrows() { |
| 744 | Injector injector = Guice.createInjector(); |
| 745 | |
| 746 | try { |
| 747 | injector.getInstance(ThrowingSingleton.class); |
| 748 | fail(); |
| 749 | } catch (ProvisionException expected) { |
| 750 | } |
| 751 | |
| 752 | // this behaviour is unspecified. If we change Guice to re-throw the exception, this test |
| 753 | // should be changed |
| 754 | injector.getInstance(ThrowingSingleton.class); |
| 755 | assertEquals(2, ThrowingSingleton.nextInstanceId); |
| 756 | } |
crazyboblee | f33d23e | 2007-02-12 04:17:48 +0000 | [diff] [blame] | 757 | } |