Skip to content

Commit 4de216b

Browse files
committed
Merge branch 'master' into rerun-formatter-exit-code
2 parents f059eb5 + 13ba17a commit 4de216b

File tree

57 files changed

+1078
-138
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+1078
-138
lines changed

History.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
## [1.2.3-SNAPSHOT](https://github.com/cucumber/cucumber-jvm/compare/v1.2.2...master) (In Git)
22

3+
* [OSGi] Cucumber is ready to run in OSGi containers ([#873](https://github.com/cucumber/cucumber-jvm/pull/873), [#799](https://github.com/cucumber/cucumber-jvm/pull/799) @HendrikSP)
4+
* [Core] `cucumber.runtime.java.ObjectFactory` moved to `cucumber.api.java.ObjectFactory`. Custom implementation can
5+
be specified in `cucumber.properties` with `cucumber.api.java.ObjectFactory=my.special.KindOfObjectFactory`. (Closes [#290](https://github.com/cucumber/cucumber-jvm/issues/290) Aslak Hellesøy)
36
* [Core] Properly decode jar URLs with spaces (%20) - ([#866](https://github.com/cucumber/cucumber-jvm/issues/866) Aslak Hellesøy)
47
* [Java] Arity mismatch Java8 Step Definition error ([#852](https://github.com/cucumber/cucumber-jvm/issues/852), [#847](https://github.com/cucumber/cucumber-jvm/pull/847) David Coelho)
58
* [Java] Print Java 8 lambda snippets when `cucumber-java8` is active (Aslak Hellesøy)

android/src/main/java/cucumber/runtime/android/AndroidObjectFactory.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@
55
import android.test.ActivityInstrumentationTestCase2;
66
import android.test.AndroidTestCase;
77
import android.test.InstrumentationTestCase;
8-
import cucumber.runtime.java.ObjectFactory;
8+
import cucumber.api.java.ObjectFactory;
99

1010
/**
11-
* Android specific implementation of {@link cucumber.runtime.java.ObjectFactory} which will
11+
* Android specific implementation of {@link ObjectFactory} which will
1212
* make sure that created test classes have all necessary references to the executing {@link android.app.Instrumentation}
1313
* and the associated {@link android.content.Context}.
1414
*/
1515
public class AndroidObjectFactory implements ObjectFactory {
1616

1717
/**
18-
* The actual {@link cucumber.runtime.java.ObjectFactory} responsible for creating instances.
18+
* The actual {@link ObjectFactory} responsible for creating instances.
1919
*/
2020
private final ObjectFactory delegate;
2121

@@ -25,11 +25,11 @@ public class AndroidObjectFactory implements ObjectFactory {
2525
private final Instrumentation instrumentation;
2626

2727
/**
28-
* Creates a new instance using the given delegate {@link cucumber.runtime.java.ObjectFactory} to
28+
* Creates a new instance using the given delegate {@link ObjectFactory} to
2929
* forward all calls to and using the given {@link android.app.Instrumentation} to set to the instantiated
3030
* android test classes.
3131
*
32-
* @param delegate the {@link cucumber.runtime.java.ObjectFactory} to delegate to
32+
* @param delegate the {@link ObjectFactory} to delegate to
3333
* @param instrumentation the {@link android.app.Instrumentation} to set to the tests
3434
*/
3535
public AndroidObjectFactory(final ObjectFactory delegate, final Instrumentation instrumentation) {

android/src/main/java/cucumber/runtime/android/CucumberExecutor.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@
88
import cucumber.runtime.Backend;
99
import cucumber.runtime.ClassFinder;
1010
import cucumber.runtime.CucumberException;
11+
import cucumber.runtime.Env;
1112
import cucumber.runtime.Runtime;
1213
import cucumber.runtime.RuntimeOptions;
1314
import cucumber.runtime.RuntimeOptionsFactory;
1415
import cucumber.runtime.io.ResourceLoader;
1516
import cucumber.runtime.java.JavaBackend;
16-
import cucumber.runtime.java.ObjectFactory;
17+
import cucumber.api.java.ObjectFactory;
18+
import cucumber.runtime.java.ObjectFactoryLoader;
1719
import cucumber.runtime.model.CucumberFeature;
1820
import dalvik.system.DexFile;
1921
import gherkin.formatter.Formatter;
@@ -155,7 +157,7 @@ private RuntimeOptions createRuntimeOptions(final Context context) {
155157
}
156158

157159
private Collection<? extends Backend> createBackends() {
158-
final ObjectFactory delegateObjectFactory = JavaBackend.loadObjectFactory(classFinder);
160+
final ObjectFactory delegateObjectFactory = ObjectFactoryLoader.loadObjectFactory(classFinder, Env.INSTANCE.get(ObjectFactory.class.getName()));
159161
final AndroidObjectFactory objectFactory = new AndroidObjectFactory(delegateObjectFactory, instrumentation);
160162
final List<Backend> backends = new ArrayList<Backend>();
161163
backends.add(new JavaBackend(objectFactory, classFinder));

android/src/main/java/cucumber/runtime/android/DexClassFinder.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -65,22 +65,22 @@ public <T> Collection<Class<? extends T>> getDescendants(final Class<T> parentTy
6565
while (entries.hasMoreElements()) {
6666
final String className = entries.nextElement();
6767
if (isInPackage(className, packageName) && !isGenerated(className)) {
68-
final Class<? extends T> clazz = loadClass(className);
69-
if (clazz != null && !parentType.equals(clazz) && parentType.isAssignableFrom(clazz)) {
70-
result.add(clazz.asSubclass(parentType));
68+
try {
69+
final Class<? extends T> clazz = loadClass(className);
70+
if (clazz != null && !parentType.equals(clazz) && parentType.isAssignableFrom(clazz)) {
71+
result.add(clazz.asSubclass(parentType));
72+
}
73+
} catch (ClassNotFoundException e) {
74+
throw new CucumberException(e);
7175
}
7276
}
7377
}
7478
return result;
7579
}
7680

77-
@SuppressWarnings("unchecked")
78-
private <T> Class<? extends T> loadClass(final String className) {
79-
try {
80-
return (Class<? extends T>) Class.forName(className, false, CLASS_LOADER);
81-
} catch (final ClassNotFoundException e) {
82-
throw new CucumberException(e);
83-
}
81+
@Override
82+
public <T> Class<? extends T> loadClass(final String className) throws ClassNotFoundException {
83+
return (Class<? extends T>) Class.forName(className, false, CLASS_LOADER);
8484
}
8585

8686
private boolean isInPackage(final String className, final String packageName) {

android/src/test/java/cucumber/runtime/android/AndroidObjectFactoryTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import android.test.ActivityInstrumentationTestCase2;
77
import android.test.AndroidTestCase;
88
import android.test.InstrumentationTestCase;
9-
import cucumber.runtime.java.ObjectFactory;
9+
import cucumber.api.java.ObjectFactory;
1010
import org.junit.Test;
1111
import org.junit.runner.RunWith;
1212
import org.robolectric.RobolectricTestRunner;

core/pom.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
<artifactId>maven-jar-plugin</artifactId>
8787
<configuration>
8888
<archive>
89+
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
8990
<manifest>
9091
<mainClass>cucumber.api.cli.Main</mainClass>
9192
</manifest>
@@ -101,6 +102,18 @@
101102
</configuration>
102103
</plugin>
103104

105+
<plugin>
106+
<groupId>org.apache.felix</groupId>
107+
<artifactId>maven-bundle-plugin</artifactId>
108+
<configuration>
109+
<instructions>
110+
<Bundle-Description></Bundle-Description>
111+
<Export-Package>cucumber.*</Export-Package>
112+
<DynamicImport-Package>*</DynamicImport-Package>
113+
</instructions>
114+
</configuration>
115+
</plugin>
116+
104117
</plugins>
105118
</build>
106119
</project>

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@
44

55
public interface ClassFinder {
66
<T> Collection<Class<? extends T>> getDescendants(Class<T> parentType, String packageName);
7+
8+
<T> Class<? extends T> loadClass(String className) throws ClassNotFoundException;
79
}
Lines changed: 26 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package cucumber.runtime;
22

3+
import java.util.HashMap;
4+
import java.util.Map;
35
import java.util.MissingResourceException;
46
import java.util.Properties;
57
import java.util.ResourceBundle;
@@ -13,8 +15,8 @@
1315
* </ol>
1416
*/
1517
public class Env {
16-
private final String bundleName;
17-
private final Properties properties;
18+
public static final Env INSTANCE = new Env("cucumber");
19+
private final Map<String, String> map = new HashMap<String, String>();
1820

1921
public Env() {
2022
this(null, System.getProperties());
@@ -29,64 +31,41 @@ public Env(Properties properties) {
2931
}
3032

3133
public Env(String bundleName, Properties properties) {
32-
this.bundleName = bundleName;
33-
this.properties = properties;
34-
}
34+
if (bundleName != null) {
35+
try {
36+
ResourceBundle bundle = ResourceBundle.getBundle(bundleName);
37+
for (String key : bundle.keySet()) {
38+
put(key, bundle.getString(key));
39+
}
40+
} catch (MissingResourceException ignore) {
41+
}
42+
}
3543

36-
public String get(String key) {
37-
String result = getFromEnvironment(key);
38-
if (result == null) {
39-
result = getFromProperty(key);
40-
if (result == null && bundleName != null) {
41-
result = getFromBundle(key);
44+
if (properties != null) {
45+
for (String key : properties.stringPropertyNames()) {
46+
put(key, properties.getProperty(key));
4247
}
4348
}
44-
return result;
45-
}
4649

47-
private String getFromEnvironment(String key) {
48-
String value = System.getenv(asEnvKey(key));
49-
if (value == null) {
50-
value = System.getenv(asPropertyKey(key));
50+
Map<String, String> env = System.getenv();
51+
for (String key : env.keySet()) {
52+
put(key, env.get(key));
5153
}
52-
return value;
5354
}
5455

55-
private String getFromProperty(String key) {
56-
String value = properties.getProperty(asEnvKey(key));
57-
if (value == null) {
58-
value = properties.getProperty(asPropertyKey(key));
59-
}
60-
return value;
56+
private void put(String key, String string) {
57+
map.put(key, string);
58+
// Support old skool
59+
map.put(key.replace('.', '_').toUpperCase(), string);
60+
map.put(key.replace('_', '.').toLowerCase(), string);
6161
}
6262

63-
private String getFromBundle(String key) {
64-
try {
65-
ResourceBundle bundle = ResourceBundle.getBundle(bundleName);
66-
try {
67-
return bundle.getString(asEnvKey(key));
68-
} catch (MissingResourceException stringNotFound) {
69-
try {
70-
return bundle.getString(asPropertyKey(key));
71-
} catch (MissingResourceException ignoreStringNotFound) {
72-
return bundle.getString(asPropertyKey(key));
73-
}
74-
}
75-
} catch (MissingResourceException ignoreBundleNotFound) {
76-
return null;
77-
}
63+
public String get(String key) {
64+
return map.get(key);
7865
}
7966

8067
public String get(String key, String defaultValue) {
8168
String result = get(key);
8269
return result != null ? result : defaultValue;
8370
}
84-
85-
private static String asEnvKey(String key) {
86-
return key.replace('.', '_').toUpperCase();
87-
}
88-
89-
private static String asPropertyKey(String key) {
90-
return key.replace('_', '.').toLowerCase();
91-
}
9271
}

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

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import gherkin.formatter.Reporter;
1515
import gherkin.util.FixJava;
1616

17+
import java.io.InputStreamReader;
18+
import java.io.Reader;
1719
import java.lang.reflect.InvocationHandler;
1820
import java.lang.reflect.Method;
1921
import java.lang.reflect.Proxy;
@@ -27,7 +29,9 @@
2729
// IMPORTANT! Make sure USAGE.txt is always uptodate if this class changes.
2830
public class RuntimeOptions {
2931
public static final String VERSION = ResourceBundle.getBundle("cucumber.version").getString("cucumber-jvm.version");
30-
public static final String USAGE = FixJava.readResource("/cucumber/api/cli/USAGE.txt");
32+
public static final String USAGE_RESOURCE = "/cucumber/api/cli/USAGE.txt";
33+
34+
static String usageText;
3135

3236
private final List<String> glue = new ArrayList<String>();
3337
private final List<Object> filters = new ArrayList<Object>();
@@ -70,7 +74,7 @@ public RuntimeOptions(Env env, List<String> argv) {
7074
}
7175

7276
public RuntimeOptions(PluginFactory pluginFactory, List<String> argv) {
73-
this(new Env("cucumber"), pluginFactory, argv);
77+
this(Env.INSTANCE, pluginFactory, argv);
7478
}
7579

7680
public RuntimeOptions(Env env, PluginFactory pluginFactory, List<String> argv) {
@@ -187,7 +191,19 @@ private void stripLinesFromFeaturePaths(List<String> featurePaths) {
187191
}
188192

189193
private void printUsage() {
190-
System.out.println(USAGE);
194+
loadUsageTextIfNeeded();
195+
System.out.println(usageText);
196+
}
197+
198+
static void loadUsageTextIfNeeded() {
199+
if (usageText == null) {
200+
try {
201+
Reader reader = new InputStreamReader(FixJava.class.getResourceAsStream(USAGE_RESOURCE), "UTF-8");
202+
usageText = FixJava.readReader(reader);
203+
} catch (Exception e) {
204+
usageText = "Could not load usage text: " + e.toString();
205+
}
206+
}
191207
}
192208

193209
private int printI18n(String language) {

core/src/main/java/cucumber/runtime/io/ResourceLoaderClassFinder.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,20 @@ public <T> Collection<Class<? extends T>> getDescendants(Class<T> parentType, St
2121
String packagePath = "classpath:" + packageName.replace('.', '/').replace(File.separatorChar, '/');
2222
for (Resource classResource : resourceLoader.resources(packagePath, ".class")) {
2323
String className = classResource.getClassName(".class");
24-
Class<?> clazz = loadClass(className, classLoader);
25-
if (clazz != null && !parentType.equals(clazz) && parentType.isAssignableFrom(clazz)) {
26-
result.add(clazz.asSubclass(parentType));
24+
25+
try {
26+
Class<?> clazz = loadClass(className);
27+
if (clazz != null && !parentType.equals(clazz) && parentType.isAssignableFrom(clazz)) {
28+
result.add(clazz.asSubclass(parentType));
29+
}
30+
} catch (ClassNotFoundException ignore) {
31+
} catch (NoClassDefFoundError ignore) {
2732
}
2833
}
2934
return result;
3035
}
3136

32-
private Class<?> loadClass(String className, ClassLoader classLoader) {
33-
try {
34-
return classLoader.loadClass(className);
35-
} catch (ClassNotFoundException ignore) {
36-
return null;
37-
} catch (NoClassDefFoundError ignore) {
38-
return null;
39-
}
37+
public <T> Class<? extends T> loadClass(String className) throws ClassNotFoundException {
38+
return (Class<? extends T>) classLoader.loadClass(className);
4039
}
4140
}

0 commit comments

Comments
 (0)