GuiceAnnotationBuilder.java
- package org.jbehave.core.configuration.guice;
- import java.util.ArrayList;
- import java.util.List;
- import com.google.inject.AbstractModule;
- import com.google.inject.Binding;
- import com.google.inject.Guice;
- import com.google.inject.Injector;
- import com.google.inject.Key;
- import com.google.inject.Module;
- import com.google.inject.TypeLiteral;
- import com.google.inject.util.Modules;
- import org.jbehave.core.annotations.guice.UsingGuice;
- import org.jbehave.core.configuration.AnnotationBuilder;
- import org.jbehave.core.configuration.AnnotationFinder;
- import org.jbehave.core.configuration.AnnotationMonitor;
- import org.jbehave.core.configuration.AnnotationRequired;
- import org.jbehave.core.configuration.Configuration;
- import org.jbehave.core.configuration.PrintStreamAnnotationMonitor;
- import org.jbehave.core.io.ResourceLoader;
- import org.jbehave.core.model.TableTransformers;
- import org.jbehave.core.steps.CompositeStepsFactory;
- import org.jbehave.core.steps.InjectableStepsFactory;
- import org.jbehave.core.steps.ParameterConverters;
- import org.jbehave.core.steps.ParameterConverters.ParameterConverter;
- import org.jbehave.core.steps.guice.GuiceStepsFactory;
- /**
- * Extends {@link AnnotationBuilder} to provide Guice-based dependency injection
- * if {@link UsingGuice} annotation is present.
- *
- * @author Cristiano GaviĆ£o
- * @author Mauro Talevi
- */
- public class GuiceAnnotationBuilder extends AnnotationBuilder {
- public Injector injector;
- public GuiceAnnotationBuilder(Class<?> annotatedClass) {
- this(annotatedClass, new PrintStreamAnnotationMonitor());
- }
- public GuiceAnnotationBuilder(Class<?> annotatedClass, AnnotationMonitor annotationMonitor) {
- super(annotatedClass, annotationMonitor);
- }
- @Override
- public Configuration buildConfiguration() throws AnnotationRequired {
- AnnotationFinder finder = annotationFinder();
- if (finder.isAnnotationPresent(UsingGuice.class)) {
- @SuppressWarnings("rawtypes")
- List<Class> moduleClasses = finder.getAnnotatedValues(UsingGuice.class, Class.class, "modules");
- List<Module> modules = new ArrayList<>();
- for (Class<Module> moduleClass : moduleClasses) {
- try {
- modules.add(moduleClass.newInstance());
- } catch (Exception e) {
- annotationMonitor().elementCreationFailed(moduleClass, e);
- }
- }
- // creating injector with any modules found
- if (modules.size() > 0) {
- injector = createInjector(modules);
- }
- } else {
- annotationMonitor().annotationNotFound(UsingGuice.class, annotatedClass());
- }
- return super.buildConfiguration();
- }
- @Override
- public InjectableStepsFactory buildStepsFactory(Configuration configuration) {
- InjectableStepsFactory factoryUsingSteps = super.buildStepsFactory(configuration);
- if (injector != null) {
- return new CompositeStepsFactory(new GuiceStepsFactory(configuration, injector), factoryUsingSteps);
- }
- return factoryUsingSteps;
- }
- @Override
- protected ParameterConverters parameterConverters(AnnotationFinder annotationFinder, ResourceLoader resourceLoader,
- TableTransformers tableTransformers) {
- ParameterConverters converters = super.parameterConverters(annotationFinder, resourceLoader, tableTransformers);
- if (injector != null) {
- return converters.addConverters(findConverters(injector));
- }
- return converters;
- }
- /**
- * Finds any {@link ParameterConverter} defined in the given injector and,
- * if none found, recurses to its parent.
- *
- * @param injector
- * the Injector
- * @return A List of ParameterConverter instances
- */
- private List<ParameterConverter> findConverters(Injector injector) {
- List<Binding<ParameterConverter>> bindingsByType = injector
- .findBindingsByType(new TypeLiteral<ParameterConverter>() {
- });
- if (bindingsByType.isEmpty() && injector.getParent() != null) {
- return findConverters(injector.getParent());
- }
- List<ParameterConverter> converters = new ArrayList<>();
- for (Binding<ParameterConverter> binding : bindingsByType) {
- converters.add(binding.getProvider().get());
- }
- return converters;
- }
- @Override
- protected <T, V extends T> T instanceOf(final Class<T> type, final Class<V> ofClass) {
- if (injector != null) {
- if (!type.equals(Object.class)) {
- try {
- boolean bindingFound = findBinding(injector, type);
- if (bindingFound) {
- // when binding found, just get the instance associated
- return injector.getInstance(type);
- } else {
- // when binding not found, need to explicitly bind type
- // + ofClass
- Module module = new AbstractModule() {
- @Override
- protected void configure() {
- if (!type.equals(ofClass)) {
- bind(type).to(ofClass);
- } else {
- // when type and oFClass are
- // binding the ofClass
- bind(ofClass);
- }
- }
- };
- injector = injector.createChildInjector(module);
- return injector.getInstance(type);
- }
- } catch (Exception e) {
- // fall back on getting instance ofClass
- return injector.getInstance(ofClass);
- }
- } else {
- return injector.getBinding(ofClass).getProvider().get();
- }
- }
- return super.instanceOf(type, ofClass);
- }
- /**
- * Finds binding for a type in the given injector and, if not found,
- * recurses to its parent
- *
- * @param injector
- * the current Injector
- * @param type
- * the Class representing the type
- * @return A boolean flag, <code>true</code> if binding found
- */
- private boolean findBinding(Injector injector, Class<?> type) {
- boolean found = false;
- for (Key<?> key : injector.getBindings().keySet()) {
- if (key.getTypeLiteral().getRawType().equals(type)) {
- found = true;
- break;
- }
- }
- if (!found && injector.getParent() != null) {
- return findBinding(injector.getParent(), type);
- }
- return found;
- }
- protected Injector createInjector(List<Module> modules) {
- if (injector != null) {
- return injector;
- }
- Injector root = Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
-
- }
- });
- return root.createChildInjector(Modules.combine(modules));
- }
- protected Injector injector() {
- return injector;
- }
- }