1 /* 2 * Copyright (C) 2010 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.name; 18 19 import static com.google.inject.Asserts.assertContains; 20 21 import com.google.inject.AbstractModule; 22 import com.google.inject.ConfigurationException; 23 import com.google.inject.CreationException; 24 import com.google.inject.Guice; 25 import com.google.inject.Inject; 26 import com.google.inject.Injector; 27 import com.google.inject.Key; 28 import com.google.inject.Module; 29 import com.google.inject.Provides; 30 import com.google.inject.internal.Annotations; 31 import java.io.Serializable; 32 import java.lang.annotation.Annotation; 33 import java.util.Properties; 34 import junit.framework.TestCase; 35 36 /** 37 * Tests that {@code javax.inject.Named} and {@code com.google.inject.name.Named} are completely 38 * interchangeable: bindings for one can be used to inject the other. 39 * 40 * @author cgdecker@gmail.com (Colin Decker) 41 */ 42 public class NamedEquivalanceTest extends TestCase { 43 44 private static final Module GUICE_BINDING_MODULE = moduleWithAnnotation(Names.named("foo")); 45 private static final Module JSR330_BINDING_MODULE = moduleWithAnnotation(new JsrNamed("foo")); 46 private static final Module GUICE_PROVIDER_METHOD_MODULE = getGuiceBindingProviderMethodModule(); 47 private static final Module JSR330_PROVIDER_METHOD_MODULE = 48 getJsr330BindingProviderMethodModule(); 49 testKeysCreatedWithDifferentTypesAreEqual()50 public void testKeysCreatedWithDifferentTypesAreEqual() { 51 assertEquals(keyForAnnotation(new GuiceNamed("foo")), keyForAnnotation(new JsrNamed("foo"))); 52 assertEquals(keyForAnnotation(Names.named("foo")), keyForAnnotation(new GuiceNamed("foo"))); 53 assertEquals(keyForAnnotation(Names.named("foo")), keyForAnnotation(new JsrNamed("foo"))); 54 55 assertEquals( 56 keyForAnnotationType(com.google.inject.name.Named.class), 57 keyForAnnotationType(javax.inject.Named.class)); 58 } 59 keyForAnnotation(Annotation annotation)60 private static Key<String> keyForAnnotation(Annotation annotation) { 61 return Key.get(String.class, annotation); 62 } 63 keyForAnnotationType(Class<? extends Annotation> annotationType)64 private static Key<String> keyForAnnotationType(Class<? extends Annotation> annotationType) { 65 return Key.get(String.class, annotationType); 66 } 67 testBindingWithNamesCanInjectBothTypes()68 public void testBindingWithNamesCanInjectBothTypes() { 69 assertInjectionsSucceed(GUICE_BINDING_MODULE); 70 } 71 testBindingWithJsr330AnnotationCanInjectBothTypes()72 public void testBindingWithJsr330AnnotationCanInjectBothTypes() { 73 assertInjectionsSucceed(JSR330_BINDING_MODULE); 74 } 75 testBindingWithGuiceNamedAnnotatedProviderMethodCanInjectBothTypes()76 public void testBindingWithGuiceNamedAnnotatedProviderMethodCanInjectBothTypes() { 77 assertInjectionsSucceed(GUICE_PROVIDER_METHOD_MODULE); 78 } 79 testBindingWithJsr330NamedAnnotatedProviderMethodCanInjectBothTypes()80 public void testBindingWithJsr330NamedAnnotatedProviderMethodCanInjectBothTypes() { 81 assertInjectionsSucceed(JSR330_PROVIDER_METHOD_MODULE); 82 } 83 testBindingDifferentTypesWithSameValueIsIgnored()84 public void testBindingDifferentTypesWithSameValueIsIgnored() { 85 assertDuplicateBinding(GUICE_BINDING_MODULE, JSR330_BINDING_MODULE, false); 86 assertDuplicateBinding(JSR330_BINDING_MODULE, GUICE_BINDING_MODULE, false); 87 } 88 testBindingDifferentTypesWithSameValueIsAnErrorWithProviderMethods()89 public void testBindingDifferentTypesWithSameValueIsAnErrorWithProviderMethods() { 90 assertDuplicateBinding(GUICE_PROVIDER_METHOD_MODULE, JSR330_PROVIDER_METHOD_MODULE, true); 91 assertDuplicateBinding(JSR330_PROVIDER_METHOD_MODULE, GUICE_PROVIDER_METHOD_MODULE, true); 92 } 93 testBindingDifferentTypesWithSameValueIsAnErrorMixed()94 public void testBindingDifferentTypesWithSameValueIsAnErrorMixed() { 95 assertDuplicateBinding(GUICE_BINDING_MODULE, JSR330_PROVIDER_METHOD_MODULE, true); 96 assertDuplicateBinding(JSR330_BINDING_MODULE, GUICE_PROVIDER_METHOD_MODULE, true); 97 } 98 testMissingBindingForGuiceNamedUsesSameTypeInErrorMessage()99 public void testMissingBindingForGuiceNamedUsesSameTypeInErrorMessage() { 100 assertMissingBindingErrorMessageUsesType(GuiceNamedClient.class); 101 } 102 testMissingBindingForJsr330NamedUsesSameTypeInErrorMessage()103 public void testMissingBindingForJsr330NamedUsesSameTypeInErrorMessage() { 104 assertMissingBindingErrorMessageUsesType(Jsr330NamedClient.class); 105 } 106 testBindPropertiesWorksWithJsr330()107 public void testBindPropertiesWorksWithJsr330() { 108 assertInjectionsSucceed( 109 new AbstractModule() { 110 @Override 111 protected void configure() { 112 Properties properties = new Properties(); 113 properties.put("foo", "bar"); 114 Names.bindProperties(binder(), properties); 115 } 116 }); 117 } 118 assertMissingBindingErrorMessageUsesType(Class<?> clientType)119 private static void assertMissingBindingErrorMessageUsesType(Class<?> clientType) { 120 try { 121 Guice.createInjector().getInstance(clientType); 122 fail("should have thrown ConfigurationException"); 123 } catch (ConfigurationException e) { 124 assertContains( 125 e.getMessage(), 126 "No implementation for java.lang.String annotated with " 127 + "@com.google.inject.name.Named(value=" 128 + Annotations.memberValueString("foo") 129 + ") was bound."); 130 } 131 } 132 assertDuplicateBinding(Module a, Module b, boolean fails)133 private static void assertDuplicateBinding(Module a, Module b, boolean fails) { 134 try { 135 Guice.createInjector(a, b); 136 if (fails) { 137 fail("should have thrown CreationException"); 138 } 139 } catch (CreationException e) { 140 if (fails) { 141 assertContains( 142 e.getMessage(), 143 "A binding to java.lang.String annotated with @com.google.inject.name.Named(value=" 144 + Annotations.memberValueString("foo") 145 + ") was already configured"); 146 } else { 147 throw e; 148 } 149 } 150 } 151 moduleWithAnnotation(final Annotation annotation)152 private static Module moduleWithAnnotation(final Annotation annotation) { 153 return new AbstractModule() { 154 @Override 155 protected void configure() { 156 bindConstant().annotatedWith(annotation).to("bar"); 157 } 158 }; 159 } 160 161 private static void assertInjectionsSucceed(Module module) { 162 Injector injector = Guice.createInjector(module); 163 assertInjected( 164 injector.getInstance(GuiceNamedClient.class), 165 injector.getInstance(Jsr330NamedClient.class)); 166 } 167 168 private static void assertInjected(GuiceNamedClient guiceClient, Jsr330NamedClient jsr330Client) { 169 assertEquals("bar", guiceClient.foo); 170 assertEquals("bar", jsr330Client.foo); 171 } 172 173 private static Module getJsr330BindingProviderMethodModule() { 174 return new AbstractModule() { 175 176 @SuppressWarnings("unused") 177 @Provides 178 @javax.inject.Named("foo") 179 String provideFoo() { 180 return "bar"; 181 } 182 }; 183 } 184 185 private static Module getGuiceBindingProviderMethodModule() { 186 return new AbstractModule() { 187 188 @SuppressWarnings("unused") 189 @Provides 190 @Named("foo") 191 String provideFoo() { 192 return "bar"; 193 } 194 }; 195 } 196 197 private static class GuiceNamedClient { 198 @Inject 199 @Named("foo") 200 String foo; 201 } 202 203 private static class Jsr330NamedClient { 204 @Inject 205 @javax.inject.Named("foo") 206 String foo; 207 } 208 209 private static class JsrNamed implements javax.inject.Named, Serializable { 210 private final String value; 211 212 public JsrNamed(String value) { 213 this.value = value; 214 } 215 216 @Override 217 public String value() { 218 return this.value; 219 } 220 221 @Override 222 public int hashCode() { 223 // This is specified in java.lang.Annotation. 224 return (127 * "value".hashCode()) ^ value.hashCode(); 225 } 226 227 @Override 228 public boolean equals(Object o) { 229 if (!(o instanceof javax.inject.Named)) { 230 return false; 231 } 232 233 javax.inject.Named other = (javax.inject.Named) o; 234 return value.equals(other.value()); 235 } 236 237 @Override 238 public String toString() { 239 return "@" 240 + javax.inject.Named.class.getName() 241 + "(value=" 242 + Annotations.memberValueString(value) 243 + ")"; 244 } 245 246 @Override 247 public Class<? extends Annotation> annotationType() { 248 return javax.inject.Named.class; 249 } 250 251 private static final long serialVersionUID = 0; 252 } 253 254 private static class GuiceNamed implements com.google.inject.name.Named, Serializable { 255 private final String value; 256 257 public GuiceNamed(String value) { 258 this.value = value; 259 } 260 261 @Override 262 public String value() { 263 return this.value; 264 } 265 266 @Override 267 public int hashCode() { 268 // This is specified in java.lang.Annotation. 269 return (127 * "value".hashCode()) ^ value.hashCode(); 270 } 271 272 @Override 273 public boolean equals(Object o) { 274 if (!(o instanceof com.google.inject.name.Named)) { 275 return false; 276 } 277 278 com.google.inject.name.Named other = (com.google.inject.name.Named) o; 279 return value.equals(other.value()); 280 } 281 282 @Override 283 public String toString() { 284 return "@" 285 + com.google.inject.name.Named.class.getName() 286 + "(value=" 287 + Annotations.memberValueString(value) 288 + ")"; 289 } 290 291 @Override 292 public Class<? extends Annotation> annotationType() { 293 return com.google.inject.name.Named.class; 294 } 295 296 private static final long serialVersionUID = 0; 297 } 298 } 299