-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathMethodCommand.java
101 lines (85 loc) · 3.54 KB
/
MethodCommand.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package me.earth.headlessmc.runtime.commands;
import lombok.CustomLog;
import lombok.val;
import me.earth.headlessmc.api.command.CommandException;
import me.earth.headlessmc.command.ParseUtil;
import me.earth.headlessmc.runtime.Runtime;
import me.earth.headlessmc.runtime.util.ClassHelper;
import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.Collectors;
@CustomLog
public class MethodCommand extends AbstractReflectionCommand {
public MethodCommand(Runtime ctx) {
super(ctx, "method", "Invokes a method.");
}
@Override
protected void execute(Object o, int address, String... args)
throws CommandException {
if (args.length < 4) {
throw new CommandException("Please specify an address to store the"
+ " result of the method call to.");
}
Class<?> clazz = o instanceof Class ? (Class<?>) o : o.getClass();
val method = getMethod(clazz, args);
if (args.length < method.getParameterTypes().length + 4) {
throw new CommandException(
"Please specify " + method.getParameterTypes().length
+ " addresses to load parameters from and one to"
+ " store the result into.");
}
Object[] arguments = parse(method.getParameterTypes(), args);
int target = ParseUtil.parseI(
args[args.length - method.getParameterTypes().length - 1]);
try {
method.setAccessible(true);
Object value = method.invoke(o, arguments);
ctx.getVm().set(value, target);
} catch (Exception e) {
log.error(e);
}
}
private Method getMethod(Class<?> clazz, String... args)
throws CommandException {
val helper = ClassHelper.of(clazz);
List<Method> methods = helper
.getMethods()
.stream()
.filter(m -> m.getName().equals(args[2]))
.collect(Collectors.toList());
if (methods.isEmpty()) {
throw new CommandException(
"Couldn't find a method for name '" + args[2] + "' in class "
+ helper.getClazz().getName());
}
Method result = methods.get(0);
if (methods.size() > 1) {
val filteredByArgs = methods
.stream()
.filter(m -> ClassHelper.getArgs(true, m.getParameterTypes())
.equals(args[3]))
.findFirst();
if (!filteredByArgs.isPresent()) {
ctx.log("Following methods with name '" + args[2] + "' are "
+ "available in class " + clazz.getName() + ":");
ctx.log(ClassHelper.getMethodTable(methods, true).build());
throw new CommandException(
"Couldn't find method with arguments " + args[3]
+ ", please specify arg types, e.g. '" + args[0]
+ " " + args[1] + " " + args[2] + " \""
+ ClassHelper.getArgs(true, result.getParameterTypes())
+ "\"" + joinArray(3, args) + "'.");
}
result = filteredByArgs.get();
}
return result;
}
@SuppressWarnings("SameParameterValue")
private String joinArray(int startIndex, String... args) {
val sb = new StringBuilder();
for (int i = startIndex; i < args.length; i++) {
sb.append(" ").append(args[i]);
}
return sb.toString();
}
}