Skip to content

Commit c144e7e

Browse files
committed
[Java] Add annotation for DefaultParameterTransformer hook
1 parent 2c0a0e5 commit c144e7e

File tree

7 files changed

+183
-1
lines changed

7 files changed

+183
-1
lines changed

java/README.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
Cucumber Java
2+
=============
3+
4+
Provides annotation based step definitions. To use add the `cucumber-java` dependency to your pom.xml:
5+
6+
```xml
7+
<dependencies>
8+
[...]
9+
<dependency>
10+
<groupId>io.cucumber</groupId>
11+
<artifactId>cucumber-java</artifactId>
12+
<version>${cucumber.version}</version>
13+
<scope>test</scope>
14+
</dependency>
15+
[...]
16+
</dependencies>
17+
```
18+
19+
## Step Definitions
20+
21+
Use annotations to mark methods as steps. For localized annotations import from `io.cucumber.java.<ISO2 Language Code>`
22+
23+
24+
```java
25+
import io.cucumber.java.en.Given;
26+
import io.cucumber.java.en.Then;
27+
import io.cucumber.java.en.When;
28+
29+
import static org.junit.Assert.assertEquals;
30+
31+
public class CalculatorSteps{
32+
private RpnCalculator calc;
33+
34+
@Given("a calculator I just turned on")
35+
public void a_calculator_I_just_turned_on() {
36+
calc = new RpnCalculator();
37+
}
38+
39+
@When("I add {int} and {int}")
40+
public void adding(int arg1, int arg2) {
41+
calc.push(arg1);
42+
calc.push(arg2);
43+
calc.push("+");
44+
}
45+
46+
@Then("the result is {int}")
47+
public void the_result_is(double expected) {
48+
assertEquals(expected, calc.value());
49+
}
50+
}
51+
```
52+
53+
## TODO: Hooks
54+
* `@Before`
55+
* `@After`
56+
* `@BeforeStep`
57+
* `@AfterStep`
58+
59+
## TODO: Transformers
60+
* `@DefaultParameterTransformer`
61+
* `@DefaultDataTableEntryTransformer`
62+
* `@DefaultDataTableCellTransformer`
63+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package io.cucumber.java;
2+
3+
import org.apiguardian.api.API;
4+
5+
import java.lang.annotation.ElementType;
6+
import java.lang.annotation.Retention;
7+
import java.lang.annotation.RetentionPolicy;
8+
import java.lang.annotation.Target;
9+
10+
/**
11+
* Allows a default transformer for all parameters to be registered.
12+
* <p>
13+
* Supports ParameterByTypeTransformer: String,Type -> T
14+
* Supports ParameterByTypeTransformer: Object,Type -> T
15+
*/
16+
@Retention(RetentionPolicy.RUNTIME)
17+
@Target(ElementType.METHOD)
18+
@API(status = API.Status.STABLE)
19+
public @interface DefaultParameterTransformer {
20+
21+
}

java/src/main/java/io/cucumber/java/JavaBackend.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ void addHook(Annotation annotation, Method method) {
9696
glue.addParameterType(new JavaParameterTypeDefinition(name, pattern, method, useForSnippets, preferForRegexMatch, lookup));
9797
} else if (annotation.annotationType().equals(DataTableType.class)) {
9898
glue.addDataTableType(new JavaDataTableTypeDefinition(method, lookup));
99+
}else if (annotation.annotationType().equals(DefaultParameterTransformer.class)) {
100+
glue.addDefaultParameterTransformer(new JavaDefaultParameterTransformerDefinition(method, lookup));
99101
}
100102
}
101103
}

java/src/main/java/io/cucumber/java/JavaDataTableTypeDefinition.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import io.cucumber.core.backend.DataTableTypeDefinition;
44
import io.cucumber.core.backend.Lookup;
55
import io.cucumber.core.exception.CucumberException;
6+
import io.cucumber.core.reflection.MethodFormat;
67
import io.cucumber.core.runtime.Invoker;
78
import io.cucumber.datatable.DataTable;
89
import io.cucumber.datatable.DataTableType;
@@ -22,11 +23,15 @@ class JavaDataTableTypeDefinition implements DataTableTypeDefinition {
2223
private final Method method;
2324
private final Lookup lookup;
2425
private final DataTableType dataTableType;
26+
private final String shortFormat;
27+
private final String fullFormat;
2528

2629
JavaDataTableTypeDefinition(Method method, Lookup lookup) {
2730
this.method = method;
2831
this.lookup = lookup;
2932
this.dataTableType = createDataTableType(method);
33+
this.shortFormat = MethodFormat.SHORT.format(method);
34+
this.fullFormat = MethodFormat.FULL.format(method);
3035
}
3136

3237
@SuppressWarnings("unchecked")
@@ -114,6 +119,10 @@ public DataTableType dataTableType() {
114119
return dataTableType;
115120
}
116121

122+
@Override
123+
public String getLocation(boolean detail) {
124+
return detail ? fullFormat : shortFormat;
125+
}
117126

118127
private Object execute(Object arg) throws Throwable {
119128
return Invoker.invoke(lookup.getInstance(method.getDeclaringClass()), method, 0, arg);
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package io.cucumber.java;
2+
3+
import io.cucumber.core.backend.DefaultParameterTransformerDefinition;
4+
import io.cucumber.core.backend.Lookup;
5+
import io.cucumber.core.exception.CucumberException;
6+
import io.cucumber.core.reflection.MethodFormat;
7+
import io.cucumber.core.runtime.Invoker;
8+
import io.cucumber.cucumberexpressions.ParameterByTypeTransformer;
9+
10+
import java.lang.reflect.Method;
11+
import java.lang.reflect.Type;
12+
13+
class JavaDefaultParameterTransformerDefinition implements DefaultParameterTransformerDefinition {
14+
15+
private final Method method;
16+
17+
private final Lookup lookup;
18+
private final ParameterByTypeTransformer transformer;
19+
private final String shortFormat;
20+
private final String fullFormat;
21+
22+
JavaDefaultParameterTransformerDefinition(Method method, Lookup lookup) {
23+
this.method = requireValidMethod(method);
24+
this.lookup = lookup;
25+
this.shortFormat = MethodFormat.SHORT.format(method);
26+
this.fullFormat = MethodFormat.FULL.format(method);
27+
this.transformer = this::execute;
28+
}
29+
30+
private Method requireValidMethod(Method method) {
31+
Class<?> returnType = method.getReturnType();
32+
if (Void.class.equals(returnType)) {
33+
throw createInvalidSignatureException();
34+
}
35+
36+
Class<?>[] parameterTypes = method.getParameterTypes();
37+
if (parameterTypes.length != 2) {
38+
throw createInvalidSignatureException();
39+
}
40+
41+
if (!(String.class.equals(parameterTypes[0]) || Object.class.equals(parameterTypes[0]))) {
42+
throw createInvalidSignatureException();
43+
}
44+
45+
if (!Type.class.equals(parameterTypes[1])) {
46+
throw createInvalidSignatureException();
47+
}
48+
49+
return method;
50+
}
51+
52+
private CucumberException createInvalidSignatureException() {
53+
return new CucumberException("" +
54+
"A @DefaultParameterTransformer annotated method must have one of these signature:\n" +
55+
" * public Object defaultParameter(String fromValue, Type toValueType)\n" +
56+
" * public Object defaultParameter(Object fromValue, Type toValueType)\n"
57+
);
58+
}
59+
60+
@Override
61+
public ParameterByTypeTransformer parameterByTypeTransformer() {
62+
return transformer;
63+
}
64+
65+
@Override
66+
public String getLocation(boolean detail) {
67+
return detail ? fullFormat : shortFormat;
68+
}
69+
70+
private Object execute(String fromValue, Type toValueType) throws Throwable {
71+
return Invoker.invoke(lookup.getInstance(method.getDeclaringClass()), method, 0, fromValue, toValueType);
72+
}
73+
74+
}

java/src/main/java/io/cucumber/java/JavaParameterTypeDefinition.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,32 @@
33
import io.cucumber.core.backend.Lookup;
44
import io.cucumber.core.backend.ParameterTypeDefinition;
55
import io.cucumber.core.exception.CucumberException;
6+
import io.cucumber.core.reflection.MethodFormat;
67
import io.cucumber.core.runtime.Invoker;
78
import io.cucumber.cucumberexpressions.ParameterType;
89

910
import java.lang.reflect.Method;
1011
import java.util.Collections;
1112

13+
import static java.util.Collections.singletonList;
14+
1215
class JavaParameterTypeDefinition implements ParameterTypeDefinition {
1316

1417
private final Method method;
1518

1619
private final Lookup lookup;
1720
private final ParameterType<Object> parameterType;
21+
private final String shortFormat;
22+
private final String fullFormat;
1823

1924
JavaParameterTypeDefinition(String name, String pattern, Method method, boolean useForSnippets, boolean preferForRegexpMatch, Lookup lookup) {
2025
this.method = requireValidMethod(method);
2126
this.lookup = lookup;
27+
this.shortFormat = MethodFormat.SHORT.format(method);
28+
this.fullFormat = MethodFormat.FULL.format(method);
2229
this.parameterType = new ParameterType<>(
2330
name.isEmpty() ? method.getName() : name,
24-
Collections.singletonList(pattern),
31+
singletonList(pattern),
2532
this.method.getReturnType(),
2633
this::execute,
2734
useForSnippets,
@@ -64,6 +71,11 @@ public ParameterType<?> parameterType() {
6471
return parameterType;
6572
}
6673

74+
@Override
75+
public String getLocation(boolean detail) {
76+
return detail ? fullFormat : shortFormat;
77+
}
78+
6779
private Object execute(Object[] args) throws Throwable {
6880
return Invoker.invoke(lookup.getInstance(method.getDeclaringClass()), method, 0, args);
6981
}

java/src/main/java/io/cucumber/java/MethodScanner.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ private boolean isHookAnnotation(Annotation annotation) {
8585
|| annotationClass.equals(AfterStep.class)
8686
|| annotationClass.equals(ParameterType.class)
8787
|| annotationClass.equals(DataTableType.class)
88+
|| annotationClass.equals(DefaultParameterTransformer.class)
8889
;
8990
}
9091

0 commit comments

Comments
 (0)