Coverage Report - org.jbehave.core.configuration.guice.GuiceAnnotationBuilder
 
Classes in this File Line Coverage Branch Coverage Complexity
GuiceAnnotationBuilder
100%
59/59
96%
31/32
3.25
GuiceAnnotationBuilder$1
100%
1/1
N/A
3.25
GuiceAnnotationBuilder$2
100%
5/5
100%
2/2
3.25
GuiceAnnotationBuilder$3
100%
2/2
N/A
3.25
 
 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  
  * 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 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  
      * Finds any {@link ParameterConverter} defined in the given injector and,
 92  
      * if none found, recurses to its parent.
 93  
      * 
 94  
      * @param injector
 95  
      *            the Injector
 96  
      * @return A List of ParameterConverter instances
 97  
      */
 98  
     private List<ParameterConverter> findConverters(Injector injector) {
 99  109
         List<Binding<ParameterConverter>> bindingsByType = injector
 100  109
                 .findBindingsByType(new TypeLiteral<ParameterConverter>() {
 101  
                 });
 102  109
         if (bindingsByType.isEmpty() && injector.getParent() != null) {
 103  100
             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  213
         if (injector != null) {
 115  162
             if (!type.equals(Object.class)) {
 116  
                 try {
 117  159
                     boolean bindingFound = findBinding(injector, type);
 118  159
                     if (bindingFound) {
 119  
                         // when binding found, just get the instance associated
 120  63
                         return injector.getInstance(type);
 121  
                     } else {
 122  
                         // when binding not found, need to explicitly bind type
 123  
                         // + ofClass
 124  96
                         Module module = new AbstractModule() {
 125  
 
 126  
                             @Override
 127  
                             protected void configure() {
 128  96
                                 if (!type.equals(ofClass)) {
 129  88
                                     bind(type).to(ofClass);
 130  
                                 } else {
 131  
                                     // when type and oFClass are
 132  
                                     // binding the ofClass
 133  8
                                     bind(ofClass);
 134  
                                 }
 135  96
                             }
 136  
                         };
 137  
 
 138  96
                         injector = injector.createChildInjector(module);
 139  96
                         return injector.getInstance(type);
 140  
                     }
 141  6
                 } catch (Exception e) {
 142  
                     // fall back on getting instance ofClass
 143  6
                     return injector.getInstance(ofClass);
 144  
                 }
 145  
             } else {
 146  3
                 return injector.getBinding(ofClass).getProvider().get();
 147  
             }
 148  
         }
 149  51
         return super.instanceOf(type, ofClass);
 150  
     }
 151  
 
 152  
     /**
 153  
      * Finds binding for a type in the given injector and, if not found,
 154  
      * recurses to its parent
 155  
      * 
 156  
      * @param injector
 157  
      *            the current Injector
 158  
      * @param type
 159  
      *            the Class representing the type
 160  
      * @return A boolean flag, <code>true</code> if binding found
 161  
      */
 162  
     private boolean findBinding(Injector injector, Class<?> type) {
 163  1187
         boolean found = false;
 164  1187
         for (Key<?> key : injector.getBindings().keySet()) {
 165  4460
             if (key.getTypeLiteral().getRawType().equals(type)) {
 166  63
                 found = true;
 167  63
                 break;
 168  
             }
 169  
         }
 170  1187
         if (!found && injector.getParent() != null) {
 171  1028
             return findBinding(injector.getParent(), type);
 172  
         }
 173  
 
 174  159
         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  
 }