Skip to content

Commit cace210

Browse files
authored
[Core] Use null safe-messages (#2497)
With cucumber/common#1879 `messages` now uses `Optional<T>` for optional types avoiding some unexpected null references. This resulted in some updating of `gherkin` and `html-formatter`. Additionally with this change the dependency on Jackson has been removed from `messages`. However we still have to serialize the message objects into json. So for now Jackson is shaded into `core` instead. And eventually we'll be able to spin this out to it's own module.
1 parent 655eb1f commit cace210

Some content is hidden

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

43 files changed

+511
-507
lines changed

.revapi/api-changes.json

+57
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,63 @@
106106
"old": "class io.cucumber.gherkin.internal.com.eclipsesource.json.JsonWriter",
107107
"new": "class io.cucumber.gherkin.internal.com.eclipsesource.json.JsonWriter",
108108
"justification": "Internal API"
109+
},
110+
{
111+
"regex": true,
112+
"code": "java.method.returnTypeChanged",
113+
"old": ".* io\\.cucumber\\.messages\\..*",
114+
"new": ".* io\\.cucumber\\.messages\\..*",
115+
"justification": "Internal API"
116+
},
117+
{
118+
"regex": true,
119+
"code": "java.method.removed",
120+
"old": ".* io\\.cucumber\\.messages\\..*",
121+
"justification": "Internal API"
122+
},
123+
{
124+
"regex": true,
125+
"code": "java.class.nowFinal",
126+
"old": ".* io\\.cucumber\\.messages\\..*",
127+
"new": ".* io\\.cucumber\\.messages\\..*",
128+
"justification": "Internal API"
129+
},
130+
{
131+
"regex": true,
132+
"code": "java.method.numberOfParametersChanged",
133+
"old": ".* io\\.cucumber\\.messages\\..*",
134+
"new": ".* io\\.cucumber\\.messages\\..*",
135+
"justification": "Internal API"
136+
},
137+
{
138+
"regex": true,
139+
"code": "java.class.removed",
140+
"old": ".* io\\.cucumber\\.messages\\..*",
141+
"justification": "Internal API"
142+
},
143+
{
144+
"regex": true,
145+
"code": "java.class.removed",
146+
"old": ".* io\\.cucumber\\.core\\.gherkin\\.messages\\.internal\\..*",
147+
"justification": "Internal API"
148+
},
149+
{
150+
"regex": true,
151+
"code": "java.class.removed",
152+
"old": ".* io\\.cucumber\\.gherkin\\..*",
153+
"justification": "Internal API"
154+
},
155+
{
156+
"regex": true,
157+
"code": "java.class.removed",
158+
"old": ".* io\\.cucumber\\.gherkin\\.internal\\..*",
159+
"justification": "Internal API"
160+
},
161+
{
162+
"regex": true,
163+
"code": "java.class.nonPublicPartOfAPI",
164+
"new": ".* io\\.cucumber\\.core\\.internal\\..*",
165+
"justification": "Internal API"
109166
}
110167
]
111168
}

CHANGELOG.md

+7-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1111
* [JUnit Platform] Support `cucumber.features` property ([#2498](https://github.com/cucumber/cucumber-jvm/pull/2498) M.P. Korstanje)
1212

1313
### Changed
14+
* [Core] Use null-safe messages ([#2497](https://github.com/cucumber/cucumber-jvm/pull/2497) M.P. Korstanje)
15+
* Update dependency io.cucumber:html-formatter to v19.1
16+
- Removed work around for 'Uncaught TypeError: e.git is undefined'
17+
* Update dependency io.cucumber:messages to v18
18+
* Update dependency io.cucumber:gherkin to v23
19+
* Moved shaded jackson from `messages` to `core`.
20+
1421
* Update dependency io.cucumber:ci-environment to v9 ([#2475](https://github.com/cucumber/cucumber-jvm/pull/2475) M.P. Korstanje)
15-
* Update dependency io.cucumber:html-formatter to v18 ([#2476](https://github.com/cucumber/cucumber-jvm/pull/2476) M.P. Korstanje)
16-
- Removed work around for 'Uncaught TypeError: e.git is undefined'
1722
* Update dependency com.google.inject:guice to v5.1.0 ([#2473](https://github.com/cucumber/cucumber-jvm/pull/2473) M.P. Korstanje)
1823
* Update dependency org.testng:testng to v7.5 ([#2457](https://github.com/cucumber/cucumber-jvm/pull/2457) M.P. Korstanje)
1924

bom/pom.xml

+1-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414
<properties>
1515
<ci-environment.version>9.0.4</ci-environment.version>
1616
<cucumber-expressions.version>15.0.2</cucumber-expressions.version>
17-
<datatable.version>4.1.0</datatable.version>
18-
<html-formatter.version>18.0.0</html-formatter.version>
17+
<html-formatter.version>19.1.0</html-formatter.version>
1918
<tag-expressions.version>4.1.0</tag-expressions.version>
2019
</properties>
2120

core/pom.xml

+55-51
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<properties>
1616
<project.Automatic-Module-Name>io.cucumber.core</project.Automatic-Module-Name>
1717
<apiguardian-api.version>1.1.2</apiguardian-api.version>
18-
<jackson-databind.version>2.13.2.2</jackson-databind.version>
18+
<jackson-databind.version>2.13.2.20220328</jackson-databind.version>
1919
<jsoup.version>1.14.3</jsoup.version>
2020
<junit-jupiter.version>5.8.2</junit-jupiter.version>
2121
<xmlunit.version>2.9.0</xmlunit.version>
@@ -42,14 +42,17 @@
4242
<type>pom</type>
4343
<scope>import</scope>
4444
</dependency>
45+
<dependency>
46+
<groupId>com.fasterxml.jackson</groupId>
47+
<artifactId>jackson-bom</artifactId>
48+
<version>${jackson-databind.version}</version>
49+
<type>pom</type>
50+
<scope>import</scope>
51+
</dependency>
4552
</dependencies>
4653
</dependencyManagement>
4754

4855
<dependencies>
49-
<dependency>
50-
<groupId>io.cucumber</groupId>
51-
<artifactId>gherkin</artifactId>
52-
</dependency>
5356
<dependency>
5457
<groupId>io.cucumber</groupId>
5558
<artifactId>cucumber-gherkin</artifactId>
@@ -95,6 +98,14 @@
9598
<artifactId>apiguardian-api</artifactId>
9699
<version>${apiguardian-api.version}</version>
97100
</dependency>
101+
<dependency>
102+
<groupId>com.fasterxml.jackson.core</groupId>
103+
<artifactId>jackson-databind</artifactId>
104+
</dependency>
105+
<dependency>
106+
<groupId>com.fasterxml.jackson.datatype</groupId>
107+
<artifactId>jackson-datatype-jdk8</artifactId>
108+
</dependency>
98109

99110
<dependency>
100111
<groupId>org.xmlunit</groupId>
@@ -136,42 +147,12 @@
136147
<artifactId>vertx-web</artifactId>
137148
<version>${vertx.version}</version>
138149
<scope>test</scope>
139-
<exclusions>
140-
<!-- Fix dependency convergence -->
141-
<exclusion>
142-
<groupId>com.fasterxml.jackson.core</groupId>
143-
<artifactId>jackson-databind</artifactId>
144-
</exclusion>
145-
<exclusion>
146-
<groupId>com.fasterxml.jackson.core</groupId>
147-
<artifactId>jackson-core</artifactId>
148-
</exclusion>
149-
</exclusions>
150150
</dependency>
151151
<dependency>
152152
<groupId>io.vertx</groupId>
153153
<artifactId>vertx-junit5</artifactId>
154154
<version>${vertx.version}</version>
155155
<scope>test</scope>
156-
<exclusions>
157-
<!-- Fix dependency convergence -->
158-
<exclusion>
159-
<groupId>org.junit.jupiter</groupId>
160-
<artifactId>junit-jupiter-params</artifactId>
161-
</exclusion>
162-
<exclusion>
163-
<groupId>org.reactivestreams</groupId>
164-
<artifactId>reactive-streams</artifactId>
165-
</exclusion>
166-
<exclusion>
167-
<groupId>com.fasterxml.jackson.core</groupId>
168-
<artifactId>jackson-databind</artifactId>
169-
</exclusion>
170-
<exclusion>
171-
<groupId>com.fasterxml.jackson.core</groupId>
172-
<artifactId>jackson-core</artifactId>
173-
</exclusion>
174-
</exclusions>
175156
</dependency>
176157
<!-- Fix dependency convergence -->
177158
<dependency>
@@ -204,13 +185,6 @@
204185
</exclusion>
205186
</exclusions>
206187
</dependency>
207-
<dependency>
208-
<groupId>com.fasterxml.jackson.core</groupId>
209-
<artifactId>jackson-databind</artifactId>
210-
<version>${jackson-databind.version}</version>
211-
<scope>test</scope>
212-
</dependency>
213-
214188
</dependencies>
215189

216190
<build>
@@ -267,21 +241,51 @@
267241
<configuration>
268242
<artifactSet>
269243
<includes>
270-
<include>io.cucumber:gherkin</include>
244+
<include>com.fasterxml.jackson.core:jackson-databind</include>
245+
<include>com.fasterxml.jackson.core:jackson-core</include>
246+
<include>com.fasterxml.jackson.core:jackson-annotations</include>
247+
<include>com.fasterxml.jackson.datatype:jackson-datatype-jdk8</include>
271248
</includes>
272249
</artifactSet>
273-
<!-- Do not enable relocation. Stuck with it until the next major. -->
274-
<!--<relocations>-->
275-
<!-- <relocation>-->
276-
<!-- <pattern>io.cucumber.gherkin</pattern>-->
277-
<!-- <shadedPattern>io.cucumber.core.internal.gherkin</shadedPattern>-->
278-
<!-- </relocation>-->
279-
<!--</relocations>-->
250+
<relocations>
251+
<relocation>
252+
<pattern>com.fasterxml</pattern>
253+
<shadedPattern>io.cucumber.core.internal.com.fasterxml</shadedPattern>
254+
</relocation>
255+
</relocations>
280256
<filters>
281257
<filter>
282-
<artifact>io.cucumber:gherkin</artifact>
258+
<artifact>com.fasterxml.jackson.core:jackson-databind</artifact>
259+
<excludes>
260+
<exclude>**/module-info.class</exclude>
261+
<exclude>META-INF/MANIFEST.MF</exclude>
262+
<exclude>META-INF/LICENSE</exclude>
263+
<exclude>META-INF/NOTICE</exclude>
264+
</excludes>
265+
</filter>
266+
<filter>
267+
<artifact>com.fasterxml.jackson.core:jackson-core</artifact>
268+
<excludes>
269+
<exclude>**/module-info.class</exclude>
270+
<exclude>META-INF/MANIFEST.MF</exclude>
271+
<exclude>META-INF/LICENSE</exclude>
272+
<exclude>META-INF/NOTICE</exclude>
273+
</excludes>
274+
</filter>
275+
<filter>
276+
<artifact>com.fasterxml.jackson.core:jackson-annotations</artifact>
277+
<excludes>
278+
<exclude>**/module-info.class</exclude>
279+
<exclude>META-INF/MANIFEST.MF</exclude>
280+
<exclude>META-INF/LICENSE</exclude>
281+
</excludes>
282+
</filter>
283+
<filter>
284+
<artifact>com.fasterxml.jackson.datatype:jackson-datatype-jdk8</artifact>
283285
<excludes>
286+
<exclude>**/module-info.class</exclude>
284287
<exclude>META-INF/MANIFEST.MF</exclude>
288+
<exclude>META-INF/LICENSE</exclude>
285289
</excludes>
286290
</filter>
287291
</filters>

core/src/main/java/io/cucumber/core/options/CommandlineOptionsParser.java

+8-5
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
import io.cucumber.core.logging.Logger;
77
import io.cucumber.core.logging.LoggerFactory;
88
import io.cucumber.datatable.DataTable;
9+
import io.cucumber.datatable.DataTableFormatter;
910
import io.cucumber.gherkin.GherkinDialect;
1011
import io.cucumber.gherkin.GherkinDialectProvider;
11-
import io.cucumber.gherkin.IGherkinDialectProvider;
1212
import io.cucumber.tagexpressions.TagExpressionParser;
1313

1414
import java.io.BufferedReader;
@@ -198,7 +198,7 @@ private String removeArgFor(String arg, List<String> args) {
198198
}
199199

200200
private byte printI18n(String language) {
201-
IGherkinDialectProvider dialectProvider = new GherkinDialectProvider();
201+
GherkinDialectProvider dialectProvider = new GherkinDialectProvider();
202202
List<String> languages = dialectProvider.getLanguages();
203203

204204
if (language.equalsIgnoreCase("help")) {
@@ -233,7 +233,7 @@ private String loadUsageText() {
233233
BufferedReader br = new BufferedReader(new InputStreamReader(usageResourceStream, UTF_8))) {
234234
return br.lines().collect(joining(System.lineSeparator()));
235235
} catch (Exception e) {
236-
return "Could not load usage text: " + e.toString();
236+
return "Could not load usage text: " + e;
237237
}
238238
}
239239

@@ -271,8 +271,11 @@ private byte printKeywordsFor(GherkinDialect dialect) {
271271
addCodeKeywordRow(table, "then", dialect.getThenKeywords());
272272
addCodeKeywordRow(table, "and", dialect.getAndKeywords());
273273
addCodeKeywordRow(table, "but", dialect.getButKeywords());
274-
DataTable.create(table).print(builder);
275-
out.println(builder.toString());
274+
DataTableFormatter.builder()
275+
.prefixRow(" ")
276+
.build()
277+
.formatTo(DataTable.create(table), builder);
278+
out.println(builder);
276279
return 0x0;
277280
}
278281

core/src/main/java/io/cucumber/core/plugin/HtmlFormatter.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public final class HtmlFormatter implements ConcurrentEventListener {
1414

1515
@SuppressWarnings("WeakerAccess") // Used by PluginFactory
1616
public HtmlFormatter(OutputStream out) throws IOException {
17-
this.writer = new MessagesToHtmlWriter(new UTF8OutputStreamWriter(out));
17+
this.writer = new MessagesToHtmlWriter(out, Jackson.OBJECT_MAPPER::writeValue);
1818
}
1919

2020
@Override
@@ -25,7 +25,8 @@ public void setEventPublisher(EventPublisher publisher) {
2525
private void write(Envelope event) {
2626
// Workaround to reduce the size of the report
2727
// See: https://github.com/cucumber/cucumber/issues/1232
28-
if (event.getStepDefinition() != null || event.getHook() != null || event.getParameterType() != null) {
28+
if (event.getStepDefinition().isPresent() || event.getHook().isPresent()
29+
|| event.getParameterType().isPresent()) {
2930
return;
3031
}
3132

@@ -37,7 +38,7 @@ private void write(Envelope event) {
3738

3839
// TODO: Plugins should implement the closable interface
3940
// and be closed by Cucumber
40-
if (event.getTestRunFinished() != null) {
41+
if (event.getTestRunFinished().isPresent()) {
4142
try {
4243
writer.close();
4344
} catch (IOException e) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package io.cucumber.core.plugin;
2+
3+
import com.fasterxml.jackson.annotation.JsonInclude.Include;
4+
import com.fasterxml.jackson.core.JsonGenerator;
5+
import com.fasterxml.jackson.databind.DeserializationFeature;
6+
import com.fasterxml.jackson.databind.ObjectMapper;
7+
import com.fasterxml.jackson.databind.SerializationFeature;
8+
import com.fasterxml.jackson.databind.cfg.ConstructorDetector;
9+
import com.fasterxml.jackson.databind.json.JsonMapper;
10+
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
11+
12+
final class Jackson {
13+
public static final ObjectMapper OBJECT_MAPPER = JsonMapper.builder()
14+
.addModule(new Jdk8Module())
15+
.serializationInclusion(Include.NON_ABSENT)
16+
.constructorDetector(ConstructorDetector.USE_PROPERTIES_BASED)
17+
.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)
18+
.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING)
19+
.enable(DeserializationFeature.USE_LONG_FOR_INTS)
20+
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
21+
.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET)
22+
.build();
23+
24+
private Jackson() {
25+
}
26+
27+
}

core/src/main/java/io/cucumber/core/plugin/JsonFormatter.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package io.cucumber.core.plugin;
22

3-
import io.cucumber.messages.JSON;
43
import io.cucumber.messages.types.Background;
54
import io.cucumber.messages.types.Feature;
65
import io.cucumber.messages.types.Scenario;
@@ -145,7 +144,7 @@ private void finishReport(TestRunFinished event) {
145144
}
146145

147146
try {
148-
JSON.writeValue(writer, featureMaps);
147+
Jackson.OBJECT_MAPPER.writeValue(writer, featureMaps);
149148
writer.close();
150149
} catch (IOException e) {
151150
throw new RuntimeException(e);

core/src/main/java/io/cucumber/core/plugin/MessageFormatter.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package io.cucumber.core.plugin;
22

3-
import io.cucumber.messages.JSON;
43
import io.cucumber.messages.types.Envelope;
54
import io.cucumber.plugin.ConcurrentEventListener;
65
import io.cucumber.plugin.event.EventPublisher;
@@ -24,10 +23,10 @@ public void setEventPublisher(EventPublisher publisher) {
2423

2524
private void writeMessage(Envelope envelope) {
2625
try {
27-
JSON.writeValue(writer, envelope);
26+
Jackson.OBJECT_MAPPER.writeValue(writer, envelope);
2827
writer.write("\n");
2928
writer.flush();
30-
if (envelope.getTestRunFinished() != null) {
29+
if (envelope.getTestRunFinished().isPresent()) {
3130
writer.close();
3231
}
3332
} catch (IOException e) {

0 commit comments

Comments
 (0)