View Javadoc

1   /*
2    * Grapht, an open source dependency injector.
3    * Copyright 2014-2015 various contributors (see CONTRIBUTORS.txt)
4    * Copyright 2010-2014 Regents of the University of Minnesota
5    *
6    * This program is free software; you can redistribute it and/or modify
7    * it under the terms of the GNU Lesser General Public License as
8    * published by the Free Software Foundation; either version 2.1 of the
9    * License, or (at your option) any later version.
10   *
11   * This program is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13   * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14   * details.
15   *
16   * You should have received a copy of the GNU General Public License along with
17   * this program; if not, write to the Free Software Foundation, Inc., 51
18   * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19   */
20  package org.grouplens.grapht.reflect.internal;
21  
22  import org.grouplens.grapht.annotation.AnnotationBuilder;
23  import org.grouplens.grapht.annotation.Attribute;
24  import org.grouplens.grapht.reflect.Desire;
25  import org.grouplens.grapht.reflect.InjectionPoint;
26  import org.grouplens.grapht.reflect.internal.types.RoleA;
27  import org.grouplens.grapht.reflect.internal.types.RoleB;
28  import org.grouplens.grapht.reflect.internal.types.RoleD;
29  import org.junit.Assert;
30  import org.junit.Test;
31  
32  import javax.annotation.Nullable;
33  import javax.inject.Inject;
34  import javax.inject.Named;
35  import java.lang.annotation.Annotation;
36  import java.lang.annotation.Retention;
37  import java.lang.annotation.RetentionPolicy;
38  import java.lang.reflect.Constructor;
39  import java.lang.reflect.Field;
40  import java.lang.reflect.Method;
41  import java.util.HashSet;
42  import java.util.List;
43  import java.util.Set;
44  
45  import static org.hamcrest.Matchers.*;
46  
47  public class InjectionPointTest {
48      private static <T extends Annotation> Annotation named(String name) {
49          return AnnotationBuilder.of(Named.class).setValue(name).build();
50      }
51      
52      @Test
53      public void testAttributesLookup() throws Exception {
54          Constructor<CtorType> ctor = CtorType.class.getConstructor(Object.class, String.class);
55          ConstructorParameterInjectionPoint p1 = new ConstructorParameterInjectionPoint(ctor, 0);
56          ConstructorParameterInjectionPoint p2 = new ConstructorParameterInjectionPoint(ctor, 1);
57          
58          // p1 has the transient attribute, p2 does not
59          Assert.assertNotNull(p1.getAttribute(Transient.class));
60          Assert.assertNull(p2.getAttribute(Transient.class));
61          Assert.assertEquals(1, p1.getAttributes().size());
62          Assert.assertEquals(0, p2.getAttributes().size());
63      }
64      
65      @Test
66      public void testConstructorParameterInjectionPoint() throws Exception {
67          // created expected injection points
68          Constructor<CtorType> ctor = CtorType.class.getConstructor(Object.class, String.class);
69          ConstructorParameterInjectionPoint p1 = new ConstructorParameterInjectionPoint(ctor, 0);
70          ConstructorParameterInjectionPoint p2 = new ConstructorParameterInjectionPoint(ctor, 1);
71          
72          Set<InjectionPoint> expected = new HashSet<InjectionPoint>();
73          expected.add(p1);
74          expected.add(p2);
75          
76          // verify that the qualifiers and types are identified properly
77          Assert.assertThat(p1.getQualifier(), instanceOf(RoleA.class));
78          Assert.assertThat(p2.getQualifier(), instanceOf(RoleB.class));
79          Assert.assertThat(p1.getAttribute(Transient.class), notNullValue());
80          Assert.assertThat(p1.getAttributes(), contains(instanceOf(Transient.class)));
81          Assert.assertThat(p2.getAttributes(), hasSize(0));
82          Assert.assertThat(p2.getAttribute(Transient.class), nullValue());
83  
84          Assert.assertEquals(Object.class, p1.getType());
85          Assert.assertEquals(String.class, p2.getType());
86          
87          // verify nullability and transience
88          Assert.assertFalse(p1.isNullable());
89          Assert.assertTrue(p2.isNullable());
90          
91          Assert.assertEquals(expected, getInjectionPoints(CtorType.class));
92      }
93      
94      @Test
95      public void testSetterMethodInjectionPoint() throws Exception {
96          // create expected injection points
97          Method m1 = SetterType.class.getMethod("setA", Object.class);
98          Method m2 = SetterType.class.getMethod("setB", String.class);
99          Method m3 = SetterType.class.getMethod("setMulti", Object.class, String.class);
100         SetterInjectionPoint p1 = new SetterInjectionPoint(m1, 0);
101         SetterInjectionPoint p2 = new SetterInjectionPoint(m2, 0);
102         SetterInjectionPoint p3 = new SetterInjectionPoint(m3, 0);
103         SetterInjectionPoint p4 = new SetterInjectionPoint(m3, 1);
104         
105         Set<InjectionPoint> expected = new HashSet<InjectionPoint>();
106         expected.add(p1);
107         expected.add(p2);
108         expected.add(p3);
109         expected.add(p4);
110         
111         // verify that the qualifiers, types, attrs are identified properly
112         Assert.assertThat(p1.getQualifier(), instanceOf(RoleA.class));
113         Assert.assertThat(p1.getAttribute(Transient.class), notNullValue());
114         Assert.assertThat(p1.getAttributes(), contains(instanceOf(Transient.class)));
115 
116         Assert.assertThat(p2.getQualifier(), instanceOf(RoleB.class));
117         Assert.assertThat(p2.getAttributes(), hasSize(0));
118         Assert.assertThat(p2.getAttribute(Transient.class), nullValue());
119 
120         Assert.assertThat(p3.getQualifier(), nullValue());
121         Assert.assertThat(p3.getAttributes(), hasSize(0));
122 
123         Assert.assertThat(p4.getQualifier(), instanceOf(RoleD.class));
124         Assert.assertThat(p4.getAttributes(), hasSize(0));
125         Assert.assertThat(p4.getAttribute(Transient.class), nullValue());
126 
127         Assert.assertEquals(Object.class, p1.getType());
128         Assert.assertEquals(String.class, p2.getType());
129         Assert.assertEquals(Object.class, p3.getType());
130         Assert.assertEquals(String.class, p4.getType());
131         
132         // verify nullability and transience
133         Assert.assertFalse(p1.isNullable());
134         Assert.assertFalse(p2.isNullable());
135         Assert.assertFalse(p3.isNullable());
136         Assert.assertTrue(p4.isNullable());
137         
138         Assert.assertEquals(expected, getInjectionPoints(SetterType.class));
139     }
140     
141     @Test
142     public void testPrimitiveBoxing() throws Exception {
143         Method m1 = PrimitiveType.class.getMethod("setUnboxed", int.class);
144         Method m2 = PrimitiveType.class.getMethod("setBoxed", Integer.class);
145         
146         SetterInjectionPoint p1 = new SetterInjectionPoint(m1, 0);
147         SetterInjectionPoint p2 = new SetterInjectionPoint(m2, 0);
148         
149         // make sure that both injection points are normalized to boxed types
150         Assert.assertEquals(Integer.class, p1.getType());
151         Assert.assertEquals(Integer.class, p2.getType());
152     }
153     
154     @Test
155     public void testNamedQualifiers() throws Exception {
156         Constructor<NamedType> ctor = NamedType.class.getConstructor(String.class, Integer.class);
157         ConstructorParameterInjectionPoint p1 = new ConstructorParameterInjectionPoint(ctor, 0);
158         ConstructorParameterInjectionPoint p2 = new ConstructorParameterInjectionPoint(ctor, 1);
159         
160         Set<InjectionPoint> expected = new HashSet<InjectionPoint>();
161         expected.add(p1);
162         expected.add(p2);
163         
164         // verify that the qualifiers and types are identified properly
165         Assert.assertThat(p1.getQualifier(), equalTo(named("test1")));
166         Assert.assertThat(p2.getQualifier(), equalTo(named("test2")));
167 
168         Assert.assertEquals(String.class, p1.getType());
169         Assert.assertEquals(Integer.class, p2.getType());
170         
171         Assert.assertEquals(expected, getInjectionPoints(NamedType.class));
172     }
173     
174     @Test
175     public void testFieldInjectionPoints() throws Exception {
176         Field f1 = FieldType.class.getField("field");
177         FieldInjectionPoint p1 = new FieldInjectionPoint(f1);
178         
179         Set<InjectionPoint> expected = new HashSet<InjectionPoint>();
180         expected.add(p1);
181         
182         Assert.assertEquals(expected, getInjectionPoints(FieldType.class));
183     }
184     
185     @Test
186     public void testCombinedDesires() throws Exception {
187         // create expected injection points
188         Constructor<AllTypes> ctor = AllTypes.class.getConstructor(Object.class, String.class);
189         ConstructorParameterInjectionPoint p1 = new ConstructorParameterInjectionPoint(ctor, 0);
190         ConstructorParameterInjectionPoint p2 = new ConstructorParameterInjectionPoint(ctor, 1);
191         Method m1 = AllTypes.class.getMethod("setC", Object.class);
192         Method m2 = AllTypes.class.getMethod("setD", String.class);
193         Field f1 = AllTypes.class.getField("field");
194         FieldInjectionPoint p3 = new FieldInjectionPoint(f1);
195         SetterInjectionPoint p4 = new SetterInjectionPoint(m1, 0);
196         SetterInjectionPoint p5 = new SetterInjectionPoint(m2, 0);
197         
198         Set<InjectionPoint> expected = new HashSet<InjectionPoint>();
199         expected.add(p1);
200         expected.add(p2);
201         expected.add(p3);
202         expected.add(p4);
203         expected.add(p5);
204         
205         Assert.assertEquals(expected, getInjectionPoints(AllTypes.class));
206     }
207     
208     @Test
209     public void testSubclassOverrides() throws Exception {
210         Method m1 = SubType.class.getMethod("injectMethod", Object.class);
211         SetterInjectionPoint p1 = new SetterInjectionPoint(m1, 0);
212         
213         Set<InjectionPoint> expected = new HashSet<InjectionPoint>();
214         expected.add(p1);
215         
216         Assert.assertEquals(expected, getInjectionPoints(SubType.class));
217     }
218     
219     private Set<InjectionPoint> getInjectionPoints(Class<?> types) {
220         List<Desire> desires = ReflectionDesire.getDesires(types);
221         Set<InjectionPoint> points = new HashSet<InjectionPoint>();
222         for (Desire rd: desires) {
223             points.add(rd.getInjectionPoint());
224         }
225         return points;
226     }
227     
228     @Attribute
229     @Retention(RetentionPolicy.RUNTIME)
230     public static @interface Transient { }
231     
232     public static class CtorType {
233         @Inject
234         public CtorType(@Transient @RoleA Object a, @Nullable @RoleB String b) { }
235         
236         // other constructor to be ignored
237         public CtorType() { }
238     }
239     
240     public static class SetterType {
241         @Inject
242         public void setA(@Transient @RoleA Object a) { }
243         
244         @Inject
245         public void setB(@RoleB String b) { }
246         
247         @Inject
248         public boolean setMulti(Object a, @Nullable @RoleD String c) {
249             return false;
250         }
251         
252         // other setter to be ignored
253         public void setX(Object c) { }
254     }
255     
256     public static class FieldType {
257         @Inject public String field;
258     }
259     
260     public static class AllTypes {
261         @Inject public String field;
262         
263         @Inject
264         public AllTypes(@RoleA Object a, @RoleB String b) { }
265         
266         @Inject
267         public void setC(Object c) { }
268         
269         @Inject
270         public void setD(@RoleD String d) { }
271     }
272     
273     public static class PrimitiveType {
274         @Inject
275         public void setUnboxed(int a) { }
276         
277         @Inject
278         public void setBoxed(Integer a) { }
279     }
280     
281     public static class NamedType {
282         @Inject
283         public NamedType(@Named("test1") String a, @Named("test2") Integer b) { }
284     }
285     
286     public static class SuperType {
287         @Inject
288         public void nonInjectMethod(Object o) { }
289         
290         public void injectMethod(Object o) { }
291     }
292     
293     public static class SubType extends SuperType {
294         public void nonInjectMethod(Object o) { }
295         
296         @Inject
297         public void injectMethod(Object o) { }
298     }
299 }