Skip to content

Commit b8ecde7

Browse files
toepimpkorstanje
authored andcommitted
[Java] Use ServiceLoader for ObjectFactory (#1615)
Backport of commit a03dd01 so it is possible to use ServciceLoader for ObjectFactory with 4.x
1 parent 9ed80b6 commit b8ecde7

File tree

25 files changed

+139
-37
lines changed

25 files changed

+139
-37
lines changed

core/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>io.cucumber</groupId>
66
<artifactId>cucumber-jvm</artifactId>
7-
<version>4.3.2-SNAPSHOT</version>
7+
<version>4.4.0-SNAPSHOT</version>
88
</parent>
99

1010
<artifactId>cucumber-core</artifactId>

core/src/main/java/cucumber/runtime/TooManyInstancesException.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
public class TooManyInstancesException extends CucumberException {
66

7-
TooManyInstancesException(Collection instances) {
7+
public TooManyInstancesException(Collection instances) {
88
super(createMessage(instances));
99
}
1010

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package io.cucumber.core.backend;
2+
3+
/**
4+
* Minimal facade for Dependency Injection containers
5+
*/
6+
public interface ObjectFactory {
7+
8+
/**
9+
* Instantiate glue code <b>before</b> scenario execution. Called once per
10+
* scenario.
11+
*/
12+
void start();
13+
14+
/**
15+
* Dispose glue code <b>after</b> scenario execution. Called once per
16+
* scenario.
17+
*/
18+
void stop();
19+
20+
/**
21+
* Collects glue classes in the classpath. Called once on init.
22+
*
23+
* @param glueClass Glue class containing cucumber.api annotations (Before,
24+
* Given, When, ...)
25+
* @return true if stepdefs and hooks in this class should be used, false if
26+
* they should be ignored.
27+
*/
28+
boolean addClass(Class<?> glueClass);
29+
30+
/**
31+
* Provides the glue instances used to execute the current scenario. The
32+
* instance can be prepared in {@link #start()}.
33+
*
34+
* @param glueClass type of instance to be created.
35+
* @param <T> type of Glue class
36+
* @return new Glue instance of type T
37+
*/
38+
<T> T getInstance(Class<T> glueClass);
39+
40+
}

examples/java-calculator-testng/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>io.cucumber</groupId>
66
<artifactId>cucumber-examples</artifactId>
7-
<version>4.3.2-SNAPSHOT</version>
7+
<version>4.4.0-SNAPSHOT</version>
88
</parent>
99

1010
<artifactId>java-calculator-testng</artifactId>

examples/java-calculator/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>io.cucumber</groupId>
66
<artifactId>cucumber-examples</artifactId>
7-
<version>4.3.2-SNAPSHOT</version>
7+
<version>4.4.0-SNAPSHOT</version>
88
</parent>
99

1010
<artifactId>java-calculator</artifactId>

examples/java-wicket/java-wicket-main/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<parent>
44
<groupId>io.cucumber</groupId>
55
<artifactId>java-wicket</artifactId>
6-
<version>4.3.2-SNAPSHOT</version>
6+
<version>4.4.0-SNAPSHOT</version>
77
</parent>
88
<artifactId>java-wicket-main</artifactId>
99
<name>Examples: Wicket application</name>

examples/java-wicket/java-wicket-test/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<parent>
44
<groupId>io.cucumber</groupId>
55
<artifactId>java-wicket</artifactId>
6-
<version>4.3.2-SNAPSHOT</version>
6+
<version>4.4.0-SNAPSHOT</version>
77
</parent>
88
<artifactId>java-wicket-test</artifactId>
99
<name>Examples: Wicket application tested with Selenium</name>

examples/java-wicket/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<parent>
44
<groupId>io.cucumber</groupId>
55
<artifactId>cucumber-examples</artifactId>
6-
<version>4.3.2-SNAPSHOT</version>
6+
<version>4.4.0-SNAPSHOT</version>
77
</parent>
88
<artifactId>java-wicket</artifactId>
99
<packaging>pom</packaging>

examples/java8-calculator/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>io.cucumber</groupId>
66
<artifactId>cucumber-examples</artifactId>
7-
<version>4.3.2-SNAPSHOT</version>
7+
<version>4.4.0-SNAPSHOT</version>
88
</parent>
99

1010
<artifactId>java8-calculator</artifactId>

examples/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>io.cucumber</groupId>
66
<artifactId>cucumber-jvm</artifactId>
7-
<version>4.3.2-SNAPSHOT</version>
7+
<version>4.4.0-SNAPSHOT</version>
88
</parent>
99

1010
<artifactId>cucumber-examples</artifactId>

examples/spring-txn/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>io.cucumber</groupId>
66
<artifactId>cucumber-examples</artifactId>
7-
<version>4.3.2-SNAPSHOT</version>
7+
<version>4.4.0-SNAPSHOT</version>
88
</parent>
99

1010
<artifactId>spring-txn</artifactId>

guice/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>io.cucumber</groupId>
66
<artifactId>cucumber-jvm</artifactId>
7-
<version>4.3.2-SNAPSHOT</version>
7+
<version>4.4.0-SNAPSHOT</version>
88
</parent>
99

1010
<artifactId>cucumber-guice</artifactId>

java/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>io.cucumber</groupId>
66
<artifactId>cucumber-jvm</artifactId>
7-
<version>4.3.2-SNAPSHOT</version>
7+
<version>4.4.0-SNAPSHOT</version>
88
</parent>
99

1010
<artifactId>cucumber-java</artifactId>

java/src/main/java/cucumber/api/java/ObjectFactory.java

+3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
/**
44
* Minimal facade for Dependency Injection containers
5+
*
6+
* @deprecated use @code io.cucumber.core.backend.ObjectFactory instead
57
*/
8+
@Deprecated
69
public interface ObjectFactory {
710

811
/**

java/src/main/java/cucumber/runtime/java/ObjectFactoryLoader.java

+74-15
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,15 @@
1313
import java.util.List;
1414

1515
import static java.util.Arrays.asList;
16+
import java.util.Collection;
17+
import java.util.HashSet;
18+
import java.util.Iterator;
19+
import java.util.Objects;
20+
import java.util.ServiceLoader;
1621

17-
public class ObjectFactoryLoader {
22+
public final class ObjectFactoryLoader {
1823

19-
private static final Logger log = LoggerFactory.getLogger(ObjectFactoryLoader.class);
24+
private static final Logger LOG = LoggerFactory.getLogger(ObjectFactoryLoader.class);
2025

2126
private ObjectFactoryLoader() {
2227
}
@@ -30,27 +35,50 @@ private ObjectFactoryLoader() {
3035
* @return an instance of {@link ObjectFactory}
3136
*/
3237
public static ObjectFactory loadObjectFactory(ClassFinder classFinder, String objectFactoryClassName) {
33-
ObjectFactory objectFactory;
3438
try {
35-
Reflections reflections = new Reflections(classFinder);
36-
37-
if (objectFactoryClassName != null) {
38-
Class<ObjectFactory> objectFactoryClass = (Class<ObjectFactory>) classFinder.loadClass(objectFactoryClassName);
39-
objectFactory = reflections.newInstance(new Class[0], new Object[0], objectFactoryClass);
39+
final Reflections reflections = new Reflections(classFinder);
40+
if (objectFactoryClassName == null) {
41+
return loadSingleObjectFactory(reflections);
4042
} else {
41-
List<URI> packages = asList(URI.create("classpath:cucumber/runtime"));
42-
objectFactory = reflections.instantiateExactlyOneSubclass(ObjectFactory.class, packages, new Class[0], new Object[0], null);
43+
return loadSelectedObjectFactory(reflections, classFinder, objectFactoryClassName);
4344
}
4445
} catch (TooManyInstancesException e) {
45-
log.warn(e.getMessage());
46-
log.warn(getMultipleObjectFactoryLogMessage());
47-
objectFactory = new DefaultJavaObjectFactory();
46+
LOG.warn(e.getMessage());
47+
LOG.warn(getMultipleObjectFactoryLogMessage());
48+
return new DefaultJavaObjectFactory();
4849
} catch (NoInstancesException e) {
49-
objectFactory = new DefaultJavaObjectFactory();
50+
return new DefaultJavaObjectFactory();
5051
} catch (ClassNotFoundException e) {
5152
throw new CucumberException("Couldn't instantiate custom ObjectFactory", e);
5253
}
53-
return objectFactory;
54+
}
55+
56+
private static ObjectFactory loadSingleObjectFactory(final Reflections reflections) {
57+
Iterator<io.cucumber.core.backend.ObjectFactory> serviceLoaderObjectFactories = ServiceLoader.load(io.cucumber.core.backend.ObjectFactory.class).iterator();
58+
if (serviceLoaderObjectFactories.hasNext()) {
59+
final Collection<io.cucumber.core.backend.ObjectFactory> instances = new HashSet<>();
60+
do {
61+
instances.add(serviceLoaderObjectFactories.next());
62+
} while (serviceLoaderObjectFactories.hasNext());
63+
if (instances.size() > 1) {
64+
throw new TooManyInstancesException(instances);
65+
}
66+
return new ObjectFactoryAdapter(instances.iterator().next());
67+
} else {
68+
LOG.warn("Use deprecated reflections to load ObjectFactory.");
69+
final List<URI> packages = asList(URI.create("classpath:cucumber/runtime"));
70+
return reflections.instantiateExactlyOneSubclass(ObjectFactory.class, packages, new Class[0], new Object[0], null);
71+
}
72+
}
73+
74+
private static ObjectFactory loadSelectedObjectFactory(final Reflections reflections, final ClassFinder classFinder, final String objectFactoryClassName) throws ClassNotFoundException {
75+
final Iterator<? extends io.cucumber.core.backend.ObjectFactory> serviceLoaderObjectFactories = ServiceLoader.load(classFinder.<io.cucumber.core.backend.ObjectFactory>loadClass(objectFactoryClassName)).iterator();
76+
if (serviceLoaderObjectFactories.hasNext()) {
77+
return new ObjectFactoryAdapter(serviceLoaderObjectFactories.next());
78+
} else {
79+
LOG.warn("Use deprecated reflections to load requested ObjectFactory.");
80+
return reflections.newInstance(new Class[0], new Object[0], classFinder.<ObjectFactory>loadClass(objectFactoryClassName));
81+
}
5482
}
5583

5684
private static String getMultipleObjectFactoryLogMessage() {
@@ -62,4 +90,35 @@ private static String getMultipleObjectFactoryLogMessage() {
6290
sb.append("In order to enjoy IoC features, please remove the unnecessary dependencies from your classpath.\n");
6391
return sb.toString();
6492
}
93+
94+
private static class ObjectFactoryAdapter implements ObjectFactory {
95+
96+
private final io.cucumber.core.backend.ObjectFactory delegate;
97+
98+
public ObjectFactoryAdapter(final io.cucumber.core.backend.ObjectFactory delegate) {
99+
this.delegate = Objects.requireNonNull(delegate);
100+
}
101+
102+
@Override
103+
public void start() {
104+
delegate.start();
105+
}
106+
107+
@Override
108+
public void stop() {
109+
delegate.stop();
110+
}
111+
112+
@Override
113+
public boolean addClass(Class<?> arg0) {
114+
return delegate.addClass(arg0);
115+
}
116+
117+
@Override
118+
public <T> T getInstance(Class<T> arg0) {
119+
return delegate.getInstance(arg0);
120+
}
121+
122+
}
123+
65124
}

java8/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>io.cucumber</groupId>
66
<artifactId>cucumber-jvm</artifactId>
7-
<version>4.3.2-SNAPSHOT</version>
7+
<version>4.4.0-SNAPSHOT</version>
88
</parent>
99

1010
<artifactId>cucumber-java8</artifactId>

junit/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>io.cucumber</groupId>
66
<artifactId>cucumber-jvm</artifactId>
7-
<version>4.3.2-SNAPSHOT</version>
7+
<version>4.4.0-SNAPSHOT</version>
88
</parent>
99

1010
<artifactId>cucumber-junit</artifactId>

kotlin-java8/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>io.cucumber</groupId>
66
<artifactId>cucumber-jvm</artifactId>
7-
<version>4.3.2-SNAPSHOT</version>
7+
<version>4.4.0-SNAPSHOT</version>
88
</parent>
99

1010
<artifactId>cucumber-kotlin-java8</artifactId>

needle/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>io.cucumber</groupId>
66
<artifactId>cucumber-jvm</artifactId>
7-
<version>4.3.2-SNAPSHOT</version>
7+
<version>4.4.0-SNAPSHOT</version>
88
</parent>
99

1010
<artifactId>cucumber-needle</artifactId>

openejb/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>io.cucumber</groupId>
66
<artifactId>cucumber-jvm</artifactId>
7-
<version>4.3.2-SNAPSHOT</version>
7+
<version>4.4.0-SNAPSHOT</version>
88
</parent>
99

1010
<artifactId>cucumber-openejb</artifactId>

picocontainer/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>io.cucumber</groupId>
66
<artifactId>cucumber-jvm</artifactId>
7-
<version>4.3.2-SNAPSHOT</version>
7+
<version>4.4.0-SNAPSHOT</version>
88
</parent>
99

1010
<artifactId>cucumber-picocontainer</artifactId>

pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<version>1.0.3</version>
77
</parent>
88
<artifactId>cucumber-jvm</artifactId>
9-
<version>4.3.2-SNAPSHOT</version>
9+
<version>4.4.0-SNAPSHOT</version>
1010
<packaging>pom</packaging>
1111
<name>Cucumber-JVM</name>
1212
<description>Cucumber for the JVM</description>

spring/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>io.cucumber</groupId>
66
<artifactId>cucumber-jvm</artifactId>
7-
<version>4.3.2-SNAPSHOT</version>
7+
<version>4.4.0-SNAPSHOT</version>
88
</parent>
99

1010
<artifactId>cucumber-spring</artifactId>

testng/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>io.cucumber</groupId>
66
<artifactId>cucumber-jvm</artifactId>
7-
<version>4.3.2-SNAPSHOT</version>
7+
<version>4.4.0-SNAPSHOT</version>
88
</parent>
99

1010
<artifactId>cucumber-testng</artifactId>

weld/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>io.cucumber</groupId>
66
<artifactId>cucumber-jvm</artifactId>
7-
<version>4.3.2-SNAPSHOT</version>
7+
<version>4.4.0-SNAPSHOT</version>
88
</parent>
99

1010
<artifactId>cucumber-weld</artifactId>

0 commit comments

Comments
 (0)