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