1 | |
package org.jbehave.core.configuration.guice; |
2 | |
|
3 | |
import java.util.ArrayList; |
4 | |
import java.util.List; |
5 | |
|
6 | |
import org.jbehave.core.annotations.guice.UsingGuice; |
7 | |
import org.jbehave.core.configuration.AnnotationBuilder; |
8 | |
import org.jbehave.core.configuration.AnnotationFinder; |
9 | |
import org.jbehave.core.configuration.AnnotationMonitor; |
10 | |
import org.jbehave.core.configuration.Configuration; |
11 | |
import org.jbehave.core.configuration.AnnotationRequired; |
12 | |
import org.jbehave.core.configuration.PrintStreamAnnotationMonitor; |
13 | |
import org.jbehave.core.steps.CandidateSteps; |
14 | |
import org.jbehave.core.steps.InjectableStepsFactory; |
15 | |
import org.jbehave.core.steps.ParameterConverters; |
16 | |
import org.jbehave.core.steps.ParameterConverters.ParameterConverter; |
17 | |
import org.jbehave.core.steps.guice.GuiceStepsFactory; |
18 | |
|
19 | |
import com.google.inject.AbstractModule; |
20 | |
import com.google.inject.Binding; |
21 | |
import com.google.inject.Guice; |
22 | |
import com.google.inject.Injector; |
23 | |
import com.google.inject.Key; |
24 | |
import com.google.inject.Module; |
25 | |
import com.google.inject.TypeLiteral; |
26 | |
import com.google.inject.util.Modules; |
27 | |
|
28 | |
|
29 | |
|
30 | |
|
31 | |
|
32 | |
|
33 | |
|
34 | |
|
35 | |
public class GuiceAnnotationBuilder extends AnnotationBuilder { |
36 | |
|
37 | |
public Injector injector; |
38 | |
|
39 | |
public GuiceAnnotationBuilder(Class<?> annotatedClass) { |
40 | 13 | this(annotatedClass, new PrintStreamAnnotationMonitor()); |
41 | 13 | } |
42 | |
|
43 | |
public GuiceAnnotationBuilder(Class<?> annotatedClass, AnnotationMonitor annotationMonitor) { |
44 | 14 | super(annotatedClass, annotationMonitor); |
45 | 14 | } |
46 | |
|
47 | |
@SuppressWarnings("unchecked") |
48 | |
public Configuration buildConfiguration() throws AnnotationRequired { |
49 | |
|
50 | 14 | AnnotationFinder finder = annotationFinder(); |
51 | 14 | if (finder.isAnnotationPresent(UsingGuice.class)) { |
52 | 12 | List<Class> moduleClasses = finder.getAnnotatedValues(UsingGuice.class, Class.class, "modules"); |
53 | 12 | List<Module> modules = new ArrayList<Module>(); |
54 | 12 | for (Class<Module> moduleClass : moduleClasses) { |
55 | |
try { |
56 | 12 | modules.add(moduleClass.newInstance()); |
57 | 1 | } catch (Exception e) { |
58 | 1 | annotationMonitor().elementCreationFailed(moduleClass, e); |
59 | 23 | } |
60 | |
} |
61 | |
|
62 | 12 | if (modules.size() > 0) { |
63 | 9 | injector = createInjector(modules); |
64 | |
} |
65 | 12 | } else { |
66 | 2 | annotationMonitor().annotationNotFound(UsingGuice.class, annotatedClass()); |
67 | |
} |
68 | 14 | return super.buildConfiguration(); |
69 | |
} |
70 | |
|
71 | |
@Override |
72 | |
public List<CandidateSteps> buildCandidateSteps(Configuration configuration) { |
73 | 7 | List<CandidateSteps> steps = super.buildCandidateSteps(configuration); |
74 | 7 | if (injector != null) { |
75 | 4 | InjectableStepsFactory factory = new GuiceStepsFactory(configuration, injector); |
76 | 4 | steps.addAll(0, factory.createCandidateSteps()); |
77 | |
} |
78 | 7 | return steps; |
79 | |
} |
80 | |
|
81 | |
@Override |
82 | |
protected ParameterConverters parameterConverters(AnnotationFinder annotationFinder) { |
83 | 12 | ParameterConverters converters = super.parameterConverters(annotationFinder); |
84 | 12 | if (injector != null) { |
85 | 9 | return converters.addConverters(findConverters(injector)); |
86 | |
} |
87 | 3 | return converters; |
88 | |
} |
89 | |
|
90 | |
|
91 | |
|
92 | |
|
93 | |
|
94 | |
|
95 | |
|
96 | |
|
97 | |
|
98 | |
private List<ParameterConverter> findConverters(Injector injector) { |
99 | 108 | List<Binding<ParameterConverter>> bindingsByType = injector |
100 | 108 | .findBindingsByType(new TypeLiteral<ParameterConverter>() { |
101 | |
}); |
102 | 108 | if (bindingsByType.isEmpty() && injector.getParent() != null) { |
103 | 99 | return findConverters(injector.getParent()); |
104 | |
} |
105 | 9 | List<ParameterConverter> converters = new ArrayList<ParameterConverter>(); |
106 | 9 | for (Binding<ParameterConverter> binding : bindingsByType) { |
107 | 18 | converters.add(binding.getProvider().get()); |
108 | |
} |
109 | 9 | return converters; |
110 | |
} |
111 | |
|
112 | |
@Override |
113 | |
protected <T, V extends T> T instanceOf(final Class<T> type, final Class<V> ofClass) { |
114 | 189 | if (injector != null) { |
115 | 144 | if (!type.equals(Object.class)) { |
116 | |
try { |
117 | 141 | boolean bindingFound = findBinding(injector, type); |
118 | 141 | if (bindingFound) { |
119 | |
|
120 | 53 | return injector.getInstance(type); |
121 | |
} else { |
122 | |
|
123 | |
|
124 | 88 | Module module = new AbstractModule() { |
125 | |
|
126 | |
@Override |
127 | |
protected void configure() { |
128 | 88 | if (!type.equals(ofClass)) { |
129 | 80 | bind(type).to(ofClass); |
130 | |
} else { |
131 | |
|
132 | |
|
133 | 8 | bind(ofClass); |
134 | |
} |
135 | 88 | } |
136 | |
}; |
137 | |
|
138 | 88 | injector = injector.createChildInjector(module); |
139 | 88 | return injector.getInstance(type); |
140 | |
} |
141 | 6 | } catch (Exception e) { |
142 | |
|
143 | 6 | return injector.getInstance(ofClass); |
144 | |
} |
145 | |
} else { |
146 | 3 | return injector.getBinding(ofClass).getProvider().get(); |
147 | |
} |
148 | |
} |
149 | 45 | return super.instanceOf(type, ofClass); |
150 | |
} |
151 | |
|
152 | |
|
153 | |
|
154 | |
|
155 | |
|
156 | |
|
157 | |
|
158 | |
|
159 | |
|
160 | |
|
161 | |
|
162 | |
private boolean findBinding(Injector injector, Class<?> type) { |
163 | 1023 | boolean found = false; |
164 | 1023 | for (Key<?> key : injector.getBindings().keySet()) { |
165 | 3764 | if (key.getTypeLiteral().getRawType().equals(type)) { |
166 | 53 | found = true; |
167 | 53 | break; |
168 | |
} |
169 | |
} |
170 | 1023 | if (!found && injector.getParent() != null) { |
171 | 882 | return findBinding(injector.getParent(), type); |
172 | |
} |
173 | |
|
174 | 141 | return found; |
175 | |
} |
176 | |
|
177 | |
protected Injector createInjector(List<Module> modules) { |
178 | 8 | if ( injector != null ){ |
179 | 1 | return injector; |
180 | |
} |
181 | 7 | Injector root = Guice.createInjector(new AbstractModule() { |
182 | |
@Override |
183 | |
protected void configure() { |
184 | |
|
185 | 7 | } |
186 | |
}); |
187 | 7 | return root.createChildInjector(Modules.combine(modules)); |
188 | |
} |
189 | |
|
190 | |
protected Injector injector() { |
191 | 2 | return injector; |
192 | |
} |
193 | |
} |