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.333
GuiceAnnotationBuilder$1
100%
1/1
N/A
3.333
GuiceAnnotationBuilder$2
100%
5/5
100%
2/2
3.333
GuiceAnnotationBuilder$3
100%
2/2
N/A
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  118
         List<Binding<ParameterConverter>> bindingsByType = injector
 99  118
                 .findBindingsByType(new TypeLiteral<ParameterConverter>() {
 100  
                 });
 101  118
         if (bindingsByType.isEmpty() && injector.getParent() != null) {
 102  109
             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  225
         if (injector != null) {
 114  171
             if (!type.equals(Object.class)) {
 115  
                 try {
 116  168
                     boolean bindingFound = findBinding(injector, type);
 117  168
                     if (bindingFound) {
 118  
                         // when binding found, just get the instance associated
 119  64
                         return injector.getInstance(type);
 120  
                     } else {
 121  
                         // when binding not found, need to explicitly bind type
 122  
                         // + ofClass
 123  104
                         Module module = new AbstractModule() {
 124  
 
 125  
                             @Override
 126  
                             protected void configure() {
 127  104
                                 if (!type.equals(ofClass)) {
 128  96
                                     bind(type).to(ofClass);
 129  
                                 } else {
 130  
                                     // when type and oFClass are
 131  
                                     // binding the ofClass
 132  8
                                     bind(ofClass);
 133  
                                 }
 134  104
                             }
 135  
                         };
 136  
 
 137  104
                         injector = injector.createChildInjector(module);
 138  104
                         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  54
         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  1362
         boolean found = false;
 163  1362
         for (Key<?> key : injector.getBindings().keySet()) {
 164  5038
             if (key.getTypeLiteral().getRawType().equals(type)) {
 165  64
                 found = true;
 166  64
                 break;
 167  
             }
 168  
         }
 169  1362
         if (!found && injector.getParent() != null) {
 170  1194
             return findBinding(injector.getParent(), type);
 171  
         }
 172  
 
 173  168
         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  
 }