ScanningStepsFactory.java

  1. package org.jbehave.core.steps;

  2. import java.lang.annotation.Annotation;
  3. import java.lang.reflect.Method;
  4. import java.util.ArrayList;
  5. import java.util.HashSet;
  6. import java.util.List;
  7. import java.util.Set;

  8. import org.jbehave.core.annotations.AfterScenario;
  9. import org.jbehave.core.annotations.AfterStories;
  10. import org.jbehave.core.annotations.AfterStory;
  11. import org.jbehave.core.annotations.BeforeScenario;
  12. import org.jbehave.core.annotations.BeforeStories;
  13. import org.jbehave.core.annotations.BeforeStory;
  14. import org.jbehave.core.annotations.Given;
  15. import org.jbehave.core.annotations.Then;
  16. import org.jbehave.core.annotations.When;
  17. import org.jbehave.core.configuration.Configuration;
  18. import org.junit.After;
  19. import org.junit.Before;
  20. import org.reflections.Reflections;
  21. import org.reflections.ReflectionsException;
  22. import org.reflections.scanners.MethodAnnotationsScanner;

  23. /**
  24.  * An {@link InjectableStepsFactory} that scans for classes in the classpath.
  25.  * The constructors allows the specification of the package names to scan or the
  26.  * root class from which the package name is derived. All classes that include
  27.  * any step method annotation ({@link Given}, {@link When}, {@link Then},
  28.  * {@link Before}, {@link After}, etc ... ) will be collected in the scan.
  29.  * Additional regex filters on the class names are provided via the
  30.  * {@link #matchingNames(String)} and {@link #notMatchingNames(String)} methods,
  31.  * which by default match all names.
  32.  */
  33. public class ScanningStepsFactory extends AbstractStepsFactory {

  34.     private final Set<Class<?>> types = new HashSet<>();
  35.     private String matchingRegex = ".*";
  36.     private String notMatchingRegex = "";

  37.     public ScanningStepsFactory(Configuration configuration, Class<?> root) {
  38.         this(configuration, root.getPackage().getName());
  39.     }

  40.     public ScanningStepsFactory(Configuration configuration,
  41.             String... packageNames) {
  42.         super(configuration);
  43.         for (String packageName : packageNames) {
  44.             types.addAll(scanTypes(packageName));
  45.         }
  46.     }

  47.     public ScanningStepsFactory matchingNames(String matchingRegex) {
  48.         this.matchingRegex = matchingRegex;
  49.         return this;
  50.     }

  51.     public ScanningStepsFactory notMatchingNames(String notMatchingRegex) {
  52.         this.notMatchingRegex = notMatchingRegex;
  53.         return this;
  54.     }

  55.     private Set<Class<?>> scanTypes(String packageName) {
  56.         Reflections reflections = new Reflections(packageName,
  57.                 new MethodAnnotationsScanner());
  58.         Set<Class<?>> types = new HashSet<>();
  59.         types.addAll(typesAnnotatedWith(reflections, Given.class));
  60.         types.addAll(typesAnnotatedWith(reflections, When.class));
  61.         types.addAll(typesAnnotatedWith(reflections, Then.class));
  62.         types.addAll(typesAnnotatedWith(reflections, Before.class));
  63.         types.addAll(typesAnnotatedWith(reflections, After.class));
  64.         types.addAll(typesAnnotatedWith(reflections, BeforeScenario.class));
  65.         types.addAll(typesAnnotatedWith(reflections, AfterScenario.class));
  66.         types.addAll(typesAnnotatedWith(reflections, BeforeStory.class));
  67.         types.addAll(typesAnnotatedWith(reflections, AfterStory.class));
  68.         types.addAll(typesAnnotatedWith(reflections, BeforeStories.class));
  69.         types.addAll(typesAnnotatedWith(reflections, AfterStories.class));
  70.         return types;
  71.     }

  72.     private Set<Class<?>> typesAnnotatedWith(Reflections reflections,
  73.             Class<? extends Annotation> annotation) {
  74.         Set<Class<?>> types = new HashSet<>();
  75.         try {
  76.             Set<Method> methodsAnnotatedWith = reflections.getMethodsAnnotatedWith(annotation);
  77.             for (Method method : methodsAnnotatedWith) {
  78.                 types.add(method.getDeclaringClass());
  79.             }
  80.         } catch (ReflectionsException e) {
  81.             // https://github.com/ronmamo/reflections/issues/297
  82.             if (!"Scanner MethodAnnotationsScanner was not configured".equals(e.getMessage())) {
  83.                 throw e;
  84.             }
  85.         }
  86.         return types;
  87.     }

  88.     @Override
  89.     protected List<Class<?>> stepsTypes() {
  90.         List<Class<?>> matchingTypes = new ArrayList<>();
  91.         for (Class<?> type : types) {
  92.             String name = type.getName();
  93.             if (name.matches(matchingRegex) && !name.matches(notMatchingRegex)) {
  94.                 matchingTypes.add(type);
  95.             }
  96.         }
  97.         return matchingTypes;
  98.     }

  99.     @Override
  100.     public Object createInstanceOfType(Class<?> type) {
  101.         Object instance;
  102.         try {
  103.             instance = type.newInstance();
  104.         } catch (Exception e) {
  105.             throw new StepsInstanceNotFound(type, this);
  106.         }
  107.         return instance;
  108.     }

  109. }