From 9e559f415f36a41c053f0c7962c06cd16692a9a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Gasterst=C3=A4dt?= <157380642+antagoony@users.noreply.github.com> Date: Sun, 23 Nov 2025 23:37:29 +0100 Subject: [PATCH 1/5] synchronize test-methode's name and result String --- .../java/JavaDefaultParameterTransformerDefinitionTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cucumber-java/src/test/java/io/cucumber/java/JavaDefaultParameterTransformerDefinitionTest.java b/cucumber-java/src/test/java/io/cucumber/java/JavaDefaultParameterTransformerDefinitionTest.java index fe7b184eec..c104aa457d 100644 --- a/cucumber-java/src/test/java/io/cucumber/java/JavaDefaultParameterTransformerDefinitionTest.java +++ b/cucumber-java/src/test/java/io/cucumber/java/JavaDefaultParameterTransformerDefinitionTest.java @@ -79,7 +79,7 @@ void must_have_two_arguments() throws Throwable { } public Object one_argument(String fromValue) { - return "one_arguments"; + return "one_argument"; } public Object three_arguments(String fromValue, Type toValueType, Object extra) { From 391cbd4bab225c1de1f77fbc54326358340172a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Gasterst=C3=A4dt?= <157380642+antagoony@users.noreply.github.com> Date: Sun, 23 Nov 2025 23:40:20 +0100 Subject: [PATCH 2/5] synchronize variable name and referred method's number of arguments --- .../JavaDefaultParameterTransformerDefinitionTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cucumber-java/src/test/java/io/cucumber/java/JavaDefaultParameterTransformerDefinitionTest.java b/cucumber-java/src/test/java/io/cucumber/java/JavaDefaultParameterTransformerDefinitionTest.java index c104aa457d..f69c6c6cf5 100644 --- a/cucumber-java/src/test/java/io/cucumber/java/JavaDefaultParameterTransformerDefinitionTest.java +++ b/cucumber-java/src/test/java/io/cucumber/java/JavaDefaultParameterTransformerDefinitionTest.java @@ -88,10 +88,10 @@ public Object three_arguments(String fromValue, Type toValueType, Object extra) @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(threeArg, lookup)); + () -> new JavaDefaultParameterTransformerDefinition(twoArg, lookup)); } public Object map_as_from_value(Map fromValue, Type toValueType) { @@ -100,10 +100,10 @@ public Object map_as_from_value(Map fromValue, Type toValueType) @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(threeArg, lookup)); + () -> new JavaDefaultParameterTransformerDefinition(twoArg, lookup)); } public Object object_as_to_value_type(String fromValue, Object toValueType) { From ca31982a5c47212205dde99adf33c389cf01582e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Gasterst=C3=A4dt?= <157380642+antagoony@users.noreply.github.com> Date: Sun, 23 Nov 2025 23:43:34 +0100 Subject: [PATCH 3/5] declare a locale aware creation of the ParameterByTypeTransformer --- .../core/backend/DefaultParameterTransformerDefinition.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cucumber-core/src/main/java/io/cucumber/core/backend/DefaultParameterTransformerDefinition.java b/cucumber-core/src/main/java/io/cucumber/core/backend/DefaultParameterTransformerDefinition.java index ddc9248701..4cbac1736c 100644 --- a/cucumber-core/src/main/java/io/cucumber/core/backend/DefaultParameterTransformerDefinition.java +++ b/cucumber-core/src/main/java/io/cucumber/core/backend/DefaultParameterTransformerDefinition.java @@ -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(); + } + } From e284caa7a12220a2d1a8af19bb94bc9f5a57181a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Gasterst=C3=A4dt?= <157380642+antagoony@users.noreply.github.com> Date: Sun, 23 Nov 2025 23:49:33 +0100 Subject: [PATCH 4/5] implement the locale aware creation of the ParameterByTypeTransformer --- .../io/cucumber/core/runner/CachingGlue.java | 2 +- ...DefaultParameterTransformerDefinition.java | 24 ++++-- ...ultParameterTransformerDefinitionTest.java | 77 +++++++++++++++++-- 3 files changed, 91 insertions(+), 12 deletions(-) diff --git a/cucumber-core/src/main/java/io/cucumber/core/runner/CachingGlue.java b/cucumber-core/src/main/java/io/cucumber/core/runner/CachingGlue.java index fbdbd66d52..26a1f4a461 100644 --- a/cucumber-core/src/main/java/io/cucumber/core/runner/CachingGlue.java +++ b/cucumber-core/src/main/java/io/cucumber/core/runner/CachingGlue.java @@ -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); diff --git a/cucumber-java/src/main/java/io/cucumber/java/JavaDefaultParameterTransformerDefinition.java b/cucumber-java/src/main/java/io/cucumber/java/JavaDefaultParameterTransformerDefinition.java index 873e03562d..b2726ccd41 100644 --- a/cucumber-java/src/main/java/io/cucumber/java/JavaDefaultParameterTransformerDefinition.java +++ b/cucumber-java/src/main/java/io/cucumber/java/JavaDefaultParameterTransformerDefinition.java @@ -6,6 +6,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Type; +import java.util.Locale; import static io.cucumber.java.InvalidMethodSignatureException.builder; @@ -13,12 +14,10 @@ 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) { @@ -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); } @@ -40,11 +39,19 @@ 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) { @@ -57,7 +64,12 @@ private static InvalidMethodSignatureException createInvalidSignatureException(M @Override public ParameterByTypeTransformer parameterByTypeTransformer() { - return transformer; + return this.parameterByTypeTransformer(null); + } + + @Override + public ParameterByTypeTransformer parameterByTypeTransformer(Locale locale) { + return (fromValue, toValueType) -> execute(fromValue, toValueType, locale); } } diff --git a/cucumber-java/src/test/java/io/cucumber/java/JavaDefaultParameterTransformerDefinitionTest.java b/cucumber-java/src/test/java/io/cucumber/java/JavaDefaultParameterTransformerDefinitionTest.java index f69c6c6cf5..c9e843f9da 100644 --- a/cucumber-java/src/test/java/io/cucumber/java/JavaDefaultParameterTransformerDefinitionTest.java +++ b/cucumber-java/src/test/java/io/cucumber/java/JavaDefaultParameterTransformerDefinitionTest.java @@ -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; @@ -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", @@ -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", @@ -68,22 +119,22 @@ 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_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 @@ -92,22 +143,38 @@ void must_have_string_or_object_as_from_value() throws Throwable { 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)); } public Object map_as_from_value(Map fromValue, Type toValueType) { return "map_as_from_value"; } + public Object map_as_from_value_with_locale(Map fromValue, Type toValueType, Locale locale) { + return "map_as_from_value_with_locale"; + } + @Test void must_have_type_as_to_value_type() throws Throwable { 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)); } 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"; + } + } From 4901e15fe5794294dc9a989751693f64f96eeb07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Gasterst=C3=A4dt?= <157380642+antagoony@users.noreply.github.com> Date: Sun, 23 Nov 2025 23:49:56 +0100 Subject: [PATCH 5/5] document the locale aware creation of the ParameterByTypeTransformer --- CHANGELOG.md | 1 + .../main/java/io/cucumber/java/DefaultParameterTransformer.java | 2 ++ .../java/JavaDefaultParameterTransformerDefinition.java | 2 ++ .../java/JavaDefaultParameterTransformerDefinitionTest.java | 2 ++ 4 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88aad4b570..736afc04c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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)) diff --git a/cucumber-java/src/main/java/io/cucumber/java/DefaultParameterTransformer.java b/cucumber-java/src/main/java/io/cucumber/java/DefaultParameterTransformer.java index 1986fe5fa9..7d8d2fdbf6 100644 --- a/cucumber-java/src/main/java/io/cucumber/java/DefaultParameterTransformer.java +++ b/cucumber-java/src/main/java/io/cucumber/java/DefaultParameterTransformer.java @@ -14,6 +14,8 @@ *
    *
  • {@code String, Type -> Object}
  • *
  • {@code Object, Type -> Object}
  • + *
  • {@code String, Type, Locale -> Object}
  • + *
  • {@code Object, Type, Locale -> Object}
  • *
* * @see io.cucumber.cucumberexpressions.ParameterByTypeTransformer diff --git a/cucumber-java/src/main/java/io/cucumber/java/JavaDefaultParameterTransformerDefinition.java b/cucumber-java/src/main/java/io/cucumber/java/JavaDefaultParameterTransformerDefinition.java index b2726ccd41..59609c587c 100644 --- a/cucumber-java/src/main/java/io/cucumber/java/JavaDefaultParameterTransformerDefinition.java +++ b/cucumber-java/src/main/java/io/cucumber/java/JavaDefaultParameterTransformerDefinition.java @@ -59,6 +59,8 @@ private static InvalidMethodSignatureException createInvalidSignatureException(M .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(); } diff --git a/cucumber-java/src/test/java/io/cucumber/java/JavaDefaultParameterTransformerDefinitionTest.java b/cucumber-java/src/test/java/io/cucumber/java/JavaDefaultParameterTransformerDefinitionTest.java index c9e843f9da..bbad1f86ba 100644 --- a/cucumber-java/src/test/java/io/cucumber/java/JavaDefaultParameterTransformerDefinitionTest.java +++ b/cucumber-java/src/test/java/io/cucumber/java/JavaDefaultParameterTransformerDefinitionTest.java @@ -112,6 +112,8 @@ 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)")); }