##### Coverage Report - org.jbehave.core.configuration.guice.GuiceAnnotationBuilder

Classes in this File | Line Coverage | Branch Coverage | Complexity
GuiceAnnotationBuilder |
100% | 58/58
96% | 31/32
| 3.3333333333333335;3.333
GuiceAnnotationBuilder$1 |
100% | 1/1
N/A | N/A
| 3.3333333333333335;3.333
GuiceAnnotationBuilder$2 |
100% | 5/5
100% | 2/2
| 3.3333333333333335;3.333
GuiceAnnotationBuilder$3 |
100% | 2/2
N/A | N/A
| 3.3333333333333335;3.333

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.AnnotationRequired;
11 |  |
     import org.jbehave.core.configuration.Configuration;
12 |  |
     import org.jbehave.core.configuration.PrintStreamAnnotationMonitor;
13 |  |
     import org.jbehave.core.steps.CompositeStepsFactory;
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 |  |
      * Extends {@link AnnotationBuilder} to provide Guice-based dependency injection
30 |  |
      * if {@link UsingGuice} annotation is present.
31 |  |
      *
32 |  |
      * @author Cristiano Gavião
33 |  |
      * @author Mauro Talevi
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 |  |
         public Configuration buildConfiguration() throws AnnotationRequired {
48 |  |
49 | 14 |
             AnnotationFinder finder = annotationFinder();
50 | 14 |
             if (finder.isAnnotationPresent(UsingGuice.class)) {
51 |  |
                 @SuppressWarnings("rawtypes")
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 |  |
                 // creating injector with any modules found
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 InjectableStepsFactory buildStepsFactory(Configuration configuration) {
73 | 7 |
             InjectableStepsFactory factoryUsingSteps = super.buildStepsFactory(configuration);
74 | 7 |
             if (injector != null) {
75 | 4 |
                 return new CompositeStepsFactory(new GuiceStepsFactory(configuration, injector), factoryUsingSteps);
76 |  |
             }
77 | 3 |
             return factoryUsingSteps;
78 |  |
         }
79 |  |
80 |  |
         @Override
81 |  |
         protected ParameterConverters parameterConverters(AnnotationFinder annotationFinder) {
82 | 12 |
             ParameterConverters converters = super.parameterConverters(annotationFinder);
83 | 12 |
             if (injector != null) {
84 | 9 |
                 return converters.addConverters(findConverters(injector));
85 |  |
             }
86 | 3 |
             return converters;
87 |  |
         }
88 |  |
89 |  |
         /**
90 |  |
          * Finds any {@link ParameterConverter} defined in the given injector and,
91 |  |
          * if none found, recurses to its parent.
92 |  |
          *
93 |  |
          * @param injector
94 |  |
          *            the Injector
95 |  |
          * @return A List of ParameterConverter instances
96 |  |
          */
97 |  |
         private List<ParameterConverter> findConverters(Injector injector) {
98 | 119 |
             List<Binding<ParameterConverter>> bindingsByType = injector
99 | 119 |
                     .findBindingsByType(new TypeLiteral<ParameterConverter>() {
100 |  |
                     });
101 | 119 |
             if (bindingsByType.isEmpty() && injector.getParent() != null) {
102 | 110 |
                 return findConverters(injector.getParent());
103 |  |
             }
104 | 9 |
             List<ParameterConverter> converters = new ArrayList<ParameterConverter>();
105 | 9 |
             for (Binding<ParameterConverter> binding : bindingsByType) {
106 | 18 |
                 converters.add(binding.getProvider().get());
107 |  |
             }
108 | 9 |
             return converters;
109 |  |
         }
110 |  |
111 |  |
         @Override
112 |  |
         protected <T, V extends T> T instanceOf(final Class<T> type, final Class<V> ofClass) {
113 | 237 |
             if (injector != null) {
114 | 180 |
                 if (!type.equals(Object.class)) {
115 |  |
                     try {
116 | 177 |
                         boolean bindingFound = findBinding(injector, type);
117 | 177 |
                         if (bindingFound) {
118 |  |
                             // when binding found, just get the instance associated
119 | 65 |
                             return injector.getInstance(type);
120 |  |
                         } else {
121 |  |
                             // when binding not found, need to explicitly bind type
122 |  |
                             // + ofClass
123 | 112 |
                             Module module = new AbstractModule() {
124 |  |
125 |  |
                                 @Override
126 |  |
                                 protected void configure() {
127 | 112 |
                                     if (!type.equals(ofClass)) {
128 | 96 |
                                         bind(type).to(ofClass);
129 |  |
                                     } else {
130 |  |
                                         // when type and oFClass are
131 |  |
                                         // binding the ofClass
132 | 16 |
                                         bind(ofClass);
133 |  |
                                     }
134 | 112 |
                                 }
135 |  |
                             };
136 |  |
137 | 112 |
                             injector = injector.createChildInjector(module);
138 | 112 |
                             return injector.getInstance(type);
139 |  |
                         }
140 | 6 |
                     } catch (Exception e) {
141 |  |
                         // fall back on getting instance ofClass
142 | 6 |
                         return injector.getInstance(ofClass);
143 |  |
                     }
144 |  |
                 } else {
145 | 3 |
                     return injector.getBinding(ofClass).getProvider().get();
146 |  |
                 }
147 |  |
             }
148 | 57 |
             return super.instanceOf(type, ofClass);
149 |  |
         }
150 |  |
151 |  |
         /**
152 |  |
          * Finds binding for a type in the given injector and, if not found,
153 |  |
          * recurses to its parent
154 |  |
          *
155 |  |
          * @param injector
156 |  |
          *            the current Injector
157 |  |
          * @param type
158 |  |
          *            the Class representing the type
159 |  |
          * @return A boolean flag, <code>true</code> if binding found
160 |  |
          */
161 |  |
         private boolean findBinding(Injector injector, Class<?> type) {
162 | 1500 |
             boolean found = false;
163 | 1500 |
             for (Key<?> key : injector.getBindings().keySet()) {
164 | 5515 |
                 if (key.getTypeLiteral().getRawType().equals(type)) {
165 | 65 |
                     found = true;
166 | 65 |
                     break;
167 |  |
                 }
168 |  |
             }
169 | 1500 |
             if (!found && injector.getParent() != null) {
170 | 1323 |
                 return findBinding(injector.getParent(), type);
171 |  |
             }
172 |  |
173 | 177 |
             return found;
174 |  |
         }
175 |  |
176 |  |
         protected Injector createInjector(List<Module> modules) {
177 | 8 |
             if ( injector != null ){
178 | 1 |
                 return injector;
179 |  |
             }
180 | 7 |
             Injector root = Guice.createInjector(new AbstractModule() {
181 |  |
                 @Override
182 |  |
                 protected void configure() {
183 |  |
184 | 7 |
                 }
185 |  |
             });
186 | 7 |
             return root.createChildInjector(Modules.combine(modules));
187 |  |
         }
188 |  |
189 |  |
         protected Injector injector() {
190 | 2 |
             return injector;
191 |  |
         }
192 |  |
     }