Skip to content

Commit

Permalink
[Needle] Move ObjectFactory to io.cucumber.needle
Browse files Browse the repository at this point in the history
  • Loading branch information
mpkorstanje committed Jun 16, 2019
1 parent 1659ef8 commit 4f2ded5
Show file tree
Hide file tree
Showing 39 changed files with 238 additions and 215 deletions.
1 change: 1 addition & 0 deletions needle/pom.xml
Expand Up @@ -12,6 +12,7 @@
<name>Cucumber-JVM: Needle</name>

<properties>
<project.Automatic-Module-Name>io.cucumber.needle</project.Automatic-Module-Name>
<needle.version>2.2</needle.version>
<javaee-api.version>7.0</javaee-api.version>
<javax.inject.version>1</javax.inject.version>
Expand Down
@@ -1,22 +1,11 @@
package cucumber.api.needle;

import cucumber.runtime.java.needle.NeedleFactory;
import de.akquinet.jbosscc.needle.NeedleTestcase;
import de.akquinet.jbosscc.needle.injection.InjectionProvider;

import java.util.Set;

/**
* <a href="http://javadocs.techempower.com/jdk18/api/java/util/function/Supplier.html">Supplies</a> a Set of
* InjectionProvider instances that are created outside the {@link NeedleFactory} lifecycle.
* InjectionProvider instances that are created outside the {@link io.cucumber.needle.NeedleFactory} lifecycle.
* @deprecated use {@code io.cucumber.needle.api.InjectionProviderInstancesSupplier} instead
*/
public interface InjectionProviderInstancesSupplier {
@Deprecated
public interface InjectionProviderInstancesSupplier extends io.cucumber.needle.InjectionProviderInstancesSupplier {

/**
* <a href="http://javadocs.techempower.com/jdk18/api/java/util/function/Supplier.html">Supplies</a> a Set of
* InjectionProvider instances that are created outside the {@link NeedleFactory} lifecycle.
*
* @return InjectionProviders that can be added to {@link NeedleTestcase}
*/
Set<InjectionProvider<?>> get();
}
Expand Up @@ -10,9 +10,11 @@
/**
* Annotation to mark InjectionProviders in the cucumber glue or cucumber steps.
* Should be placed on fields of type {@link InjectionProvider} or an array of those.
*
* @deprecated use {@code NeedleInjectionProvider} instead
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Deprecated
public @interface NeedleInjectionProvider {
// Nothing here
}

This file was deleted.

@@ -0,0 +1,71 @@
package io.cucumber.needle;

import de.akquinet.jbosscc.needle.injection.InjectionProvider;
import de.akquinet.jbosscc.needle.reflection.ReflectionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;

/**
* Collects {@link InjectionProvider} instances.
*/
enum CollectInjectionProvidersFromStepsInstance {
/**
* stateless Singleton
*/
INSTANCE;

/**
* Logger for the factory.
*/
private final Logger logger = LoggerFactory.getLogger(NeedleFactory.class);

/**
* Collect providers direct in the step definition.
*
* @param instance step definition instance
* @return collected injection providers.
*/
final <T> InjectionProvider<?>[] apply(final T instance) {
final Set<InjectionProvider<?>> allProviders = new LinkedHashSet<>();
for (final Field field : ReflectionUtil.getAllFieldsWithAnnotation(instance, NeedleInjectionProvider.class)) {
final Set<InjectionProvider<?>> providers = getInjectionProviders(field, instance);
allProviders.addAll(providers);
}
for (final Field field : ReflectionUtil.getAllFieldsWithAnnotation(instance, cucumber.api.needle.NeedleInjectionProvider.class)) {
final Set<InjectionProvider<?>> providers = getInjectionProviders(field, instance);
allProviders.addAll(providers);
}
if (logger.isTraceEnabled()) {
logger.trace("Adding {} InjectionProvider instances.", allProviders.size());
}

return allProviders.toArray(new InjectionProvider<?>[0]);
}

private <T> Set<InjectionProvider<?>> getInjectionProviders(Field field, T instance) {
final Set<InjectionProvider<?>> providers = new LinkedHashSet<>();
field.setAccessible(true);
try {
final Object value = field.get(instance);
if (value instanceof InjectionProvider<?>[]) {
providers.addAll(Arrays.asList((InjectionProvider<?>[]) value));
} else if (value instanceof InjectionProvider) {
providers.add((InjectionProvider<?>) value);
} else if (value instanceof InjectionProviderInstancesSupplier) {
providers.addAll(((InjectionProviderInstancesSupplier) value).get());
} else {
throw new IllegalStateException("Fields annotated with NeedleInjectionProviders must be of type "
+ "InjectionProviderInstancesSupplier, InjectionProvider " + "or InjectionProvider[]");
}
} catch (final Exception e) {
throw new IllegalStateException(e);
}
return providers;
}

}
@@ -1,23 +1,23 @@
package cucumber.runtime.java.needle.config;
package io.cucumber.needle;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Instantiates new java object by default constructor
*/
public enum CreateInstanceByDefaultConstructor {
enum CreateInstanceByDefaultConstructor {
/**
* Singleton
*/
INSTANCE;

private final Logger logger = LoggerFactory.getLogger(this.getClass());

public final <T> T apply(final Class<T> type) {
final <T> T apply(final Class<T> type) {
try {
final T newInstance = type.getConstructor().newInstance();
logger.debug("newInstance by DefaultConstructor: " + newInstance);
logger.debug("newInstance by DefaultConstructor: {}", newInstance);
return newInstance;
} catch (final Exception e) {
throw new IllegalStateException("Can not instantiate Instance by Default Constructor.", e);
Expand Down
@@ -1,9 +1,6 @@
package cucumber.runtime.java.needle.config;
package io.cucumber.needle;

import cucumber.api.needle.InjectionProviderInstancesSupplier;
import de.akquinet.jbosscc.needle.injection.InjectionProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashSet;
import java.util.ResourceBundle;
Expand All @@ -12,35 +9,29 @@
/**
* Reads cucumber-needle.properties to initialize additional {@link InjectionProvider}s.
*/
public class CucumberNeedleConfiguration {
class CucumberNeedleConfiguration {
/**
* Default properties fiel name.
*/
public static final String RESOURCE_CUCUMBER_NEEDLE = "cucumber-needle";
static final String RESOURCE_CUCUMBER_NEEDLE = "cucumber-needle";

@SuppressWarnings("unused")
private final Logger logger = LoggerFactory.getLogger(this.getClass());

private final LoadResourceBundle loadResourceBundle = LoadResourceBundle.INSTANCE;
private final ReadInjectionProviderClassNames readInjectionProviderClassNames = ReadInjectionProviderClassNames.INSTANCE;
private final CreateInstanceByDefaultConstructor createInstance = CreateInstanceByDefaultConstructor.INSTANCE;

private final Set<InjectionProvider<?>> injectionProviders = new HashSet<InjectionProvider<?>>();
private final Set<InjectionProvider<?>> injectionProviders = new HashSet<>();

/**
* Creates new instance from default resource {@link #RESOURCE_CUCUMBER_NEEDLE}.
*/
public CucumberNeedleConfiguration() {
CucumberNeedleConfiguration() {
this(RESOURCE_CUCUMBER_NEEDLE);
}

public CucumberNeedleConfiguration(final String resourceName) {
final ResourceBundle resourceBundle = loadResourceBundle.apply(resourceName);
final Set<String> classNames = readInjectionProviderClassNames.apply(resourceBundle);
CucumberNeedleConfiguration(final String resourceName) {
final ResourceBundle resourceBundle = LoadResourceBundle.INSTANCE.apply(resourceName);
final Set<String> classNames = ReadInjectionProviderClassNames.INSTANCE.apply(resourceBundle);

for (final String className : classNames) {
try {
final Class<?> clazz = Class.forName(className);
CreateInstanceByDefaultConstructor createInstance = CreateInstanceByDefaultConstructor.INSTANCE;
if (isInjectionProvider(clazz)) {
injectionProviders.add((InjectionProvider<?>) createInstance.apply(clazz));
} else if (isInjectionProviderInstanceSupplier(clazz)) {
Expand All @@ -57,8 +48,8 @@ public CucumberNeedleConfiguration(final String resourceName) {
}
}

public InjectionProvider<?>[] getInjectionProviders() {
return injectionProviders.toArray(new InjectionProvider<?>[injectionProviders.size()]);
InjectionProvider<?>[] getInjectionProviders() {
return injectionProviders.toArray(new InjectionProvider<?>[0]);
}

/**
Expand Down
@@ -0,0 +1,21 @@
package io.cucumber.needle;

import de.akquinet.jbosscc.needle.NeedleTestcase;
import de.akquinet.jbosscc.needle.injection.InjectionProvider;

import java.util.Set;

/**
* <a href="http://javadocs.techempower.com/jdk18/api/java/util/function/Supplier.html">Supplies</a> a Set of
* InjectionProvider instances that are created outside the {@link NeedleFactory} lifecycle.
*/
public interface InjectionProviderInstancesSupplier {

/**
* <a href="http://javadocs.techempower.com/jdk18/api/java/util/function/Supplier.html">Supplies</a> a Set of
* InjectionProvider instances that are created outside the {@link NeedleFactory} lifecycle.
*
* @return InjectionProviders that can be added to {@link NeedleTestcase}
*/
Set<InjectionProvider<?>> get();
}
@@ -1,4 +1,4 @@
package cucumber.runtime.java.needle.config;
package io.cucumber.needle;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -10,7 +10,7 @@
/**
* Null safe Resource Loader. If ResourceBundle does not exist, an empty Bundle is returned.
*/
public enum LoadResourceBundle {
enum LoadResourceBundle {
INSTANCE;

public static final ResourceBundle EMPTY_RESOURCE_BUNDLE = new ResourceBundle() {
Expand Down
@@ -1,37 +1,33 @@
package cucumber.runtime.java.needle;
package io.cucumber.needle;

import cucumber.runtime.java.needle.config.CollectInjectionProvidersFromStepsInstance;
import cucumber.runtime.java.needle.config.CreateInstanceByDefaultConstructor;
import cucumber.runtime.java.needle.config.CucumberNeedleConfiguration;
import io.cucumber.core.backend.ObjectFactory;
import de.akquinet.jbosscc.needle.NeedleTestcase;
import de.akquinet.jbosscc.needle.injection.InjectionProvider;
import io.cucumber.core.backend.ObjectFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.LinkedHashMap;
import java.util.Map;

import static cucumber.runtime.java.needle.config.CucumberNeedleConfiguration.RESOURCE_CUCUMBER_NEEDLE;
import static java.lang.String.format;

/**
* Needle factory for object resolution inside of cucumber tests.
*/
public class NeedleFactory extends NeedleTestcase implements ObjectFactory {
public final class NeedleFactory extends NeedleTestcase implements ObjectFactory {

private final Map<Class<?>, Object> cachedStepsInstances = new LinkedHashMap<Class<?>, Object>();
private final Map<Class<?>, Object> cachedStepsInstances = new LinkedHashMap<>();
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final CreateInstanceByDefaultConstructor createInstanceByDefaultConstructor = CreateInstanceByDefaultConstructor.INSTANCE;
private final CollectInjectionProvidersFromStepsInstance collectInjectionProvidersFromStepsInstance = CollectInjectionProvidersFromStepsInstance.INSTANCE;

public NeedleFactory() {
super(setUpInjectionProviders(RESOURCE_CUCUMBER_NEEDLE));
super(setUpInjectionProviders());
}

@Override
public <T> T getInstance(final Class<T> type) {
logger.trace("getInstance: " + type.getCanonicalName());
logger.trace("getInstance: {}", type.getCanonicalName());
assertTypeHasBeenAdded(type);
return nullSafeGetInstance(type);
}
Expand Down Expand Up @@ -67,7 +63,7 @@ public void stop() {

@Override
public boolean addClass(final Class<?> type) {
logger.trace("addClass(): " + type.getCanonicalName());
logger.trace("addClass(): {}", type.getCanonicalName());

// build up cache keys ...
if (!cachedStepsInstances.containsKey(type)) {
Expand All @@ -92,12 +88,12 @@ private <T> T nullSafeGetInstance(final Class<T> type) {
return (T) instance;
}

private <T> T createStepsInstance(final Class<T> type) throws Exception {
logger.trace("createInstance(): " + type.getCanonicalName());
private <T> T createStepsInstance(final Class<T> type) {
logger.trace("createInstance(): {}", type.getCanonicalName());
return createInstanceByDefaultConstructor.apply(type);
}

static InjectionProvider<?>[] setUpInjectionProviders(final String resourceName) {
return new CucumberNeedleConfiguration(resourceName).getInjectionProviders();
static InjectionProvider<?>[] setUpInjectionProviders() {
return new CucumberNeedleConfiguration().getInjectionProviders();
}
}

0 comments on commit 4f2ded5

Please sign in to comment.