Skip to content

Commit a03dd01

Browse files
nhojpatrickmpkorstanje
authored andcommitted
[Java] Use ServiceLoader for ObjectFactory
Closes: #1463 Fixes: #1450
1 parent 27f9b33 commit a03dd01

File tree

8 files changed

+56
-34
lines changed

8 files changed

+56
-34
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
io.cucumber.guice.GuiceFactory

java/src/main/java/io/cucumber/java/JavaBackend.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public JavaBackend(ResourceLoader resourceLoader, TypeRegistry typeRegistry) {
5454
}
5555

5656
private JavaBackend(ClassFinder classFinder, TypeRegistry typeRegistry) {
57-
this(loadObjectFactory(classFinder, Env.INSTANCE.get(ObjectFactory.class.getName())), classFinder, typeRegistry);
57+
this(loadObjectFactory(Env.INSTANCE.get(ObjectFactory.class.getName())), classFinder, typeRegistry);
5858
}
5959

6060
public JavaBackend(ObjectFactory objectFactory, ClassFinder classFinder, TypeRegistry typeRegistry) {
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,72 @@
11
package io.cucumber.java;
22

3-
import io.cucumber.java.api.ObjectFactory;
4-
import io.cucumber.core.io.ClassFinder;
53
import io.cucumber.core.exception.CucumberException;
6-
import io.cucumber.core.reflection.NoInstancesException;
7-
import io.cucumber.core.reflection.Reflections;
8-
import io.cucumber.core.reflection.TooManyInstancesException;
4+
import io.cucumber.java.api.ObjectFactory;
95

10-
import static java.util.Arrays.asList;
6+
import java.util.Iterator;
7+
import java.util.ServiceLoader;
118

129
class ObjectFactoryLoader {
1310
private ObjectFactoryLoader() {
1411
}
1512

1613
/**
17-
* Loads an instance of {@link ObjectFactory}. The class name can be explicit, or it can be null.
18-
* When it's null, the implementation is searched for in the <pre>cucumber.runtime</pre> packahe.
14+
* Loads an instance of {@link ObjectFactory} using the {@link ServiceLoader}.
15+
* When <code>objectFactoryClassName</code> is provided that object factory
16+
* will be used if present.
17+
* <p>
18+
* If <code>objectFactoryClassName</code> is not provided and there exactly one
19+
* instance present that instance will be used.
20+
* <p>
21+
* Otherwise a default object factory with no Dependency Injection capabilities
22+
* will be used.
1923
*
20-
* @param classFinder where to load classes from
21-
* @param objectFactoryClassName specific class name of {@link ObjectFactory} implementation. May be null.
24+
* @param objectFactoryClassName optional object factory to use
2225
* @return an instance of {@link ObjectFactory}
2326
*/
24-
static ObjectFactory loadObjectFactory(ClassFinder classFinder, String objectFactoryClassName) {
25-
ObjectFactory objectFactory;
26-
try {
27-
Reflections reflections = new Reflections(classFinder);
28-
29-
if(objectFactoryClassName != null) {
30-
Class<ObjectFactory> objectFactoryClass = (Class<ObjectFactory>) classFinder.loadClass(objectFactoryClassName);
31-
objectFactory = reflections.newInstance(new Class[0], new Object[0], objectFactoryClass);
32-
} else {
33-
objectFactory = reflections.instantiateExactlyOneSubclass(ObjectFactory.class, asList("io.cucumber"), new Class[0], new Object[0], null);
27+
static ObjectFactory loadObjectFactory(String objectFactoryClassName) {
28+
final ServiceLoader<ObjectFactory> loader = ServiceLoader.load(ObjectFactory.class);
29+
if (objectFactoryClassName == null) {
30+
return loadSingleObjectFactoryOrDefault(loader);
31+
32+
}
33+
34+
return loadSelectedObjectFactory(loader, objectFactoryClassName);
35+
}
36+
37+
private static ObjectFactory loadSelectedObjectFactory(ServiceLoader<ObjectFactory> loader, String objectFactoryClassName) {
38+
for (ObjectFactory objectFactory : loader) {
39+
if (objectFactoryClassName.equals(objectFactory.getClass().getName())) {
40+
return objectFactory;
3441
}
35-
} catch (TooManyInstancesException e) {
36-
System.out.println(e.getMessage());
37-
System.out.println(getMultipleObjectFactoryLogMessage());
42+
}
43+
44+
throw new CucumberException("Could not find object factory " + objectFactoryClassName);
45+
}
46+
47+
private static ObjectFactory loadSingleObjectFactoryOrDefault(ServiceLoader<ObjectFactory> loader) {
48+
final Iterator<ObjectFactory> objectFactories = loader.iterator();
49+
50+
ObjectFactory objectFactory;
51+
if (objectFactories.hasNext()) {
52+
objectFactory = objectFactories.next();
53+
} else {
3854
objectFactory = new DefaultJavaObjectFactory();
39-
} catch (NoInstancesException e) {
55+
}
56+
57+
if (objectFactories.hasNext()) {
58+
System.out.println(getMultipleObjectFactoryLogMessage());
4059
objectFactory = new DefaultJavaObjectFactory();
41-
} catch (ClassNotFoundException e) {
42-
throw new CucumberException("Couldn't instantiate custom ObjectFactory", e);
4360
}
4461
return objectFactory;
4562
}
4663

4764
private static String getMultipleObjectFactoryLogMessage() {
48-
StringBuilder sb = new StringBuilder();
49-
sb.append("More than one Cucumber ObjectFactory was found in the classpath\n\n");
50-
sb.append("You probably may have included, for instance, cucumber-spring AND cucumber-guice as part of\n");
51-
sb.append("your dependencies. When this happens, Cucumber falls back to instantiating the\n");
52-
sb.append("DefaultJavaObjectFactory implementation which doesn't provide IoC.\n");
53-
sb.append("In order to enjoy IoC features, please remove the unnecessary dependencies from your classpath.\n");
54-
return sb.toString();
65+
return "More than one Cucumber ObjectFactory was found in the classpath\n" +
66+
"\n" +
67+
"You probably may have included, for instance, cucumber-spring AND cucumber-guice as part of\n" +
68+
"your dependencies. When this happens, Cucumber falls back to instantiating the\n" +
69+
"DefaultJavaObjectFactory implementation which doesn't provide IoC.\n" +
70+
"In order to enjoy IoC features, please remove the unnecessary dependencies from your classpath.\n";
5571
}
5672
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
io.cucumber.needle.NeedleFactory
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
io.cucumber.openejb.OpenEJBObjectFactory
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
io.cucumber.picocontainer.PicoFactory
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
io.cucumber.spring.SpringFactory
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
io.cucumber.weld.WeldFactory

0 commit comments

Comments
 (0)