diff --git a/examples/core/src/main/java/org/jbehave/examples/core/converters/CalendarConverter.java b/examples/core/src/main/java/org/jbehave/examples/core/converters/CalendarConverter.java index 245e2906b..2de47e683 100755 --- a/examples/core/src/main/java/org/jbehave/examples/core/converters/CalendarConverter.java +++ b/examples/core/src/main/java/org/jbehave/examples/core/converters/CalendarConverter.java @@ -6,9 +6,9 @@ import java.util.Calendar; import org.apache.commons.lang3.StringUtils; -import org.jbehave.core.steps.ParameterConverters.AbstractParameterConverter; +import org.jbehave.core.steps.ParameterConverters.FromStringParameterConverter; -public class CalendarConverter extends AbstractParameterConverter { +public class CalendarConverter extends FromStringParameterConverter { private final SimpleDateFormat dateFormat; diff --git a/examples/core/src/main/java/org/jbehave/examples/core/converters/TraderConverter.java b/examples/core/src/main/java/org/jbehave/examples/core/converters/TraderConverter.java index 5f41e557d..2b340ca9b 100755 --- a/examples/core/src/main/java/org/jbehave/examples/core/converters/TraderConverter.java +++ b/examples/core/src/main/java/org/jbehave/examples/core/converters/TraderConverter.java @@ -2,12 +2,12 @@ import java.lang.reflect.Type; -import org.jbehave.core.steps.ParameterConverters.AbstractParameterConverter; +import org.jbehave.core.steps.ParameterConverters.FromStringParameterConverter; import org.jbehave.core.steps.ParameterConverters.ParameterConversionFailed; import org.jbehave.examples.core.model.Trader; import org.jbehave.examples.core.persistence.TraderPersister; -public class TraderConverter extends AbstractParameterConverter { +public class TraderConverter extends FromStringParameterConverter { private TraderPersister persister; public TraderConverter(TraderPersister persister) { diff --git a/jbehave-core/src/main/java/org/jbehave/core/steps/AbstractStepsFactory.java b/jbehave-core/src/main/java/org/jbehave/core/steps/AbstractStepsFactory.java index b5cea7523..de6512cea 100755 --- a/jbehave-core/src/main/java/org/jbehave/core/steps/AbstractStepsFactory.java +++ b/jbehave-core/src/main/java/org/jbehave/core/steps/AbstractStepsFactory.java @@ -9,8 +9,8 @@ import org.jbehave.core.annotations.AsParameterConverter; import org.jbehave.core.configuration.Configuration; -import org.jbehave.core.steps.ParameterConverters.MethodReturningConverter; import org.jbehave.core.steps.ParameterConverters.ParameterConverter; +import org.jbehave.core.steps.ParameterConverters.MethodReturningConverter; /** *

diff --git a/jbehave-core/src/main/java/org/jbehave/core/steps/ParameterConverters.java b/jbehave-core/src/main/java/org/jbehave/core/steps/ParameterConverters.java index 7938075af..04413e3c2 100755 --- a/jbehave-core/src/main/java/org/jbehave/core/steps/ParameterConverters.java +++ b/jbehave-core/src/main/java/org/jbehave/core/steps/ParameterConverters.java @@ -8,6 +8,7 @@ import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; import java.math.BigDecimal; import java.math.BigInteger; import java.text.DateFormat; @@ -40,6 +41,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.NavigableSet; import java.util.Optional; import java.util.Queue; @@ -107,7 +109,7 @@ public class ParameterConverters { private static final String DEFAULT_FALSE_VALUE = "false"; private final StepMonitor monitor; - private final List converters; + private final List converters; private final boolean threadSafe; private String escapedCollectionSeparator; @@ -264,14 +266,14 @@ public ParameterConverters(StepMonitor monitor, Keywords keywords, ResourceLoade collectionSeparator)); } - private ParameterConverters(StepMonitor monitor, List converters, boolean threadSafe) { + private ParameterConverters(StepMonitor monitor, List converters, boolean threadSafe) { this.monitor = monitor; this.threadSafe = threadSafe; this.converters = threadSafe ? new CopyOnWriteArrayList<>(converters) : new ArrayList<>(converters); } - protected ChainableParameterConverter[] defaultConverters(Keywords keywords, ResourceLoader resourceLoader, + protected ParameterConverter[] defaultConverters(Keywords keywords, ResourceLoader resourceLoader, ParameterControls parameterControls, TableParsers tableParsers, TableTransformers tableTransformers, Locale locale, String collectionSeparator) { this.escapedCollectionSeparator = escapeRegexPunctuation(collectionSeparator); @@ -315,11 +317,11 @@ private String escapeRegexPunctuation(String matchThis) { return matchThis.replaceAll("([\\[\\]\\{\\}\\?\\^\\.\\*\\(\\)\\+\\\\])", "\\\\$1"); } - public ParameterConverters addConverters(ChainableParameterConverter... converters) { + public ParameterConverters addConverters(ParameterConverter... converters) { return addConverters(asList(converters)); } - public ParameterConverters addConverters(List converters) { + public ParameterConverters addConverters(List converters) { this.converters.addAll(0, converters); return this; } @@ -328,7 +330,7 @@ public ParameterConverters addConverterFromFunction(Class targetType, Fun return addConverters(new FunctionalParameterConverter<>(targetType, converter)); } - private static boolean isChainComplete(Queue convertersChain) { + private static boolean isChainComplete(Queue convertersChain) { if (convertersChain.isEmpty()) { return false; } @@ -336,7 +338,7 @@ private static boolean isChainComplete(Queue conver return typeArguments.length <= 1 || typeArguments[0].equals(String.class); } - private static Object applyConverters(Object value, Type basicType, Queue convertersChain) { + private static Object applyConverters(Object value, Type basicType, Queue convertersChain) { Object identity = convertersChain.peek().convertValue(value, basicType); return convertersChain.stream().skip(1).reduce(identity, (v, c) -> c.convertValue(v, getTargetType(c.getClass())), (l, r) -> l); @@ -344,10 +346,10 @@ private static Object applyConverters(Object value, Type basicType, Queue converters = findConverters(type); + Queue converters = findConverters(type); if (isChainComplete(converters)) { Object converted = applyConverters(value, type, converters); - Queue> classes = converters.stream().map(ChainableParameterConverter::getClass) + Queue> classes = converters.stream().map(ParameterConverter::getClass) .collect(Collectors.toCollection(LinkedList::new)); monitor.convertedValueOfType(value, type, converted, classes); return converted; @@ -355,7 +357,7 @@ public Object convert(String value, Type type) { if (isAssignableFromRawType(Collection.class, type)) { Type elementType = argumentType(type); - ChainableParameterConverter elementConverter = findConverter(elementType); + ParameterConverter elementConverter = findConverter(elementType); Collection collection = createCollection(rawClass(type)); if (elementConverter != null && collection != null) { fillCollection(value, escapedCollectionSeparator, elementConverter, elementType, collection); @@ -368,7 +370,7 @@ public Object convert(String value, Type type) { if (clazz.isArray()) { String[] elements = parseElements(value, escapedCollectionSeparator); Class elementType = clazz.getComponentType(); - ChainableParameterConverter elementConverter = findConverter(elementType); + ParameterConverter elementConverter = findConverter(elementType); Object array = createArray(elementType, elements.length); if (elementConverter != null && array != null) { @@ -381,8 +383,8 @@ public Object convert(String value, Type type) { throw new ParameterConversionFailed("No parameter converter for " + type); } - private ChainableParameterConverter findConverter(Type type) { - for (ChainableParameterConverter converter : converters) { + private ParameterConverter findConverter(Type type) { + for (ParameterConverter converter : converters) { if (converter.canConvertTo(type)) { return converter; } @@ -390,14 +392,14 @@ private ChainableParameterConverter findConverter(Type type) { return null; } - private Queue findConverters(Type type) { - LinkedList convertersChain = new LinkedList<>(); + private Queue findConverters(Type type) { + LinkedList convertersChain = new LinkedList<>(); putConverters(type, convertersChain); return convertersChain; } - private void putConverters(Type type, LinkedList container) { - for (ChainableParameterConverter converter : converters) { + private void putConverters(Type type, LinkedList container) { + for (ParameterConverter converter : converters) { if (converter.canConvertTo(type)) { container.addFirst(converter); Type[] types = getTypeArguments(converter.getClass()); @@ -415,7 +417,7 @@ private static Type[] getTypeArguments(Class clazz) { .orElse(new Type [] {}); } - private static Type getTargetType(Class clazz) { + private static Type getTargetType(Class clazz) { Type[] types = getTypeArguments(clazz); if (types.length > 0) { return types.length == 1 ? types[0] : types[1]; @@ -425,7 +427,7 @@ private static Type getTargetType(Class c private static Optional getParameterizedType(Class clazz) { Optional parametrizedType = Arrays.stream(clazz.getGenericInterfaces()) - .filter(t -> TypeUtils.isAssignable(t, ChainableParameterConverter.class)) + .filter(t -> TypeUtils.isAssignable(t, ParameterConverter.class)) .filter(t -> t instanceof ParameterizedType) .map(ParameterizedType.class::cast) .findFirst(); @@ -471,7 +473,7 @@ private static String[] parseElements(String value, String elementSeparator) { return elements; } - private static void fillCollection(String value, String elementSeparator, ChainableParameterConverter elementConverter, + private static void fillCollection(String value, String elementSeparator, ParameterConverter elementConverter, Type elementType, Collection convertedValues) { for (String element : parseElements(value, elementSeparator)) { T convertedValue = elementConverter.convertValue(element, elementType); @@ -479,7 +481,7 @@ private static void fillCollection(String value, String elementSeparator, Ch } } - private static void fillArray(String[] elements, ChainableParameterConverter elementConverter, + private static void fillArray(String[] elements, ParameterConverter elementConverter, Type elementType, Object convertedValues) { for (int i = 0; i < elements.length; i++) { T convertedValue = elementConverter.convertValue(elements[i], elementType); @@ -516,8 +518,8 @@ private static Object createArray(Class elementType, int length) { return null; } - public ParameterConverters newInstanceAdding(ChainableParameterConverter converter) { - List convertersForNewInstance = new ArrayList<>(converters); + public ParameterConverters newInstanceAdding(ParameterConverter converter) { + List convertersForNewInstance = new ArrayList<>(converters); convertersForNewInstance.add(converter); return new ParameterConverters(monitor, convertersForNewInstance, threadSafe); } @@ -530,15 +532,22 @@ public ParameterConverters newInstanceAdding(ChainableParameterConverter convert * @param the target converted output * @param the source input value */ - public interface ChainableParameterConverter { + public interface ParameterConverter { /** - * Return {@code true} if the type converter can convert to the desired target type. + * Return {@code true} if the converter can convert to the desired target type. * @param type the type descriptor that describes the requested result type * @return {@code true} if that conversion can be performed */ boolean canConvertTo(Type type); + /** + * Return {@code true} if the converter can convert from the desired target type. + * @param type the type descriptor that describes the source type + * @return {@code true} if that conversion can be performed + */ + boolean canConvertFrom(Type type); + /** * Convert the value from one type to another, for example from a {@code boolean} to a {@code String}. * @param value the value to be converted @@ -548,14 +557,6 @@ public interface ChainableParameterConverter { T convertValue(S value, Type type); } - /** - * A parameter converter for String input values - * - * @param the target converted output - */ - public interface ParameterConverter extends ChainableParameterConverter { - } - @SuppressWarnings("serial") public static class ParameterConversionFailed extends RuntimeException { @@ -568,37 +569,51 @@ public ParameterConversionFailed(String message, Throwable cause) { } } - public abstract static class AbstractParameterConverter extends AbstractChainableParameterConverter implements ParameterConverter { - public AbstractParameterConverter() { + public abstract static class FromStringParameterConverter extends AbstractParameterConverter { + public FromStringParameterConverter() { } - public AbstractParameterConverter(Type targetType) { - super(targetType); + public FromStringParameterConverter(Type targetType) { + super(String.class, targetType); } } - public abstract static class AbstractChainableParameterConverter implements ChainableParameterConverter { + public abstract static class AbstractParameterConverter implements ParameterConverter { + private final Type sourceType; private final Type targetType; - public AbstractChainableParameterConverter() { - this.targetType = getTargetType(getClass()); + public AbstractParameterConverter() { + Map, Type> types = TypeUtils.getTypeArguments(getClass(), ParameterConverter.class); + TypeVariable[] typeVariables = ParameterConverter.class.getTypeParameters(); + this.sourceType = types.get(typeVariables[0]); + this.targetType = types.get(typeVariables[1]); } - public AbstractChainableParameterConverter(Type targetType) { + public AbstractParameterConverter(Type sourceType, Type targetType) { + this.sourceType = sourceType; this.targetType = targetType; } @Override public boolean canConvertTo(Type type) { - if (targetType instanceof Class) { - return isAssignableFrom((Class) targetType, type); + return isAssignable(targetType, type); + } + + @Override + public boolean canConvertFrom(Type type) { + return isAssignable(sourceType, type); + } + + private static boolean isAssignable(Type from, Type to) { + if (from instanceof Class) { + return isAssignableFrom((Class) from, to); } - return targetType.equals(type); + return from.equals(to); } } - public static class FunctionalParameterConverter extends AbstractParameterConverter { + public static class FunctionalParameterConverter extends FromStringParameterConverter { private Function converterFunction; @@ -617,12 +632,12 @@ public T convertValue(String value, Type type) { } } - public abstract static class AbstractListParameterConverter implements ParameterConverter> { + public abstract static class AbstractListParameterConverter extends FromStringParameterConverter> { private final String valueSeparator; - private final ParameterConverter elementConverter; + private final FromStringParameterConverter elementConverter; - public AbstractListParameterConverter(String valueSeparator, ParameterConverter elementConverter) { + public AbstractListParameterConverter(String valueSeparator, FromStringParameterConverter elementConverter) { this.valueSeparator = valueSeparator; this.elementConverter = elementConverter; } @@ -664,7 +679,7 @@ public List convertValue(String value, Type type) { * used to convert numbers in specific locales. *

*/ - public static class NumberConverter extends AbstractParameterConverter { + public static class NumberConverter extends FromStringParameterConverter { private static List> primitiveTypes = asList(new Class[] { byte.class, short.class, int.class, float.class, long.class, double.class }); @@ -806,7 +821,7 @@ public NumberListConverter(NumberFormat numberFormat, String valueSeparator) { } } - public static class StringConverter extends AbstractParameterConverter { + public static class StringConverter extends FromStringParameterConverter { private static final String NEWLINES_PATTERN = "(\n)|(\r\n)"; private static final String SYSTEM_NEWLINE = System.getProperty("line.separator"); @@ -847,7 +862,7 @@ public List convertValue(String value, Type type) { * Parses value to a {@link Date} using an injectable {@link DateFormat} * (defaults to new SimpleDateFormat("dd/MM/yyyy")) */ - public static class DateConverter extends AbstractParameterConverter { + public static class DateConverter extends FromStringParameterConverter { public static final DateFormat DEFAULT_FORMAT = new SimpleDateFormat("dd/MM/yyyy"); @@ -894,7 +909,7 @@ public FileConverter() { } } - public static class BooleanConverter extends AbstractParameterConverter { + public static class BooleanConverter extends FromStringParameterConverter { private final String trueValue; private final String falseValue; @@ -940,7 +955,7 @@ public BooleanListConverter(String valueSeparator, String trueValue, String fals /** * Parses value to any {@link Enum} */ - public static class EnumConverter implements ParameterConverter> { + public static class EnumConverter extends FromStringParameterConverter> { @Override public boolean canConvertTo(Type type) { @@ -1022,7 +1037,7 @@ public ExamplesTableConverter(ExamplesTableFactory factory) { * Converts ExamplesTable to list of parameters, mapped to annotated custom * types. */ - public static class ExamplesTableParametersConverter implements ParameterConverter { + public static class ExamplesTableParametersConverter extends FromStringParameterConverter { private final ExamplesTableFactory factory; @@ -1050,7 +1065,7 @@ public Object convertValue(String value, Type type) { } - public static class JsonConverter implements ParameterConverter { + public static class JsonConverter extends FromStringParameterConverter { private final JsonFactory factory; @@ -1130,7 +1145,7 @@ public Keywords keywords() { /** * Invokes method on instance to return value. */ - public static class MethodReturningConverter implements ParameterConverter { + public static class MethodReturningConverter extends FromStringParameterConverter { private Method method; private Class stepsType; private InjectableStepsFactory stepsFactory; diff --git a/jbehave-core/src/main/java/org/jbehave/core/steps/StepCreator.java b/jbehave-core/src/main/java/org/jbehave/core/steps/StepCreator.java index 448e9b20f..47df53411 100755 --- a/jbehave-core/src/main/java/org/jbehave/core/steps/StepCreator.java +++ b/jbehave-core/src/main/java/org/jbehave/core/steps/StepCreator.java @@ -45,7 +45,7 @@ import org.jbehave.core.model.Verbatim; import org.jbehave.core.parsers.StepMatcher; import org.jbehave.core.reporters.StoryReporter; -import org.jbehave.core.steps.ParameterConverters.ParameterConverter; +import org.jbehave.core.steps.ParameterConverters.FromStringParameterConverter; import org.jbehave.core.steps.context.StepsContext; public class StepCreator { @@ -763,7 +763,7 @@ public StepResult doNotPerform(StoryReporter storyReporter, UUIDExceptionWrapper return perform(storyReporter, storyFailureIfItHappened); } - private class UUIDExceptionWrapperInjector implements ParameterConverter { + private class UUIDExceptionWrapperInjector extends FromStringParameterConverter { private final UUIDExceptionWrapper storyFailureIfItHappened; public UUIDExceptionWrapperInjector(UUIDExceptionWrapper storyFailureIfItHappened) { diff --git a/jbehave-core/src/test/java/org/jbehave/core/configuration/AnnotationBuilderBehaviour.java b/jbehave-core/src/test/java/org/jbehave/core/configuration/AnnotationBuilderBehaviour.java index a791df1b5..8968b04e9 100755 --- a/jbehave-core/src/test/java/org/jbehave/core/configuration/AnnotationBuilderBehaviour.java +++ b/jbehave-core/src/test/java/org/jbehave/core/configuration/AnnotationBuilderBehaviour.java @@ -26,7 +26,7 @@ import org.jbehave.core.embedder.EmbedderControls; import org.jbehave.core.i18n.LocalizedKeywords; import org.jbehave.core.steps.CandidateSteps; -import org.jbehave.core.steps.ParameterConverters.ParameterConverter; +import org.jbehave.core.steps.ParameterConverters.FromStringParameterConverter; import org.jbehave.core.steps.Steps; import org.jbehave.core.steps.scan.GivenOnly; import org.jbehave.core.steps.scan.GivenWhen; @@ -188,7 +188,7 @@ static class Annotated { } - static class MyParameterConverter implements ParameterConverter { + static class MyParameterConverter extends FromStringParameterConverter { @Override public boolean canConvertTo(Type type) { diff --git a/jbehave-core/src/test/java/org/jbehave/core/steps/ParameterConvertersBehaviour.java b/jbehave-core/src/test/java/org/jbehave/core/steps/ParameterConvertersBehaviour.java index b69ebc600..ec6d20ee3 100755 --- a/jbehave-core/src/test/java/org/jbehave/core/steps/ParameterConvertersBehaviour.java +++ b/jbehave-core/src/test/java/org/jbehave/core/steps/ParameterConvertersBehaviour.java @@ -7,6 +7,8 @@ import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -40,6 +42,7 @@ import java.util.Collection; import java.util.Currency; import java.util.Date; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; @@ -66,11 +69,11 @@ import org.jbehave.core.model.ExamplesTableFactory; import org.jbehave.core.model.TableParsers; import org.jbehave.core.model.TableTransformers; -import org.jbehave.core.steps.ParameterConverters.AbstractChainableParameterConverter; import org.jbehave.core.steps.ParameterConverters.AbstractParameterConverter; +import org.jbehave.core.steps.ParameterConverters.FromStringParameterConverter; import org.jbehave.core.steps.ParameterConverters.BooleanConverter; import org.jbehave.core.steps.ParameterConverters.BooleanListConverter; -import org.jbehave.core.steps.ParameterConverters.ChainableParameterConverter; +import org.jbehave.core.steps.ParameterConverters.ParameterConverter; import org.jbehave.core.steps.ParameterConverters.CurrencyConverter; import org.jbehave.core.steps.ParameterConverters.DateConverter; import org.jbehave.core.steps.ParameterConverters.EnumConverter; @@ -83,7 +86,6 @@ import org.jbehave.core.steps.ParameterConverters.NumberConverter; import org.jbehave.core.steps.ParameterConverters.NumberListConverter; import org.jbehave.core.steps.ParameterConverters.ParameterConversionFailed; -import org.jbehave.core.steps.ParameterConverters.ParameterConverter; import org.jbehave.core.steps.ParameterConverters.PatternConverter; import org.jbehave.core.steps.ParameterConverters.StringListConverter; import org.jbehave.core.steps.SomeSteps.MyParameters; @@ -108,7 +110,7 @@ void shouldDefineDefaultConverters() { ParameterConverters converters = new ParameterConverters(resourceLoader, parameterControls, tableTransformers, true); TableParsers tableParsers = new TableParsers(keywords, converters); - ChainableParameterConverter[] defaultConverters = converters.defaultConverters(keywords, resourceLoader, parameterControls, + ParameterConverter[] defaultConverters = converters.defaultConverters(keywords, resourceLoader, parameterControls, tableParsers, tableTransformers, Locale.ENGLISH, ","); assertThatDefaultConvertersInclude(defaultConverters, BooleanConverter.class, NumberConverter.class, StringListConverter.class, @@ -121,11 +123,11 @@ void shouldDefineDefaultConverters() { ExamplesTableParametersConverter.class); } - private void assertThatDefaultConvertersInclude(ChainableParameterConverter[] defaultConverters, - Class>... converterTypes) { - for (Class> type : converterTypes) { + private void assertThatDefaultConvertersInclude(ParameterConverter[] defaultConverters, + Class>... converterTypes) { + for (Class> type : converterTypes) { boolean found = false; - for (ChainableParameterConverter converter : defaultConverters) { + for (ParameterConverter converter : defaultConverters) { if (converter.getClass().isAssignableFrom(type)) { found = true; } @@ -146,11 +148,11 @@ void shouldConvertValuesToNumbersWithDefaultNumberFormat() { @Test void shouldConvertValuesToNumbersWithEnglishNumberFormat() { Locale locale = Locale.ENGLISH; - ParameterConverter converter = new NumberConverter(NumberFormat.getInstance(locale)); + FromStringParameterConverter converter = new NumberConverter(NumberFormat.getInstance(locale)); assertConverterForLocale(converter, locale); } - private void assertConverterForLocale(ParameterConverter converter, Locale locale) { + private void assertConverterForLocale(FromStringParameterConverter converter, Locale locale) { assertThatAllNumberTypesAreAccepted(converter); assertThatAllNumbersAreConverted(converter, locale); assertThat(converter.convertValue("100,000", Integer.class), is((Number) 100000)); @@ -165,7 +167,7 @@ private void assertConverterForLocale(ParameterConverter converter, Loca void shouldConvertValuesToNumbersWithEnglishNumberFormatInMultipleThreads() { final Locale locale = Locale.ENGLISH; final int threads = 3; - final ParameterConverter converter = new NumberConverter(NumberFormat.getInstance(locale)); + final FromStringParameterConverter converter = new NumberConverter(NumberFormat.getInstance(locale)); final BlockingQueue queue = new ArrayBlockingQueue<>(threads); Thread t1 = new Thread() { @Override @@ -205,7 +207,7 @@ public void run() { @Test void shouldConvertValuesToNumbersWithFrenchNumberFormat() { Locale locale = Locale.FRENCH; - ParameterConverter converter = new NumberConverter(NumberFormat.getInstance(locale)); + FromStringParameterConverter converter = new NumberConverter(NumberFormat.getInstance(locale)); assertThatAllNumberTypesAreAccepted(converter); assertThatAllNumbersAreConverted(converter, locale); assertThat(converter.convertValue("100000,01", Float.class), is((Number) 100000.01f)); @@ -215,13 +217,13 @@ void shouldConvertValuesToNumbersWithFrenchNumberFormat() { @Test void shouldConvertValuesToNumbersWithGermanNumberFormat() { Locale locale = Locale.GERMAN; - ParameterConverter converter = new NumberConverter(NumberFormat.getInstance(locale)); + FromStringParameterConverter converter = new NumberConverter(NumberFormat.getInstance(locale)); assertThatAllNumberTypesAreAccepted(converter); assertThatAllNumbersAreConverted(converter, locale); assertThat(converter.convertValue("1.000.000,01", BigDecimal.class), is((Number) new BigDecimal("1000000.01"))); } - private void assertThatAllNumberTypesAreAccepted(ParameterConverter converter) { + private void assertThatAllNumberTypesAreAccepted(FromStringParameterConverter converter) { Type[] numberTypes = { Byte.class, byte.class, @@ -244,7 +246,7 @@ private void assertThatAllNumberTypesAreAccepted(ParameterConverter conv assertThatTypesAreAccepted(converter, numberTypes); } - private void assertThatAllNumbersAreConverted(ParameterConverter converter, Locale locale) { + private void assertThatAllNumbersAreConverted(FromStringParameterConverter converter, Locale locale) { DecimalFormatSymbols format = new DecimalFormatSymbols(locale); char dot = format.getDecimalSeparator(); char minus = format.getMinusSign(); @@ -289,7 +291,7 @@ void shouldFailToConvertInvalidNumbersWithNumberFormat2() { @Test void shouldConvertNaNAndInfinityValuesToNumbers() { - ParameterConverter converter = new NumberConverter(); + FromStringParameterConverter converter = new NumberConverter(); assertThat(converter.convertValue(NAN, Float.class), is((Number) Float.NaN)); assertThat(converter.convertValue(POSITIVE_INFINITY, Float.class), is((Number) Float.POSITIVE_INFINITY)); assertThat(converter.convertValue(NEGATIVE_INFINITY, Float.class), is((Number) Float.NEGATIVE_INFINITY)); @@ -300,7 +302,7 @@ void shouldConvertNaNAndInfinityValuesToNumbers() { @Test void shouldConvertCommaSeparatedValuesToListOfNumbersWithDefaultFormat() { - ParameterConverter> converter = new NumberListConverter(); + FromStringParameterConverter> converter = new NumberListConverter(); Type listOfNumbers = new TypeLiteral>() {}.getType(); Type setOfNumbers = new TypeLiteral>() {}.getType(); assertThat(converter.canConvertTo(listOfNumbers), is(true)); @@ -320,7 +322,7 @@ void shouldConvertCommaSeparatedValuesToSetOfNumbersWithDefaultFormat() { @Test void shouldConvertCommaSeparatedValuesToListOfNumbersWithCustomFormat() { DecimalFormat numberFormat = new DecimalFormat("#,####", DecimalFormatSymbols.getInstance(Locale.ENGLISH)); - ParameterConverter> converter = new NumberListConverter(numberFormat, " "); + FromStringParameterConverter> converter = new NumberListConverter(numberFormat, " "); Type type = new TypeLiteral>() {}.getType(); List list = converter.convertValue("3,000 0.5 6.1f 8.00", type); assertThatCollectionIs(list, 3000L, 0.5, 6.1, 8L); @@ -329,7 +331,7 @@ void shouldConvertCommaSeparatedValuesToListOfNumbersWithCustomFormat() { @SuppressWarnings("unchecked") @Test void shouldConvertCommaSeparatedValuesOfSpecificNumberTypes() { - ParameterConverter converter = new NumberListConverter(); + FromStringParameterConverter converter = new NumberListConverter(); Type doubleType = new TypeLiteral>() {}.getType(); List doubles = (List) converter.convertValue( @@ -380,7 +382,7 @@ void shouldFailToConvertCommaSeparatedValuesOfInvalidNumbers() { @Test void shouldConvertCommaSeparatedValuesToListOfStrings() { - ParameterConverter> converter = new StringListConverter(); + FromStringParameterConverter> converter = new StringListConverter(); Type listOfStrings = new TypeLiteral>() {}.getType(); Type listOfNumbers = new TypeLiteral>() {}.getType(); Type setOfNumbers = new TypeLiteral>() {}.getType(); @@ -393,7 +395,7 @@ void shouldConvertCommaSeparatedValuesToListOfStrings() { @Test void shouldConvertDateWithDefaultFormat() throws ParseException { - ParameterConverter converter = new DateConverter(); + FromStringParameterConverter converter = new DateConverter(); Type type = Date.class; assertThatTypesAreAccepted(converter, type); String date = "01/01/2010"; @@ -403,7 +405,7 @@ void shouldConvertDateWithDefaultFormat() throws ParseException { @Test void shouldConvertDateWithCustomFormat() throws ParseException { DateFormat customFormat = new SimpleDateFormat("yyyy-MM-dd"); - ParameterConverter converter = new DateConverter(customFormat); + FromStringParameterConverter converter = new DateConverter(customFormat); Type type = Date.class; assertThatTypesAreAccepted(converter, type); String date = "2010-01-01"; @@ -442,7 +444,7 @@ void shouldConvertFile() { @Test void shouldConvertMultilineTable() { - ParameterConverter converter = new ExamplesTableConverter( + FromStringParameterConverter converter = new ExamplesTableConverter( new ExamplesTableFactory(new LoadFromClasspath(), new TableTransformers())); Type type = ExamplesTable.class; assertThatTypesAreAccepted(converter, type); @@ -459,7 +461,7 @@ void shouldConvertMultilineTable() { @Test void shouldConvertMultilineTableToParameters() { - ParameterConverter converter = new ExamplesTableParametersConverter( + FromStringParameterConverter converter = new ExamplesTableParametersConverter( new ExamplesTableFactory(new LoadFromClasspath(), new TableTransformers())); Type type = new TypeLiteral>() {}.getType(); assertThatTypesAreAccepted(converter, type); @@ -477,7 +479,7 @@ void shouldConvertMultilineTableToParameters() { @Test void shouldConvertSinglelineTableToParameters() { - ParameterConverter converter = new ExamplesTableParametersConverter( + FromStringParameterConverter converter = new ExamplesTableParametersConverter( new ExamplesTableFactory(new LoadFromClasspath(), new TableTransformers())); Type type = MyParameters.class; assertThatTypesAreAccepted(converter, type); @@ -490,7 +492,7 @@ void shouldConvertSinglelineTableToParameters() { @Test void shouldConvertParameterFromMethodReturningValue() throws IntrospectionException { Method method = SomeSteps.methodFor("aMethodReturningExamplesTable"); - ParameterConverter converter = new MethodReturningConverter(method, new SomeSteps()); + FromStringParameterConverter converter = new MethodReturningConverter(method, new SomeSteps()); assertThatTypesAreAccepted(converter, method.getReturnType()); String value = "|col1|col2|\n|row11|row12|\n|row21|row22|\n"; ExamplesTable table = (ExamplesTable) converter.convertValue(value, ExamplesTable.class); @@ -506,7 +508,7 @@ void shouldConvertParameterFromMethodReturningValue() throws IntrospectionExcept @Test void shouldFailToConvertParameterFromFailingMethodReturningValue() throws IntrospectionException { Method method = SomeSteps.methodFor("aFailingMethodReturningExamplesTable"); - ParameterConverter converter = new MethodReturningConverter(method, new SomeSteps()); + FromStringParameterConverter converter = new MethodReturningConverter(method, new SomeSteps()); String value = "|col1|col2|\n|row11|row12|\n|row21|row22|\n"; assertThrows(ParameterConversionFailed.class, () -> converter.convertValue(value, ExamplesTable.class)); } @@ -519,7 +521,7 @@ void shouldFailToConvertToUnknownType() { @Test void shouldConvertEnum() { - ParameterConverter> converter = new EnumConverter(); + FromStringParameterConverter> converter = new EnumConverter(); Type type = SomeEnum.class; assertThatTypesAreAccepted(converter, type); assertThat(converter.convertValue("ONE", type), is((Enum)SomeEnum.ONE)); @@ -527,7 +529,7 @@ void shouldConvertEnum() { @Test void shouldConvertEnumFluently() { - ParameterConverter> converter = new FluentEnumConverter(); + FromStringParameterConverter> converter = new FluentEnumConverter(); Type type = SomeEnum.class; assertThat(converter.canConvertTo(type), is(true)); assertThat(converter.convertValue("multiple words and 1 number", type), is((Enum)SomeEnum.MULTIPLE_WORDS_AND_1_NUMBER)); @@ -541,7 +543,7 @@ void shouldFailToConvertEnumForValueNotDefined() { @Test void shouldConvertEnumList() { - ParameterConverter converter = new EnumListConverter(); + FromStringParameterConverter converter = new EnumListConverter(); Type type = new TypeLiteral>() {}.getType(); assertThat(converter.canConvertTo(type), is(true)); @@ -551,7 +553,7 @@ void shouldConvertEnumList() { @Test void shouldConvertBoolean() { - ParameterConverter converter = new BooleanConverter(); + FromStringParameterConverter converter = new BooleanConverter(); Type type = Boolean.TYPE; assertThatTypesAreAccepted(converter, type, Boolean.class); assertThat(converter.convertValue("true", type), is(true)); @@ -561,7 +563,7 @@ void shouldConvertBoolean() { @Test void shouldConvertBooleanWithCustomValues() { - ParameterConverter converter = new BooleanConverter("ON", "OFF"); + FromStringParameterConverter converter = new BooleanConverter("ON", "OFF"); Type type = Boolean.TYPE; assertThatTypesAreAccepted(converter, type, Boolean.class); assertThat(converter.convertValue("ON", type), is(true)); @@ -571,7 +573,7 @@ void shouldConvertBooleanWithCustomValues() { @Test void shouldConvertBooleanList() { - ParameterConverter> converter = new BooleanListConverter(); + FromStringParameterConverter> converter = new BooleanListConverter(); Type type = new TypeLiteral>() {}.getType(); assertThat(converter.canConvertTo(type), is(true)); List list = converter.convertValue("true,false,true", type); @@ -797,7 +799,7 @@ void shouldBeEqualDtosConvertedFromJsonWithWhitespaces() { @Test void shouldAceeptParameterizedTypesAutomatically () { - ParameterConverter> parameterizedTypeConverter = new AbstractParameterConverter>() { + FromStringParameterConverter> parameterizedTypeConverter = new FromStringParameterConverter>() { @Override public Set convertValue(String value, Type type) { throw new IllegalStateException("Not implemented"); @@ -914,6 +916,21 @@ void shouldConvertFromStringUsingChainableParameterConverterIfDefaultDoesNotExis assertThat(output.getOutput(), is(inputValue)); } + @Test + void shouldCheckIfWeCanConvertFromType() { + StringContainerConverter simpleChainableConverter = new StringContainerConverter(); + assertTrue(simpleChainableConverter.canConvertFrom(String.class)); + assertFalse(simpleChainableConverter.canConvertFrom(Number.class)); + + ListToSetConverter collectionChainableConverter = new ListToSetConverter(); + assertTrue(collectionChainableConverter.canConvertFrom(new TypeLiteral>() {}.getType())); + assertFalse(collectionChainableConverter.canConvertFrom(new TypeLiteral>() {}.getType())); + + BooleanConverter simpleConverter = new BooleanConverter(); + assertTrue(simpleConverter.canConvertFrom(String.class)); + assertFalse(simpleConverter.canConvertFrom(Boolean.class)); + } + @AsJson public static class MyJsonDto { @@ -954,7 +971,7 @@ private void assertThatCollectionIs(Collection collection, T... expected) } } - private static void assertThatTypesAreAccepted(ParameterConverter converter, Type... types) { + private static void assertThatTypesAreAccepted(FromStringParameterConverter converter, Type... types) { for (Type type : types) { assertThat(converter.canConvertTo(type), is(true)); } @@ -981,14 +998,14 @@ public int compareTo(Bar o) { } } - private class FooToBarParameterConverter extends AbstractParameterConverter { + private class FooToBarParameterConverter extends FromStringParameterConverter { @Override public Bar convertValue(String value, Type type) { return new Bar(); } } - private class FirstParameterConverter extends AbstractChainableParameterConverter { + private class FirstParameterConverter extends AbstractParameterConverter { @Override public FirstConverterOutput convertValue(ExamplesTable value, Type type) { return new FirstConverterOutput(value.asString() + "first"); @@ -1001,7 +1018,7 @@ private FirstConverterOutput(String output) { } } - private class SecondParameterConverter extends AbstractChainableParameterConverter { + private class SecondParameterConverter extends AbstractParameterConverter { @Override public SecondConverterOutput convertValue(FirstConverterOutput value, Type type) { return new SecondConverterOutput(value.getOutput() + "second"); @@ -1014,7 +1031,7 @@ private SecondConverterOutput(String output) { } } - private class ThirdParameterConverter extends AbstractChainableParameterConverter { + private class ThirdParameterConverter extends AbstractParameterConverter { @Override public ThirdConverterOutput convertValue(SecondConverterOutput value, Type type) { return new ThirdConverterOutput(value.getOutput() + "third"); @@ -1039,10 +1056,19 @@ String getOutput() { } } - private class StringContainerConverter extends AbstractChainableParameterConverter { + private class StringContainerConverter extends AbstractParameterConverter { @Override public StringContainer convertValue(String value, Type type) { return new StringContainer(value); } } + + private class ListToSetConverter extends AbstractParameterConverter, Set> { + + @Override + public Set convertValue(List value, Type type) { + return new HashSet<>(value); + } + + } }