AbstractStepsFactory.java

  1. package org.jbehave.core.steps;

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

  8. import org.jbehave.core.annotations.AsParameterConverter;
  9. import org.jbehave.core.configuration.Configuration;
  10. import org.jbehave.core.steps.ParameterConverters.MethodReturningConverter;
  11. import org.jbehave.core.steps.ParameterConverters.ParameterConverter;

  12. /**
  13.  * <p>
  14.  * An abstract implementation of {@link InjectableStepsFactory} that is provided
  15.  * by concrete subclasses Object instances which contain the candidate steps
  16.  * methods. The Object instances are wrapped by {@link Steps}.
  17.  * </p>
  18.  * <p>
  19.  * The object instances are also inspected for methods annotated by {@link AsParameterConverter}
  20.  * and the {@link ParameterConverter} is configured accordingly.
  21.  * </p>
  22.  */
  23. public abstract class AbstractStepsFactory implements InjectableStepsFactory {

  24.     private final Configuration configuration;

  25.     public AbstractStepsFactory(Configuration configuration) {
  26.         this.configuration = configuration;
  27.     }

  28.     @Override
  29.     public List<CandidateSteps> createCandidateSteps() {
  30.         List<Class<?>> types = stepsTypes();
  31.         List<CandidateSteps> steps = new ArrayList<>();
  32.         for (Class<?> type : types) {
  33.             configuration.parameterConverters().addConverters(
  34.                     methodReturningConverters(type));
  35.             steps.add(new Steps(configuration, type, this));
  36.         }
  37.         Set<String> compositePaths = configuration.compositePaths();
  38.         if (!compositePaths.isEmpty()) {
  39.             steps.add(new CompositeCandidateSteps(configuration, compositePaths));
  40.         }
  41.         return steps;
  42.     }

  43.     protected abstract List<Class<?>> stepsTypes();

  44.     /**
  45.      * Create parameter converters from methods annotated with @AsParameterConverter
  46.      */
  47.     private List<ParameterConverter> methodReturningConverters(Class<?> type) {
  48.         List<ParameterConverter> converters = new ArrayList<>();

  49.         for (Method method : type.getMethods()) {
  50.             if (method.isAnnotationPresent(AsParameterConverter.class)) {
  51.                 converters.add(new MethodReturningConverter(method, type, this));
  52.             }
  53.         }

  54.         return converters;
  55.     }

  56.     /**
  57.      * Determines if the given type is a {@link Class} containing at least one method
  58.      * annotated with annotations from package "org.jbehave.core.annotations".
  59.      *
  60.      * @param type the Type of the steps instance
  61.      * @return A boolean, <code>true</code> if at least one annotated method is found.
  62.      */
  63.     protected boolean hasAnnotatedMethods(Type type) {
  64.         if (type instanceof Class<?>) {
  65.             for (Method method : ((Class<?>) type).getMethods()) {
  66.                 for (Annotation annotation : method.getAnnotations()) {
  67.                     if (annotation.annotationType().getName().startsWith(
  68.                             "org.jbehave.core.annotations")) {
  69.                         return true;
  70.                     }
  71.                 }
  72.             }
  73.         }
  74.         return false;
  75.     }

  76.     @SuppressWarnings("serial")
  77.     public static class StepsInstanceNotFound extends RuntimeException {

  78.         public StepsInstanceNotFound(Class<?> type, InjectableStepsFactory stepsFactory) {
  79.             super("Steps instance not found for type " + type + " in factory " + stepsFactory);
  80.         }

  81.     }
  82. }