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.ResolutionException;
23  import org.grouplens.grapht.reflect.Desire;
24  import org.grouplens.grapht.reflect.InjectionPoint;
25  import org.grouplens.grapht.reflect.MockInjectionPoint;
26  import org.grouplens.grapht.reflect.internal.types.*;
27  import org.grouplens.grapht.solver.*;
28  import org.junit.Assert;
29  import org.junit.Test;
30  
31  import javax.annotation.Nullable;
32  import javax.inject.Inject;
33  import java.lang.reflect.Method;
34  import java.util.List;
35  
36  import static org.hamcrest.Matchers.instanceOf;
37  import static org.hamcrest.Matchers.nullValue;
38  
39  public class ReflectionDesireTest {
40      @Test
41      public void testSubtypeInjectionPointSatisfactionConstructor() throws Exception {
42          ClassSatisfaction satis = new ClassSatisfaction(B.class);
43          InjectionPoint inject = new MockInjectionPoint(A.class, false);
44          ReflectionDesire desire = new ReflectionDesire(B.class, inject, satis);
45          
46          Assert.assertEquals(B.class, desire.getDesiredType());
47          Assert.assertEquals(satis, desire.getSatisfaction());
48          Assert.assertEquals(inject, desire.getInjectionPoint());
49      }
50      
51      @Test
52      public void testInheritedRoleDefault() throws Exception {
53          // Test that the default desire for the setRoleE injection point in TypeC
54          // defaults to TypeB.  This also tests qualifier default inheritence
55          List<Desire> desires = ReflectionDesire.getDesires(TypeC.class);
56          ReflectionDesire dflt = getDefaultDesire(TypeC.class.getMethod("setRoleD", InterfaceB.class), desires);
57          
58          Assert.assertTrue(dflt.getSatisfaction() instanceof ClassSatisfaction);
59          Assert.assertThat(dflt.getInjectionPoint().getQualifier(),
60                            instanceOf(RoleD.class));
61          Assert.assertEquals(TypeB.class, ((ClassSatisfaction) dflt.getSatisfaction()).getErasedType());
62          Assert.assertEquals(TypeB.class, dflt.getDesiredType());
63      }
64      
65      @Test
66      public void testRoleParameterDefault() throws Exception {
67          // Test that the default desire for the constructor injection in TypeC
68          // defaults to the int value 5
69          List<Desire> desires = ReflectionDesire.getDesires(TypeC.class);
70          ReflectionDesire dflt = getDefaultDesire(0, desires);
71          
72          Assert.assertTrue(dflt.getSatisfaction() instanceof InstanceSatisfaction);
73          Assert.assertThat(dflt.getInjectionPoint().getQualifier(),
74                            instanceOf(ParameterA.class));
75          Assert.assertEquals(Integer.class, dflt.getDesiredType());
76          Assert.assertEquals(5, ((InstanceSatisfaction) dflt.getSatisfaction()).getInstance());
77      }
78      
79      @Test
80      public void testProvidedByDefault() throws Exception {
81          // Test that the default desire for the setTypeA injection point in TypeC
82          // is satisfied by a provider satisfaction to ProviderA
83          List<Desire> desires = ReflectionDesire.getDesires(TypeC.class);
84          ReflectionDesire dflt = getDefaultDesire(TypeC.class.getMethod("setTypeA", TypeA.class), desires);
85          
86          Assert.assertTrue(dflt.getSatisfaction() instanceof ProviderClassSatisfaction);
87          Assert.assertThat(dflt.getInjectionPoint().getQualifier(),
88                            nullValue());
89          Assert.assertEquals(TypeA.class, dflt.getDesiredType());
90          Assert.assertEquals(ProviderA.class, ((ProviderClassSatisfaction) dflt.getSatisfaction()).getProviderType());
91      }
92      
93      @Test
94      public void testImplementedByDefault() throws Exception {
95          // Test that the default desire for the setRoleA injection point in TypeC
96          // is satisfied by a type binding to TypeA
97          List<Desire> desires = ReflectionDesire.getDesires(TypeC.class);
98          ReflectionDesire dflt = getDefaultDesire(TypeC.class.getMethod("setRoleA", InterfaceA.class), desires);
99          
100         Assert.assertTrue(dflt.getSatisfaction() instanceof ClassSatisfaction);
101         Assert.assertThat(dflt.getInjectionPoint().getQualifier(),
102                           instanceOf(RoleA.class));
103         Assert.assertEquals(TypeA.class, ((ClassSatisfaction) dflt.getSatisfaction()).getErasedType());
104         Assert.assertEquals(TypeA.class, dflt.getDesiredType());
105     }
106     
107     @Test
108     public void testNoDefaultDesire() throws Exception {
109         // Test that there is no default desire for the setTypeB injection point
110         // in TypeC, but that it is still satisfiable
111         List<Desire> desires = ReflectionDesire.getDesires(TypeC.class);
112         ReflectionDesire dflt = getDefaultDesire(TypeC.class.getMethod("setTypeB", TypeB.class), desires);
113         
114         Assert.assertNull(dflt);
115     }
116 
117     /**
118      * If we have a nullable injection point, and restrict the desire to a class, we
119      * should throw out the null satisfaction (and recompute it, if appropriate) based
120      * on the restricted type.
121      */
122     @Test
123     public void testRestrictNullableDesire() throws NoSuchMethodException, ResolutionException {
124         List<Desire> desires = ReflectionDesire.getDesires(ReqB.class);
125         Assert.assertEquals(1, desires.size());
126         Desire desire = desires.get(0);
127         Desire restricted = desire.restrict(TypeB.class);
128         Assert.assertNotNull(restricted);
129     }
130     
131     private ReflectionDesire getDefaultDesire(Object methodOrCtorParam, List<Desire> desires) throws ResolutionException {
132         BindingResult result = null;
133         for (Desire d: desires) {
134             if (methodOrCtorParam instanceof Method) {
135                 if (d.getInjectionPoint() instanceof SetterInjectionPoint) {
136                     SetterInjectionPoint sp = (SetterInjectionPoint) (d.getInjectionPoint());
137                     if (sp.getMember().equals(methodOrCtorParam)) {
138                         result = DefaultDesireBindingFunction.create()
139                                                              .bind(DependencySolver.initialContext(),
140                                                                    DesireChain.singleton(d));
141                         break;
142                     }
143                 }
144             } else { // assume its an Integer
145                 if (d.getInjectionPoint() instanceof ConstructorParameterInjectionPoint) {
146                     ConstructorParameterInjectionPoint cp = (ConstructorParameterInjectionPoint) (d.getInjectionPoint());
147                     if (((Integer) methodOrCtorParam).intValue() == cp.getParameterIndex()) {
148                         result = DefaultDesireBindingFunction.create()
149                                 .bind(DependencySolver.initialContext(),
150                                       DesireChain.singleton(d));
151                         break;
152                     }
153                 }
154             }
155         }
156         
157         return (result == null ? null : (ReflectionDesire) result.getDesire());
158     }
159     
160     public static class A { }
161     
162     public static class B extends A { }
163     
164     public static class C { }
165 
166     public static class ReqB {
167         @Inject
168         public void setB(@Nullable InterfaceB foo) {
169             /* do nothing */
170         }
171     }
172 }