Skip to content

[Java] Invoke static methods without instantiating target object #1953

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
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
11 changes: 10 additions & 1 deletion java/src/main/java/io/cucumber/java/AbstractGlueDefinition.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
import io.cucumber.core.backend.Lookup;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import static java.util.Objects.requireNonNull;

abstract class AbstractGlueDefinition implements Located {

protected final Method method;
protected final Lookup lookup;
private final Lookup lookup;
private String fullFormat;

AbstractGlueDefinition(Method method, Lookup lookup) {
Expand All @@ -34,4 +35,12 @@ private String getFullLocationLocation() {
}
return fullFormat;
}

final Object invokeMethod(Object... args) {
if (Modifier.isStatic(method.getModifiers())) {
return Invoker.invokeStatic(this, method, args);
}
return Invoker.invoke(this, lookup.getInstance(method.getDeclaringClass()), method, args);
}

}
8 changes: 8 additions & 0 deletions java/src/main/java/io/cucumber/java/Invoker.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,16 @@ static Object invoke(Annotation annotation, Method expressionMethod) {
return invoke(null, annotation, expressionMethod);
}

static Object invokeStatic(Located located, Method method, Object... args) {
return doInvoke(located, null, method, args);
}

static Object invoke(Located located, Object target, Method method, Object... args) {
Method targetMethod = targetMethod(target, method);
return doInvoke(located, target, targetMethod, args);
}

private static Object doInvoke(Located located, Object target, Method targetMethod, Object[] args) {
boolean accessible = targetMethod.isAccessible();
try {
targetMethod.setAccessible(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,28 +71,36 @@ private DataTableType createDataTableType(Method method) {
if (DataTable.class.equals(parameterType)) {
return new DataTableType(
returnType,
(DataTable table) -> execute(replaceEmptyPatternsWithEmptyString(table))
(DataTable table) -> invokeMethod(
replaceEmptyPatternsWithEmptyString(table)
)
);
}

if (List.class.equals(parameterType)) {
return new DataTableType(
returnType,
(List<String> row) -> execute(replaceEmptyPatternsWithEmptyString(row))
(List<String> row) -> invokeMethod(
replaceEmptyPatternsWithEmptyString(row)
)
);
}

if (Map.class.equals(parameterType)) {
return new DataTableType(
returnType,
(Map<String, String> entry) -> execute(replaceEmptyPatternsWithEmptyString(entry))
(Map<String, String> entry) -> invokeMethod(
replaceEmptyPatternsWithEmptyString(entry)
)
);
}

if (String.class.equals(parameterType)) {
return new DataTableType(
returnType,
(String cell) -> execute(replaceEmptyPatternsWithEmptyString(cell))
(String cell) -> invokeMethod(
replaceEmptyPatternsWithEmptyString(cell)
)
);
}

Expand All @@ -104,8 +112,4 @@ public DataTableType dataTableType() {
return dataTableType;
}

private Object execute(Object arg) {
return Invoker.invoke(this, lookup.getInstance(method.getDeclaringClass()), method, arg);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class JavaDefaultDataTableCellTransformerDefinition extends AbstractDatatableEle
JavaDefaultDataTableCellTransformerDefinition(Method method, Lookup lookup, String[] emptyPatterns) {
super(requireValidMethod(method), lookup, emptyPatterns);
this.transformer = (cellValue, toValueType) ->
execute(replaceEmptyPatternsWithEmptyString(cellValue), toValueType);
invokeMethod(replaceEmptyPatternsWithEmptyString(cellValue), toValueType);
}

private static Method requireValidMethod(Method method) {
Expand Down Expand Up @@ -54,8 +54,4 @@ public TableCellByTypeTransformer tableCellByTypeTransformer() {
return transformer;
}

private Object execute(String fromValue, Type toValueType) {
return Invoker.invoke(this, lookup.getInstance(method.getDeclaringClass()), method, fromValue, toValueType);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ private Object execute(Map<String, String> fromValue, Type toValueType, TableCel
} else {
args = new Object[]{fromValue, toValueType};
}
return Invoker.invoke(this, lookup.getInstance(method.getDeclaringClass()), method, args);
return invokeMethod(args);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class JavaDocStringTypeDefinition extends AbstractGlueDefinition implements DocS
this.docStringType = new DocStringType(
this.method.getReturnType(),
contentType.isEmpty() ? method.getName() : contentType,
this::execute
this::invokeMethod
);
}

Expand Down Expand Up @@ -50,11 +50,6 @@ private static InvalidMethodSignatureException createInvalidSignatureException(M
.build();
}


private Object execute(String content) {
return Invoker.invoke(this, lookup.getInstance(method.getDeclaringClass()), method, content);
}

@Override
public DocStringType docStringType() {
return docStringType;
Expand Down
4 changes: 1 addition & 3 deletions java/src/main/java/io/cucumber/java/JavaHookDefinition.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@ final class JavaHookDefinition extends AbstractGlueDefinition implements HookDef

private final String tagExpression;
private final int order;
private final Lookup lookup;

JavaHookDefinition(Method method, String tagExpression, int order, Lookup lookup) {
super(requireValidMethod(method), lookup);
this.tagExpression = requireNonNull(tagExpression, "tag-expression may not be null");
this.order = order;
this.lookup = lookup;
}

private static Method requireValidMethod(Method method) {
Expand Down Expand Up @@ -58,7 +56,7 @@ public void execute(TestCaseState state) {
args = new Object[0];
}

Invoker.invoke(this, lookup.getInstance(method.getDeclaringClass()), method, args);
invokeMethod(args);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ private Object execute(String[] captureGroups) {
args = captureGroups;
}

return Invoker.invoke(this, lookup.getInstance(method.getDeclaringClass()), method, args);
return invokeMethod(args);
}

}
4 changes: 2 additions & 2 deletions java/src/main/java/io/cucumber/java/JavaStepDefinition.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
import static java.util.Objects.requireNonNull;

final class JavaStepDefinition extends AbstractGlueDefinition implements StepDefinition {
private final String expression;

private final String expression;
private final List<ParameterInfo> parameterInfos;

JavaStepDefinition(Method method,
Expand All @@ -24,7 +24,7 @@ final class JavaStepDefinition extends AbstractGlueDefinition implements StepDef

@Override
public void execute(Object[] args) {
Invoker.invoke(this, lookup.getInstance(method.getDeclaringClass()), method, args);
invokeMethod(args);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ public <T> T getInstance(Class<T> glueClass) {
}
};

private final Lookup lookupForStaticMethod = new Lookup() {
@Override
public <T> T getInstance(Class<T> glueClass) {
throw new IllegalArgumentException("should not be invoked");
}
};

private final DataTable dataTable = DataTable.create(asList(
asList("a", "b"),
asList("c", "d")
Expand Down Expand Up @@ -172,4 +179,17 @@ public String converts_map_of_objects_to_string(Map<Object, Object> entry) {
return "converts_map_of_objects_to_string=" + entry;
}

@Test
void static_methods_are_invoked_without_a_body() throws NoSuchMethodException {
Method method = JavaDataTableTypeDefinitionTest.class.getMethod("static_convert_data_table_to_string", DataTable.class);
JavaDataTableTypeDefinition definition = new JavaDataTableTypeDefinition(method, lookupForStaticMethod, new String[0]);
assertThat(definition.dataTableType().transform(dataTable.asLists()), is("static_convert_data_table_to_string=[[a, b], [c, d]]"));
}

public static String static_convert_data_table_to_string(DataTable table) {
return "static_convert_data_table_to_string=" + table.cells();
}



}