-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathreflectivestyle.html
284 lines (241 loc) · 7.57 KB
/
reflectivestyle.html
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
<?xml version="1.0" encoding="UTF-8"?>
<html>
<head>
<title>Reflective Style Access to Scripted Methods</title>
</head>
<body bgcolor="ffffff">
<table cellspacing="10">
<tr>
<td align="center"><a href="http://www.beanshell.org/"><img src="images/homebutton.png" /><br />Home</a>
</td>
<td><a href="jconsole.html#Using_JConsole"><img src="images/backbutton.png" /><br />Back
</a></td>
<td align="center"><a href="contents.html"><img src="images/upbutton.png" /><br />Contents</a></td>
<td align="center"><a href="execscripts.html#Executable_scripts_under_Unix"><img
src="images/forwardbutton.png" /><br />Next
</a></td>
</tr>
</table>
<h1>Reflective Style Access to Scripted Methods</h1>
The following examples show how to work with BeanShell methods dynamically
from within scripts, using the equivalent of reflective style access in Java.
This is an advanced topic primarily of interest to developers who wish to
do tight integration of BeanShell scripts with their application environment.
<p CLEAR="ALL" />
<h2><a name="eval()">eval()</a></h2>
The simplest form of reflective style access to scripts is through the
eval() command. With eval() you can evaluate any text just as if it had
appeared in the current scope. For example:
<p />
<center>
<table border="1" cellpadding="5" width="100%">
<tr>
<td bgcolor="#dfdfdc">
<pre>
eval("a=5;");
print( a ); // 5
</pre>
</td>
</tr>
</table>
</center>
<p />
So, if you know the signature (argument types) of a method you wish to work
with you can simply construct a method call as a string and evaluate it
with eval() as in the following:
<p />
<center>
<table border="1" cellpadding="5" width="100%">
<tr>
<td bgcolor="#dfdfdc">
<pre>
// Declare methods foo() and bar( int, String )
foo() { ... }
bar( int arg1, String arg2 ) { ... }
// Invoke a no-args method foo() by its name using eval()
name="foo";
// invoke foo() using eval()
eval( name+"()");
// Invoke two arg method bar(arg1,arg2) by name using eval()
name="bar";
arg1=5;
arg2="stringy";
eval( name+"(arg1,arg2)");
</pre>
</td>
</tr>
</table>
</center>
<p />
You can get the names of all of the methods defined in the current scope
using the 'this.methods' magic reference, which returns an array of Strings:
<p />
<center>
<table border="1" cellpadding="5" width="100%">
<tr>
<td bgcolor="#dfdfdc">
<pre>
// Print the methods defined in this namespace
print( this.methods );
</pre>
</td>
</tr>
</table>
</center>
<p />
We'll talk about more powerful forms of method lookup in a moment.
<h2><a name="invokeMethod()">invokeMethod()</a></h2>
You can explicitly invoke a method by name with arguments through a 'this'
type reference using the invokeMethod() method:
<p />
<center>
<table border="1" cellpadding="5" width="100%">
<tr>
<td bgcolor="#dfdfdc">
<pre>
this.invokeMethod( "bar", new Object [] { new Integer(5), "stringy" } );
</pre>
</td>
</tr>
</table>
</center>
<p />
Arguments are passed as an array of objects. Primitive types must be
wrapped in their appropriate wrappers.
BeanShell will select among overloaded methods using the standard Java
method resolution rules. (JLS 15.11.2).
<h2><a name="Method_Lookup">Method Lookup</a></h2>
The previous section showed how to invoke a method by name when we know
the argument types. Of course, in general we'd like to be able to find out
what methods are defined in the current script or to look up a method by
its signature.
<p CLEAR="ALL" />
You can get "handles" to all of the methods defined in a context using the
namespace getMethods() method.
getMethods() returns an array of bsh.BshMethod objects,
which are wrappers for the internally parsed representation of BeanShell
scripted methods:
<p />
<center>
<table border="1" cellpadding="5" width="100%">
<tr>
<td bgcolor="#dfdfdc">
<pre>
foo() { ... }
foo( int a ) { ... }
bar( int arg1, String arg2 ) { ... }
print ( this.namespace.getMethods() );
// Array: [Lbsh.BshMethod;@291aff {
// Bsh Method: bar
// Bsh Method: foo
// Bsh Method: foo
// }
</pre>
</td>
</tr>
</table>
</center>
<p />
We'll talk about what you can do with a BshMethod in a moment.
<p CLEAR="ALL" />
Alternately, you can use the namespace getMethod() method to search
for a specific method signature. The method signature is a set of argument
types represented by an array of Classes:
<p />
<center>
<table border="1" cellpadding="5" width="100%">
<tr>
<td bgcolor="#dfdfdc">
<pre>
name="bar";
signature = new Class [] { Integer.TYPE, String.class };
// Look up a method named bar with arg types int and String
bshMethod = this.namespace.getMethod( name, signature );
print("Found method: "+bshMethod);
</pre>
</td>
</tr>
</table>
</center>
<p />
<p />
<center>
<table cellpadding="5" border="1" width="100%">
<tr>
<td><strong>Tip:</strong><br CLEAR="ALL" />
The Java reflection API uses special class values to represent primitive types
such as int, char, an boolean. These types are static fields in the respective
primitive wrapper classes. e.g. Integer.TYPE, Character.TYPE, Boolean.TYPE.
</td>
</tr>
</table>
</center>
<p />
In the above snippet we located the bar() method by its signature. If there
had been overloaded forms of bar() getMethod() would have located the most
specific one according to the standard Java method resolution rules
(JLS 15.11.2).
The result of the lookup is a bsh.BshMethod object, as before.
<p CLEAR="ALL" />
<h2><a name="BshMethod">BshMethod</a></h2>
You can inspect a BshMethod object to determine its method name and
argument types:
<p />
<center>
<table border="1" cellpadding="5" width="100%">
<tr>
<td bgcolor="#dfdfdc">
<pre>
name = bshMethod.getName();
Class [] types = bshMethod.getArgumentTypes();
Class returnType = bshMethod.getReturnType();
</pre>
</td>
</tr>
</table>
</center>
<p />
To invoke the BshMethod, call its invoke() method, passing an array of
arguments, an interpreter reference, and a "callstack" reference.
<p CLEAR="ALL" />
<p />
<center>
<table border="1" cellpadding="5" width="100%">
<tr>
<td bgcolor="#dfdfdc">
<pre>
// invoke the method with arg
bshMethod.invoke( new Object [] { new Integer(1), "blah!" },
this.interpreter, this.callstack );
</pre>
</td>
</tr>
</table>
</center>
<p />
For the
interpreter and callstack references you can simply pass along the current
context's values via 'this.interpreter' and 'this.callstack', as we did
above. The arguments array may be null or empty for no arguments.
<p CLEAR="ALL" />
<h2><a name="Uses">Uses</a></h2>
Why would anyone want to do this? Well, perhaps you are sourcing a script
created by a user and want to automatically begin using methods that they
have defined. Perhaps the user is allowed to define methods to take control
of various aspects of your application. With the tools we've described
in this section you can list the methods they have defined and invoke
them dynamically.
<table cellspacing="10">
<tr>
<td align="center"><a href="http://www.beanshell.org/"><img src="images/homebutton.png" /><br />Home</a>
</td>
<td><a href="jconsole.html#Using_JConsole"><img src="images/backbutton.png" /><br />Back
</a></td>
<td align="center"><a href="contents.html"><img src="images/upbutton.png" /><br />Contents</a></td>
<td align="center"><a href="execscripts.html#Executable_scripts_under_Unix"><img
src="images/forwardbutton.png" /><br />Next
</a></td>
</tr>
</table>
</body>
</html>