Skip to content

Commit d2e568c

Browse files
laeubiChristoph Läubrichmpkorstanje
authored
Add custom UuidGenerator to Runtime.Builder (#3039)
Currently the UuidGenerator is looked up by SPI when creating the event bus. This requires the UuidGenerator to be part of the classloader what might not always be the case. This now adds an option to set an actual instance for the UuidGenerator and uses that in case it is specified. Co-authored-by: Christoph Läubrich <[email protected]> Co-authored-by: M.P. Korstanje <[email protected]>
1 parent 16530e0 commit d2e568c

File tree

2 files changed

+93
-43
lines changed

2 files changed

+93
-43
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2020
### Fixed
2121
- [Core] Intellij prints summary printed when executing concurrently ([#3049](https://github.com/cucumber/cucumber-jvm/pull/3049) M.P. Korstanje)
2222

23+
### Added
24+
- [Core] Add custom UuidGenerator to Runtime.Builder ([#3039](https://github.com/cucumber/junit-xml-formatter/pull/3039) Christoph Läubrich, M.P. Korstanje)
25+
26+
2327
## [7.27.1] - 2025-08-17
2428
### Fixed
2529
- [Core] Format time in JUnit XML report as `xs:float` ([junit-xml-formatter/#83](https://github.com/cucumber/junit-xml-formatter/pull/83) M.P. Korstanje)

cucumber-core/src/main/java/io/cucumber/core/runtime/Runtime.java

Lines changed: 89 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.cucumber.core.runtime;
22

33
import io.cucumber.core.eventbus.EventBus;
4+
import io.cucumber.core.eventbus.UuidGenerator;
45
import io.cucumber.core.feature.FeatureParser;
56
import io.cucumber.core.filter.Filters;
67
import io.cucumber.core.gherkin.Feature;
@@ -117,96 +118,141 @@ public static class Builder {
117118
private Supplier<ClassLoader> classLoader = ClassLoaders::getDefaultClassLoader;
118119
private RuntimeOptions runtimeOptions = RuntimeOptions.defaultOptions();
119120
private BackendSupplier backendSupplier;
121+
private ObjectFactorySupplier objectFactorySupplier;
120122
private FeatureSupplier featureSupplier;
121123
private List<Plugin> additionalPlugins = emptyList();
124+
private Supplier<UuidGenerator> uuidGeneratorSupplier;
122125

123126
private Builder() {
124127
}
125128

126-
public Builder withRuntimeOptions(final RuntimeOptions runtimeOptions) {
129+
public Builder withRuntimeOptions(RuntimeOptions runtimeOptions) {
127130
this.runtimeOptions = runtimeOptions;
128131
return this;
129132
}
130133

131-
public Builder withClassLoader(final Supplier<ClassLoader> classLoader) {
134+
public Builder withClassLoader(Supplier<ClassLoader> classLoader) {
132135
this.classLoader = classLoader;
133136
return this;
134137
}
135138

136-
public Builder withBackendSupplier(final BackendSupplier backendSupplier) {
139+
public Builder withBackendSupplier(BackendSupplier backendSupplier) {
137140
this.backendSupplier = backendSupplier;
138141
return this;
139142
}
140143

141-
public Builder withFeatureSupplier(final FeatureSupplier featureSupplier) {
144+
public Builder withObjectFactorySupplier(ObjectFactorySupplier objectFactorySupplier) {
145+
this.objectFactorySupplier = objectFactorySupplier;
146+
return this;
147+
}
148+
149+
public Builder withFeatureSupplier(FeatureSupplier featureSupplier) {
142150
this.featureSupplier = featureSupplier;
143151
return this;
144152
}
145153

146-
public Builder withAdditionalPlugins(final Plugin... plugins) {
154+
public Builder withUuidGeneratorSupplier(Supplier<UuidGenerator> uuidGenerator) {
155+
this.uuidGeneratorSupplier = uuidGenerator;
156+
return this;
157+
}
158+
159+
public Builder withAdditionalPlugins(Plugin... plugins) {
147160
this.additionalPlugins = Arrays.asList(plugins);
148161
return this;
149162
}
150163

151-
public Builder withEventBus(final EventBus eventBus) {
164+
public Builder withEventBus(EventBus eventBus) {
152165
this.eventBus = eventBus;
153166
return this;
154167
}
155168

156169
public Runtime build() {
157-
final ObjectFactoryServiceLoader objectFactoryServiceLoader = new ObjectFactoryServiceLoader(classLoader,
158-
runtimeOptions);
159-
160-
final ObjectFactorySupplier objectFactorySupplier = runtimeOptions.isMultiThreaded()
161-
? new ThreadLocalObjectFactorySupplier(objectFactoryServiceLoader)
162-
: new SingletonObjectFactorySupplier(objectFactoryServiceLoader);
163-
164-
final BackendSupplier backendSupplier = this.backendSupplier != null
165-
? this.backendSupplier
166-
: new BackendServiceLoader(this.classLoader, objectFactorySupplier);
170+
EventBus eventBus = synchronize(createEventBus());
171+
ExitStatus exitStatus = createPluginsAndExitStatus(eventBus);
172+
RunnerSupplier runnerSupplier = createRunnerSupplier(eventBus);
173+
CucumberExecutionContext context = new CucumberExecutionContext(eventBus, exitStatus, runnerSupplier);
174+
Predicate<Pickle> filter = new Filters(runtimeOptions);
175+
int limit = runtimeOptions.getLimitCount();
176+
FeatureSupplier featureSupplier = createFeatureSupplier(eventBus);
177+
ExecutorService executor = createExecutorService();
178+
PickleOrder pickleOrder = runtimeOptions.getPickleOrder();
179+
return new Runtime(exitStatus, context, filter, limit, featureSupplier, executor, pickleOrder);
180+
}
167181

168-
final Plugins plugins = new Plugins(new PluginFactory(), runtimeOptions);
169-
for (final Plugin plugin : additionalPlugins) {
170-
plugins.addPlugin(plugin);
171-
}
172-
final ExitStatus exitStatus = new ExitStatus(runtimeOptions);
182+
private ExitStatus createPluginsAndExitStatus(EventBus eventBus) {
183+
Plugins plugins = createPlugins();
184+
ExitStatus exitStatus = new ExitStatus(runtimeOptions);
173185
plugins.addPlugin(exitStatus);
174186

175-
if (this.eventBus == null) {
176-
final UuidGeneratorServiceLoader uuidGeneratorServiceLoader = new UuidGeneratorServiceLoader(
177-
classLoader,
178-
runtimeOptions);
179-
this.eventBus = new TimeServiceEventBus(Clock.systemUTC(),
180-
uuidGeneratorServiceLoader.loadUuidGenerator());
181-
}
182-
final EventBus eventBus = synchronize(this.eventBus);
183-
184187
if (runtimeOptions.isMultiThreaded()) {
185188
plugins.setSerialEventBusOnEventListenerPlugins(eventBus);
186189
} else {
187190
plugins.setEventBusOnEventListenerPlugins(eventBus);
188191
}
192+
return exitStatus;
193+
}
189194

190-
final RunnerSupplier runnerSupplier = runtimeOptions.isMultiThreaded()
195+
private RunnerSupplier createRunnerSupplier(EventBus eventBus) {
196+
ObjectFactorySupplier objectFactorySupplier = createObjectFactorySupplier();
197+
BackendSupplier backendSupplier = createBackendSupplier(objectFactorySupplier);
198+
return runtimeOptions.isMultiThreaded()
191199
? new ThreadLocalRunnerSupplier(runtimeOptions, eventBus, backendSupplier, objectFactorySupplier)
192200
: new SingletonRunnerSupplier(runtimeOptions, eventBus, backendSupplier, objectFactorySupplier);
201+
}
193202

194-
final ExecutorService executor = runtimeOptions.isMultiThreaded()
195-
? Executors.newFixedThreadPool(runtimeOptions.getThreads(), new CucumberThreadFactory())
196-
: new SameThreadExecutorService();
203+
private ObjectFactorySupplier createObjectFactorySupplier() {
204+
if (this.objectFactorySupplier != null) {
205+
return objectFactorySupplier;
206+
}
207+
ObjectFactoryServiceLoader objectFactoryServiceLoader = new ObjectFactoryServiceLoader(classLoader,
208+
runtimeOptions);
209+
return runtimeOptions.isMultiThreaded()
210+
? new ThreadLocalObjectFactorySupplier(objectFactoryServiceLoader)
211+
: new SingletonObjectFactorySupplier(objectFactoryServiceLoader);
212+
}
197213

198-
final FeatureParser parser = new FeatureParser(eventBus::generateId);
214+
private BackendSupplier createBackendSupplier(ObjectFactorySupplier objectFactorySupplier) {
215+
return this.backendSupplier != null
216+
? this.backendSupplier
217+
: new BackendServiceLoader(this.classLoader, objectFactorySupplier);
218+
}
199219

200-
final FeatureSupplier featureSupplier = this.featureSupplier != null
201-
? this.featureSupplier
202-
: new FeaturePathFeatureSupplier(classLoader, runtimeOptions, parser);
220+
private EventBus createEventBus() {
221+
if (this.eventBus != null) {
222+
return this.eventBus;
223+
}
224+
UuidGenerator uuidGenerator = createUuidGenerator();
225+
return new TimeServiceEventBus(Clock.systemUTC(), uuidGenerator);
226+
}
203227

204-
final Predicate<Pickle> filter = new Filters(runtimeOptions);
205-
final int limit = runtimeOptions.getLimitCount();
206-
final PickleOrder pickleOrder = runtimeOptions.getPickleOrder();
207-
final CucumberExecutionContext context = new CucumberExecutionContext(eventBus, exitStatus, runnerSupplier);
228+
private UuidGenerator createUuidGenerator() {
229+
if (uuidGeneratorSupplier != null) {
230+
return uuidGeneratorSupplier.get();
231+
} else {
232+
return new UuidGeneratorServiceLoader(classLoader, runtimeOptions).loadUuidGenerator();
233+
}
234+
}
208235

209-
return new Runtime(exitStatus, context, filter, limit, featureSupplier, executor, pickleOrder);
236+
private FeatureSupplier createFeatureSupplier(EventBus eventBus) {
237+
if (this.featureSupplier != null) {
238+
return this.featureSupplier;
239+
}
240+
FeatureParser parser = new FeatureParser(eventBus::generateId);
241+
return new FeaturePathFeatureSupplier(classLoader, runtimeOptions, parser);
242+
}
243+
244+
private ExecutorService createExecutorService() {
245+
return runtimeOptions.isMultiThreaded()
246+
? Executors.newFixedThreadPool(runtimeOptions.getThreads(), new CucumberThreadFactory())
247+
: new SameThreadExecutorService();
248+
}
249+
250+
private Plugins createPlugins() {
251+
Plugins plugins = new Plugins(new PluginFactory(), runtimeOptions);
252+
for (Plugin plugin : additionalPlugins) {
253+
plugins.addPlugin(plugin);
254+
}
255+
return plugins;
210256
}
211257

212258
}

0 commit comments

Comments
 (0)