cucumber.runtime.table.TableConverter Maven / Gradle / Ivy
package cucumber.runtime.table;
import cucumber.api.DataTable;
import cucumber.deps.com.thoughtworks.xstream.converters.ConversionException;
import cucumber.deps.com.thoughtworks.xstream.converters.SingleValueConverter;
import cucumber.deps.com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter;
import cucumber.deps.com.thoughtworks.xstream.io.HierarchicalStreamReader;
import cucumber.runtime.CucumberException;
import cucumber.runtime.ParameterInfo;
import cucumber.runtime.xstream.CellWriter;
import cucumber.runtime.xstream.ComplexTypeWriter;
import cucumber.runtime.xstream.ListOfComplexTypeReader;
import cucumber.runtime.xstream.ListOfSingleValueWriter;
import cucumber.runtime.xstream.LocalizedXStreams;
import cucumber.runtime.xstream.MapWriter;
import gherkin.formatter.model.Comment;
import gherkin.formatter.model.DataTableRow;
import gherkin.util.Mapper;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static cucumber.runtime.Utils.listItemType;
import static cucumber.runtime.Utils.mapKeyType;
import static cucumber.runtime.Utils.mapValueType;
import static gherkin.util.FixJava.map;
import static java.util.Arrays.asList;
/**
* This class converts a {@link cucumber.api.DataTable} to various other types.
*/
public class TableConverter {
private static final List NO_COMMENTS = Collections.emptyList();
private final LocalizedXStreams.LocalizedXStream xStream;
private final ParameterInfo parameterInfo;
public TableConverter(LocalizedXStreams.LocalizedXStream xStream, ParameterInfo parameterInfo) {
this.xStream = xStream;
this.parameterInfo = parameterInfo;
}
/**
* This method converts a {@link cucumber.api.DataTable} to abother type.
* When a Step Definition is passed a Gherkin Data Table, the runtime will use this method to convert the
* {@link cucumber.api.DataTable} to the declared type before invoking the Step Definition.
*
* This method uses reflection to inspect the type and delegates to the appropriate {@code toXxx} method.
*
* @param dataTable the table to convert
* @param type the type to convert to
* @param transposed whether the table should be transposed first.
* @return the transformed object.
*/
public T convert(DataTable dataTable, Type type, boolean transposed) {
if (transposed) {
dataTable = dataTable.transpose();
}
if (type == null || (type instanceof Class && ((Class) type).isAssignableFrom(DataTable.class))) {
return (T) dataTable;
}
Type mapKeyType = mapKeyType(type);
if (mapKeyType != null) {
Type mapValueType = mapValueType(type);
return (T) toMap(dataTable, mapKeyType, mapValueType);
}
Type itemType = listItemType(type);
if (itemType == null) {
throw new CucumberException("Not a Map or List type: " + type);
}
Type listItemType = listItemType(itemType);
if (listItemType != null) {
return (T) toLists(dataTable, listItemType);
} else {
SingleValueConverter singleValueConverter = xStream.getSingleValueConverter(itemType);
if (singleValueConverter != null) {
return (T) toList(dataTable, singleValueConverter);
} else {
if (itemType instanceof Class) {
if (Map.class.equals(itemType)) {
// Non-generic map
return (T) toMaps(dataTable, String.class, String.class);
} else {
return (T) toListOfComplexType(dataTable, (Class) itemType);
}
} else {
return (T) toMaps(dataTable, mapKeyType(itemType), mapValueType(itemType));
}
}
}
}
private List toListOfComplexType(DataTable dataTable, Class itemType) {
HierarchicalStreamReader reader = new ListOfComplexTypeReader(itemType, convertTopCellsToFieldNames(dataTable), dataTable.cells(1));
try {
xStream.setParameterInfo(parameterInfo);
return Collections.unmodifiableList((List) xStream.unmarshal(reader));
} catch (AbstractReflectionConverter.UnknownFieldException e) {
throw new CucumberException(e.getShortMessage());
} catch (AbstractReflectionConverter.DuplicateFieldException e) {
throw new CucumberException(e.getShortMessage());
} catch (ConversionException e) {
if (e.getCause() instanceof NullPointerException) {
throw new CucumberException(String.format("Can't assign null value to one of the primitive fields in %s. Please use boxed types.", e.get("class")));
} else {
throw new CucumberException(e);
}
} finally {
xStream.unsetParameterInfo();
}
}
public List toList(DataTable dataTable, Type itemType) {
SingleValueConverter itemConverter = xStream.getSingleValueConverter(itemType);
if (itemConverter != null) {
return toList(dataTable, itemConverter);
} else {
if (itemType instanceof Class) {
return toListOfComplexType(dataTable, (Class) itemType);
} else {
throw new CucumberException(String.format("Can't convert DataTable to List<%s>", itemType));
}
}
}
private List toList(DataTable dataTable, SingleValueConverter itemConverter) {
List result = new ArrayList();
for (List row : dataTable.raw()) {
for (String cell : row) {
result.add((T) itemConverter.fromString(cell));
}
}
return Collections.unmodifiableList(result);
}
public List> toLists(DataTable dataTable, Type itemType) {
try {
xStream.setParameterInfo(parameterInfo);
SingleValueConverter itemConverter = xStream.getSingleValueConverter(itemType);
if (itemConverter == null) {
throw new CucumberException(String.format("Can't convert DataTable to List>", itemType));
}
List> result = new ArrayList>();
for (List row : dataTable.raw()) {
List convertedRow = new ArrayList();
for (String cell : row) {
convertedRow.add((T) itemConverter.fromString(cell));
}
result.add(Collections.unmodifiableList(convertedRow));
}
return Collections.unmodifiableList(result);
} finally {
xStream.unsetParameterInfo();
}
}
public Map toMap(DataTable dataTable, Type keyType, Type valueType) {
try {
xStream.setParameterInfo(parameterInfo);
SingleValueConverter keyConverter = xStream.getSingleValueConverter(keyType);
SingleValueConverter valueConverter = xStream.getSingleValueConverter(valueType);
if (keyConverter == null || valueConverter == null) {
throw new CucumberException(String.format("Can't convert DataTable to Map<%s,%s>", keyType, valueType));
}
Map result = new LinkedHashMap();
for (List row : dataTable.raw()) {
if (row.size() != 2) {
throw new CucumberException("A DataTable can only be converted to a Map when there are 2 columns");
}
K key = (K) keyConverter.fromString(row.get(0));
V value = (V) valueConverter.fromString(row.get(1));
result.put(key, value);
}
return Collections.unmodifiableMap(result);
} finally {
xStream.unsetParameterInfo();
}
}
public List
© 2015 - 2024 Weber Informatics LLC | Privacy Policy