Skip to content

Commit 0b09193

Browse files
authored
datatable/java: Allow Object and String datatable types to be redefined (#885)
This enables the following in Cucumber-JVM: ```feature Feature: Whitespace Scenario: Whitespace in a table Given a blank value | key | value | | a | [blank] | ``` ```java @given("A blank value") public void given_a_blank_value(Map<String, String> map){ // map contains { "key":"a", "value": ""} } @DataTableType(replaceWithEmptyString = "[blank]") public String listOfStringListsType(String cell) { return cell; } ``` Note that this only applies to `String` and `Object` the other build in types can not be redefined. Though this could be considered if a clear usecase is presented. See: #1884
1 parent 0eaf09e commit 0b09193

File tree

4 files changed

+52
-7
lines changed

4 files changed

+52
-7
lines changed

CHANGELOG.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
88
## [Unreleased]
99

1010
### Added
11-
11+
* [Java] Allow Object and String datatable types to be redefined
12+
([#885](https://github.com/cucumber/cucumber/pull/885)
13+
[mpkorstanje])
1214
### Changed
1315

1416
### Deprecated

java/datatable/src/main/java/io/cucumber/datatable/DataTableType.java

+24
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,19 @@ public final class DataTableType {
2424
private final JavaType targetType;
2525
private final RawTableTransformer<?> transformer;
2626
private final Type elementType;
27+
private final boolean replaceable;
2728

2829
private DataTableType(Type type, Type target, RawTableTransformer<?> transformer) {
30+
this(type, target, transformer, false);
31+
}
32+
private DataTableType(Type type, Type target, RawTableTransformer<?> transformer, boolean replaceable) {
2933
if (type == null) throw new NullPointerException("targetType cannot be null");
3034
if (target == null) throw new NullPointerException("target cannot be null");
3135
if (transformer == null) throw new NullPointerException("transformer cannot be null");
3236
this.elementType = type;
3337
this.targetType = constructType(target);
3438
this.transformer = transformer;
39+
this.replaceable = replaceable;
3540
}
3641

3742
/**
@@ -74,6 +79,21 @@ public <T> DataTableType(Type type, TableEntryTransformer<T> transformer) {
7479
this(type, aListOf(type), new TableEntryTransformerAdaptor<>(transformer));
7580
}
7681

82+
/**
83+
* Creates a data replaceable table type that transforms the entries of the
84+
* table into a list of objects. An entry consists of the elements of the
85+
* table header paired with the values of each subsequent row.
86+
*
87+
* @param type the type of the list items
88+
* @param transformer a function that creates an instance of
89+
* <code>type</code> from the data table entry
90+
* @param replaceable can this datatable type be replaced with another for the same type
91+
* @param <T> see <code>type</code>
92+
*/
93+
<T> DataTableType(Type type, TableCellTransformer<T> transformer, boolean replaceable) {
94+
this(type, aListOf(aListOf(type)), new TableCellTransformerAdaptor<>(transformer), replaceable);
95+
}
96+
7797
/**
7898
* Creates a data table type that transforms the cells of the table into a
7999
* list of list of objects.
@@ -141,6 +161,10 @@ Class<?> getTransformerType() {
141161
return transformer.getOriginalTransformerType();
142162
}
143163

164+
public boolean isReplaceable() {
165+
return replaceable;
166+
}
167+
144168
@Override
145169
public boolean equals(Object o) {
146170
if (this == o) return true;

java/datatable/src/main/java/io/cucumber/datatable/DataTableTypeRegistry.java

+3-6
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ public DataTableTypeRegistry(Locale locale) {
2626
final NumberParser numberParser = new NumberParser(locale);
2727

2828
TableCellTransformer<Object> objectTableCellTransformer = applyIfPresent(s -> s);
29-
defineDataTableType(new DataTableType(Object.class, objectTableCellTransformer));
29+
defineDataTableType(new DataTableType(Object.class, objectTableCellTransformer, true));
30+
defineDataTableType(new DataTableType(String.class, objectTableCellTransformer, true));
3031

3132
TableCellTransformer<BigInteger> bigIntegerTableCellTransformer = applyIfPresent(BigInteger::new);
3233
defineDataTableType(new DataTableType(BigInteger.class, bigIntegerTableCellTransformer));
@@ -56,10 +57,6 @@ public DataTableTypeRegistry(Locale locale) {
5657
TableCellTransformer<Double> doubleTableCellTransformer = applyIfPresent(numberParser::parseDouble);
5758
defineDataTableType(new DataTableType(Double.class, doubleTableCellTransformer));
5859
defineDataTableType(new DataTableType(double.class, doubleTableCellTransformer));
59-
60-
TableCellTransformer<String> stringTableCellTransformer = (String cell) -> cell;
61-
defineDataTableType(new DataTableType(String.class, stringTableCellTransformer));
62-
6360
}
6461

6562
private static <R> TableCellTransformer<R> applyIfPresent(Function<String, R> f) {
@@ -68,7 +65,7 @@ private static <R> TableCellTransformer<R> applyIfPresent(Function<String, R> f)
6865

6966
public void defineDataTableType(DataTableType dataTableType) {
7067
DataTableType existing = tableTypeByType.get(dataTableType.getTargetType());
71-
if (existing != null) {
68+
if (existing != null && !existing.isReplaceable()) {
7269
throw new DuplicateTypeException(format("" +
7370
"There already is a data table type registered that can supply %s.\n" +
7471
"You are trying to register a %s for %s.\n" +

java/datatable/src/test/java/io/cucumber/datatable/DataTableTypeRegistryTest.java

+22
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class DataTableTypeRegistryTest {
2929
private static final Type LIST_OF_LIST_OF_FLOAT = aListOf(aListOf(Float.class));
3030
private static final Type LIST_OF_LIST_OF_DOUBLE = aListOf(aListOf(Double.class));
3131
private static final Type LIST_OF_LIST_OF_STRING = aListOf(aListOf(String.class));
32+
private static final Type LIST_OF_LIST_OF_OBJECT = aListOf(aListOf(Object.class));
3233

3334
private static final TableCellByTypeTransformer PLACE_TABLE_CELL_TRANSFORMER =
3435
(value, cellType) -> new Place(value);
@@ -235,6 +236,27 @@ void null_string_transformed_to_null() {
235236
singletonList(singletonList(null)),
236237
dataTableType.transform(singletonList(singletonList(null)))
237238
);
239+
}
240+
241+
@Test
242+
void string_transformer_is_replaceable() {
243+
DataTableTypeRegistry registry = new DataTableTypeRegistry(Locale.ENGLISH);
244+
registry.defineDataTableType(new DataTableType(String.class, (String cell) -> "[blank]".equals(cell) ? "" : cell));
245+
DataTableType dataTableType = registry.lookupTableTypeByType(LIST_OF_LIST_OF_STRING);
246+
assertEquals(
247+
singletonList(singletonList("")),
248+
dataTableType.transform(singletonList(singletonList("[blank]")))
249+
);
250+
}
238251

252+
@Test
253+
void object_transformer_is_replaceable() {
254+
DataTableTypeRegistry registry = new DataTableTypeRegistry(Locale.ENGLISH);
255+
registry.defineDataTableType(new DataTableType(Object.class, (String cell) -> "[blank]".equals(cell) ? "" : cell));
256+
DataTableType dataTableType = registry.lookupTableTypeByType(LIST_OF_LIST_OF_OBJECT);
257+
assertEquals(
258+
singletonList(singletonList("")),
259+
dataTableType.transform(singletonList(singletonList("[blank]")))
260+
);
239261
}
240262
}

0 commit comments

Comments
 (0)