Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [Core] Update dependency io.cucumber:html-formatter to v22.1.0
- [Core] Update dependency io.cucumber:junit-xml-formatter to v0.11.0
- [Core] Update dependency io.cucumber:pretty-formatter to v2.4.1
- [Java] Any custom method declared as `@DefaultParameterTransformer` can now have a `Locale` argument to optionally consider the locale declaration of the current Feature ([cucumber/cucumber-expressions#376](https://github.com/cucumber/cucumber-expressions/issues/376) Stefan Gasterstädt)

### Fixed
- [Core] Add OS version to `Meta` message ([#3108](https://github.com/cucumber/cucumber-jvm/pull/3108))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@
import io.cucumber.cucumberexpressions.ParameterByTypeTransformer;
import org.apiguardian.api.API;

import java.util.Locale;

@API(status = API.Status.STABLE)
public interface DefaultParameterTransformerDefinition extends Located {

ParameterByTypeTransformer parameterByTypeTransformer();

default ParameterByTypeTransformer parameterByTypeTransformer(Locale locale) {
return this.parameterByTypeTransformer();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ void prepareGlue(Locale locale) throws DuplicateStepDefinitionException {

if (defaultParameterTransformers.size() == 1) {
DefaultParameterTransformerDefinition definition = defaultParameterTransformers.get(0);
ParameterByTypeTransformer transformer = definition.parameterByTypeTransformer();
ParameterByTypeTransformer transformer = definition.parameterByTypeTransformer(locale);
stepTypeRegistry.setDefaultParameterTransformer(transformer);
} else if (defaultParameterTransformers.size() > 1) {
throw new DuplicateDefaultParameterTransformers(defaultParameterTransformers);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
* <ul>
* <li>{@code String, Type -> Object}</li>
* <li>{@code Object, Type -> Object}</li>
* <li>{@code String, Type, Locale -> Object}</li>
* <li>{@code Object, Type, Locale -> Object}</li>
* </ul>
*
* @see io.cucumber.cucumberexpressions.ParameterByTypeTransformer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,18 @@

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Locale;

import static io.cucumber.java.InvalidMethodSignatureException.builder;

class JavaDefaultParameterTransformerDefinition extends AbstractGlueDefinition
implements DefaultParameterTransformerDefinition {

private final Lookup lookup;
private final ParameterByTypeTransformer transformer;

JavaDefaultParameterTransformerDefinition(Method method, Lookup lookup) {
super(requireValidMethod(method), lookup);
this.lookup = lookup;
this.transformer = this::execute;
}

private static Method requireValidMethod(Method method) {
Expand All @@ -28,7 +27,7 @@ private static Method requireValidMethod(Method method) {
}

Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length != 2) {
if ((parameterTypes.length != 2) || (parameterTypes.length != 3)) {
throw createInvalidSignatureException(method);
}

Expand All @@ -40,24 +39,39 @@ private static Method requireValidMethod(Method method) {
throw createInvalidSignatureException(method);
}

if ((parameterTypes.length == 3) && !Locale.class.equals(parameterTypes[2])) {
throw createInvalidSignatureException(method);
}
return method;
}

private Object execute(String fromValue, Type toValueType) {
return Invoker.invoke(this, lookup.getInstance(method.getDeclaringClass()), method, fromValue, toValueType);
private Object execute(String fromValue, Type toValueType, Locale locale) {
if (method.getParameterTypes().length == 2) {
return Invoker.invoke(this, lookup.getInstance(method.getDeclaringClass()), method, fromValue, toValueType);
} else {
return Invoker.invoke(this, lookup.getInstance(method.getDeclaringClass()), method, fromValue, toValueType,
locale);
}
}

private static InvalidMethodSignatureException createInvalidSignatureException(Method method) {
return builder(method)
.addAnnotation(DefaultParameterTransformer.class)
.addSignature("public Object defaultDataTableEntry(String fromValue, Type toValueType)")
.addSignature("public Object defaultDataTableEntry(Object fromValue, Type toValueType)")
.addSignature("public Object defaultDataTableEntry(String fromValue, Type toValueType, Locale locale)")
.addSignature("public Object defaultDataTableEntry(Object fromValue, Type toValueType, Locale locale)")
.build();
}

@Override
public ParameterByTypeTransformer parameterByTypeTransformer() {
return transformer;
return this.parameterByTypeTransformer(null);
}

@Override
public ParameterByTypeTransformer parameterByTypeTransformer(Locale locale) {
return (fromValue, toValueType) -> execute(fromValue, toValueType, locale);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This puts state in an otherwise stateless component.

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Locale;
import java.util.Map;

import static org.hamcrest.CoreMatchers.startsWith;
Expand Down Expand Up @@ -33,10 +34,34 @@ void can_transform_string_to_type() throws Throwable {
assertThat(transformed, is("transform_string_to_type"));
}

@Test
void can_transform_string_to_type_ignoring_locale() throws Throwable {
Method method = JavaDefaultParameterTransformerDefinitionTest.class.getMethod("transform_string_to_type",
String.class, Type.class);
JavaDefaultParameterTransformerDefinition definition = new JavaDefaultParameterTransformerDefinition(method,
lookup);
Object transformed = definition.parameterByTypeTransformer(Locale.ENGLISH).transform("something", String.class);
assertThat(transformed, is("transform_string_to_type"));
}

public Object transform_string_to_type(String fromValue, Type toValueType) {
return "transform_string_to_type";
}

@Test
void can_transform_string_to_type_using_locale() throws Throwable {
Method method = JavaDefaultParameterTransformerDefinitionTest.class.getMethod(
"transform_string_to_type_with_locale", String.class, Type.class, Locale.class);
JavaDefaultParameterTransformerDefinition definition = new JavaDefaultParameterTransformerDefinition(method,
lookup);
Object transformed = definition.parameterByTypeTransformer(Locale.ENGLISH).transform("something", String.class);
assertThat(transformed, is("transform_string_to_type_with_locale_en"));
}

public Object transform_string_to_type_with_locale(String fromValue, Type toValueType, Locale locale) {
return "transform_string_to_type_with_locale_" + locale.getLanguage();
}

@Test
void can_transform_object_to_type() throws Throwable {
Method method = JavaDefaultParameterTransformerDefinitionTest.class.getMethod("transform_object_to_type",
Expand All @@ -47,10 +72,36 @@ void can_transform_object_to_type() throws Throwable {
assertThat(transformed, is("transform_object_to_type"));
}

@Test
void can_transform_object_to_type_ignoring_locale() throws Throwable {
Method method = JavaDefaultParameterTransformerDefinitionTest.class.getMethod("transform_object_to_type",
Object.class, Type.class);
JavaDefaultParameterTransformerDefinition definition = new JavaDefaultParameterTransformerDefinition(method,
lookup);
String transformed = (String) definition.parameterByTypeTransformer(Locale.ENGLISH).transform("something",
String.class);
assertThat(transformed, is("transform_object_to_type"));
}

public Object transform_object_to_type(Object fromValue, Type toValueType) {
return "transform_object_to_type";
}

@Test
void can_transform_object_to_type_using_locale() throws Throwable {
Method method = JavaDefaultParameterTransformerDefinitionTest.class.getMethod(
"transform_object_to_type_with_locale", Object.class, Type.class, Locale.class);
JavaDefaultParameterTransformerDefinition definition = new JavaDefaultParameterTransformerDefinition(method,
lookup);
String transformed = (String) definition.parameterByTypeTransformer(Locale.ENGLISH).transform("something",
String.class);
assertThat(transformed, is("transform_object_to_type_with_locale_en"));
}

public Object transform_object_to_type_with_locale(Object fromValue, Type toValueType, Locale locale) {
return "transform_object_to_type_with_locale_" + locale.getLanguage();
}

@Test
void must_have_non_void_return() throws Throwable {
Method method = JavaDefaultParameterTransformerDefinitionTest.class.getMethod("transforms_string_to_void",
Expand All @@ -61,35 +112,41 @@ void must_have_non_void_return() throws Throwable {
"A @DefaultParameterTransformer annotated method must have one of these signatures:\n" +
" * public Object defaultDataTableEntry(String fromValue, Type toValueType)\n" +
" * public Object defaultDataTableEntry(Object fromValue, Type toValueType)\n" +
" * public Object defaultDataTableEntry(Object fromValue, Type toValueType, Locale locale)\n" +
" * public Object defaultDataTableEntry(Object fromValue, Type toValueType, Locale locale)\n" +
"at io.cucumber.java.JavaDefaultParameterTransformerDefinitionTest.transforms_string_to_void(java.lang.String,java.lang.reflect.Type)"));
}

public void transforms_string_to_void(String fromValue, Type toValueType) {
}

@Test
void must_have_two_arguments() throws Throwable {
void must_have_two_or_three_arguments() throws Throwable {
Method oneArg = JavaDefaultParameterTransformerDefinitionTest.class.getMethod("one_argument", String.class);
assertThrows(InvalidMethodSignatureException.class,
() -> new JavaDefaultParameterTransformerDefinition(oneArg, lookup));
Method threeArg = JavaDefaultParameterTransformerDefinitionTest.class.getMethod("three_arguments", String.class,
Method fourArg = JavaDefaultParameterTransformerDefinitionTest.class.getMethod("four_arguments", String.class,
Type.class, Object.class);
assertThrows(InvalidMethodSignatureException.class,
() -> new JavaDefaultParameterTransformerDefinition(threeArg, lookup));
() -> new JavaDefaultParameterTransformerDefinition(fourArg, lookup));
}

public Object one_argument(String fromValue) {
return "one_arguments";
return "one_argument";
}

public Object three_arguments(String fromValue, Type toValueType, Object extra) {
return "three_arguments";
public Object four_arguments(String fromValue, Type toValueType, Locale locale, Object extra) {
return "four_arguments";
}

@Test
void must_have_string_or_object_as_from_value() throws Throwable {
Method threeArg = JavaDefaultParameterTransformerDefinitionTest.class.getMethod("map_as_from_value", Map.class,
Method twoArg = JavaDefaultParameterTransformerDefinitionTest.class.getMethod("map_as_from_value", Map.class,
Type.class);
assertThrows(InvalidMethodSignatureException.class,
() -> new JavaDefaultParameterTransformerDefinition(twoArg, lookup));
Method threeArg = JavaDefaultParameterTransformerDefinitionTest.class.getMethod("map_as_from_value_with_locale",
Map.class, Type.class, Locale.class);
assertThrows(InvalidMethodSignatureException.class,
() -> new JavaDefaultParameterTransformerDefinition(threeArg, lookup));
}
Expand All @@ -98,10 +155,18 @@ public Object map_as_from_value(Map<String, String> fromValue, Type toValueType)
return "map_as_from_value";
}

public Object map_as_from_value_with_locale(Map<String, String> fromValue, Type toValueType, Locale locale) {
return "map_as_from_value_with_locale";
}

@Test
void must_have_type_as_to_value_type() throws Throwable {
Method threeArg = JavaDefaultParameterTransformerDefinitionTest.class.getMethod("object_as_to_value_type",
Method twoArg = JavaDefaultParameterTransformerDefinitionTest.class.getMethod("object_as_to_value_type",
String.class, Object.class);
assertThrows(InvalidMethodSignatureException.class,
() -> new JavaDefaultParameterTransformerDefinition(twoArg, lookup));
Method threeArg = JavaDefaultParameterTransformerDefinitionTest.class.getMethod(
"object_as_to_value_type_with_locale", String.class, Object.class, Locale.class);
assertThrows(InvalidMethodSignatureException.class,
() -> new JavaDefaultParameterTransformerDefinition(threeArg, lookup));
}
Expand All @@ -110,4 +175,8 @@ public Object object_as_to_value_type(String fromValue, Object toValueType) {
return "object_as_to_value_type";
}

public Object object_as_to_value_type_with_locale(String fromValue, Object toValueType, Locale locale) {
return "object_as_to_value_type_with_locale";
}

}