Skip to content

Commit 563b004

Browse files
author
Jason Feinstein
committed
Create new command call
* `call` allows you to call any method on an object, regardless of access modifiers * Created new command annotation: ParamName, to show parameter names in the results of `help()` * Changed formatting of `help()`
1 parent de6c815 commit 563b004

File tree

12 files changed

+247
-68
lines changed

12 files changed

+247
-68
lines changed

app/src/main/java/jwf/debugport/app/App.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,8 @@ public int[] getIntArray() {
4444
public void setIntArray(int[] arry) {
4545
mIntArray = arry;
4646
}
47+
48+
public void setIntArrayVarArg(int... arr) {
49+
mIntArray = arr;
50+
}
4751
}

library/src/main/java/jwf/debugport/annotations/Command.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,10 @@
1717
@interface Help {
1818
String value() default "";
1919
}
20+
21+
@Target(ElementType.PARAMETER)
22+
@Retention(RetentionPolicy.RUNTIME)
23+
@interface ParamName {
24+
String value() default "";
25+
}
2026
}

library/src/main/java/jwf/debugport/commands/Commands.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public final class Commands {
1818
help.registerCommand(fieldsLocal.class);
1919
help.registerCommand(get.class);
2020
help.registerCommand(set.class);
21+
help.registerCommand(call.class);
2122
}
2223

2324
public Commands(ExitListener listener) {
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package jwf.debugport.commands;
2+
3+
import java.lang.reflect.InvocationTargetException;
4+
import java.lang.reflect.Method;
5+
6+
import bsh.CallStack;
7+
import bsh.Interpreter;
8+
import jwf.debugport.annotations.Command;
9+
10+
/**
11+
*
12+
*/
13+
@Command
14+
public class call {
15+
/*
16+
* In order to support a varargs-like behavior when the command is called with no third
17+
* parameter, we have to supply several methods.. beanshell doesn't really support varargs well.
18+
*/
19+
public static Object invoke(
20+
Interpreter interpreter,
21+
CallStack callStack,
22+
Object object,
23+
String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
24+
return invokeInner(object, methodName, null);
25+
}
26+
27+
public static Object invoke(
28+
Interpreter interpreter,
29+
CallStack callStack,
30+
Object object,
31+
String methodName,
32+
Object p1) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
33+
return invokeInner(object, methodName, p1);
34+
}
35+
36+
public static Object invoke(
37+
Interpreter interpreter,
38+
CallStack callStack,
39+
Object object,
40+
String methodName,
41+
Object p1,
42+
Object p2) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
43+
return invokeInner(object, methodName, p1, p2);
44+
}
45+
46+
public static Object invoke(
47+
Interpreter interpreter,
48+
CallStack callStack,
49+
Object object,
50+
String methodName,
51+
Object p1,
52+
Object p2,
53+
Object p3) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
54+
return invokeInner(object, methodName, p1, p2, p3);
55+
}
56+
57+
public static Object invoke(
58+
Interpreter interpreter,
59+
CallStack callStack,
60+
Object object,
61+
String methodName,
62+
Object p1,
63+
Object p2,
64+
Object p3,
65+
Object p4) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
66+
return invokeInner(object, methodName, p1, p2, p3, p4);
67+
}
68+
69+
public static Object invoke(
70+
Interpreter interpreter,
71+
CallStack callStack,
72+
Object object,
73+
String methodName,
74+
Object p1,
75+
Object p2,
76+
Object p3,
77+
Object p4,
78+
Object p5) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
79+
return invokeInner(object, methodName, p1, p2, p3, p4, p5);
80+
}
81+
82+
public static Object invoke(
83+
Interpreter interpreter,
84+
CallStack callStack,
85+
Object object,
86+
String methodName,
87+
Object p1,
88+
Object p2,
89+
Object p3,
90+
Object p4,
91+
Object p5,
92+
Object p6) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
93+
return invokeInner(object, methodName, p1, p2, p3, p4, p5, p6);
94+
}
95+
96+
@Command.Help("Call a method, regardless of access modifiers, on the provided object.")
97+
public static Object invoke(
98+
Interpreter interpreter,
99+
CallStack callStack,
100+
@Command.ParamName("obj") Object object,
101+
@Command.ParamName("method") String methodName,
102+
@Command.ParamName("params") Object... params) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
103+
return invokeInner(object, methodName, params);
104+
}
105+
106+
private static Object invokeInner(
107+
Object object,
108+
String methodName,
109+
Object... params) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
110+
Method method;
111+
Class<?>[] paramClasses = new Class<?>[0];
112+
if (params != null) {
113+
paramClasses = new Class<?>[params.length];
114+
for (int i = 0; i < params.length; i++) {
115+
paramClasses[i] = params[i].getClass();
116+
}
117+
}
118+
119+
try {
120+
method = object.getClass().getDeclaredMethod(methodName, paramClasses);
121+
} catch (NoSuchMethodException e) {
122+
// try a method on a parent of the object's class
123+
method = object.getClass().getMethod(methodName, paramClasses);
124+
}
125+
method.setAccessible(true);
126+
return method.invoke(object, params);
127+
}
128+
}

library/src/main/java/jwf/debugport/commands/descriptors/MethodDescriptor.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,21 +44,35 @@ public String toString() {
4444
sb.append(getName());
4545
sb.append("(");
4646
try {
47+
Class<?>[] params = mMethod.getParameterTypes();
4748
Type[] genericParams = mMethod.getGenericParameterTypes();
4849
for (int i = 0; i < genericParams.length; i++) {
4950
if (i != 0) {
5051
sb.append(", ");
5152
}
5253
Type paramType = genericParams[i];
53-
sb.append(getSimpleClassName(paramType));
54+
55+
String name = getSimpleClassName(paramType);
56+
if (i == genericParams.length-1 && mMethod.isVarArgs() && params[i].isArray()) {
57+
sb.append(name.replace("[]", ""));
58+
sb.append("...");
59+
} else {
60+
sb.append(name);
61+
}
5462
}
5563
} catch (Exception e) {
5664
Class<?>[] params = mMethod.getParameterTypes();
5765
for (int i = 0; i < params.length; i++) {
5866
if (i != 0) {
5967
sb.append(", ");
6068
}
61-
sb.append(params[i].getSimpleName());
69+
String name = params[i].getSimpleName();
70+
if (i == params.length-1 && mMethod.isVarArgs() && params[i].isArray()) {
71+
sb.append(name.replace("[]", ""));
72+
sb.append("...");
73+
} else {
74+
sb.append(name);
75+
}
6276
}
6377
}
6478
sb.append(")");

library/src/main/java/jwf/debugport/commands/fields.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@
1111
@Command
1212
public class fields {
1313
@Command.Help("List all of the fields available for a particular object.")
14-
public static void invoke(Interpreter interpreter, CallStack callStack, Object obj) {
14+
public static void invoke(Interpreter interpreter, CallStack callStack, @Command.ParamName("obj") Object obj) {
1515
invoke(interpreter, callStack, obj.getClass());
1616
}
1717

1818
@Command.Help("List all of the fields available for a particular class.")
19-
public static void invoke(Interpreter interpreter, CallStack callStack, Class klass) {
19+
public static void invoke(Interpreter interpreter, CallStack callStack, @Command.ParamName("class") Class klass) {
2020
if (klass == null) {
2121
interpreter.println("value is null");
2222
return;

library/src/main/java/jwf/debugport/commands/fieldsLocal.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@
1111
@Command
1212
public class fieldsLocal {
1313
@Command.Help("List all of the fields defined locally for an object.")
14-
public static void invoke(Interpreter interpreter, CallStack callStack, Object obj) {
14+
public static void invoke(Interpreter interpreter, CallStack callStack, @Command.ParamName("obj") Object obj) {
1515
invoke(interpreter, callStack, obj.getClass());
1616
}
1717

1818
@Command.Help("List all of the fields defined locally for a particular class.")
19-
public static void invoke(Interpreter interpreter, CallStack callStack, Class klass) {
19+
public static void invoke(Interpreter interpreter, CallStack callStack, @Command.ParamName("class") Class klass) {
2020
if (klass == null) {
2121
interpreter.println("null");
2222
return;

library/src/main/java/jwf/debugport/commands/get.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,16 @@
77
import jwf.debugport.annotations.Command;
88

99
/**
10-
* Created by jason on 5/6/16.
10+
*
1111
*/
1212
@Command
1313
public class get {
14-
@Command.Help("Get the value of a parameter, regardless of access modifiers, on the provided object.")
15-
public static Object invoke(Interpreter interpreter, CallStack callstack, Object object, String param) throws NoSuchFieldException, IllegalAccessException {
14+
@Command.Help("Get the value of a field, regardless of access modifiers, on the provided object.")
15+
public static Object invoke(
16+
Interpreter interpreter,
17+
CallStack callstack,
18+
@Command.ParamName("obj") Object object,
19+
@Command.ParamName("fieldName") String param) throws NoSuchFieldException, IllegalAccessException {
1620
Field field;
1721
try {
1822
field = object.getClass().getDeclaredField(param);

0 commit comments

Comments
 (0)