2
|
1 |
/*
|
5506
|
2 |
* Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
|
2
|
3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
4 |
*
|
|
5 |
* This code is free software; you can redistribute it and/or modify it
|
|
6 |
* under the terms of the GNU General Public License version 2 only, as
|
5506
|
7 |
* published by the Free Software Foundation. Oracle designates this
|
2
|
8 |
* particular file as subject to the "Classpath" exception as provided
|
5506
|
9 |
* by Oracle in the LICENSE file that accompanied this code.
|
2
|
10 |
*
|
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that
|
|
15 |
* accompanied this code).
|
|
16 |
*
|
|
17 |
* You should have received a copy of the GNU General Public License version
|
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
20 |
*
|
5506
|
21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
22 |
* or visit www.oracle.com if you need additional information or have any
|
|
23 |
* questions.
|
2
|
24 |
*/
|
|
25 |
|
|
26 |
package sun.rmi.rmic.newrmic.jrmp;
|
|
27 |
|
|
28 |
import com.sun.javadoc.ClassDoc;
|
|
29 |
import com.sun.javadoc.MethodDoc;
|
|
30 |
import com.sun.javadoc.Type;
|
|
31 |
import java.io.IOException;
|
|
32 |
import java.util.ArrayList;
|
|
33 |
import java.util.Iterator;
|
|
34 |
import java.util.List;
|
|
35 |
import sun.rmi.rmic.newrmic.BatchEnvironment;
|
|
36 |
import sun.rmi.rmic.newrmic.IndentingWriter;
|
|
37 |
|
|
38 |
import static sun.rmi.rmic.newrmic.Constants.*;
|
|
39 |
import static sun.rmi.rmic.newrmic.jrmp.Constants.*;
|
|
40 |
|
|
41 |
/**
|
|
42 |
* Writes the source code for the stub class and (optionally) skeleton
|
|
43 |
* class for a particular remote implementation class.
|
|
44 |
*
|
|
45 |
* WARNING: The contents of this source file are not part of any
|
|
46 |
* supported API. Code that depends on them does so at its own risk:
|
|
47 |
* they are subject to change or removal without notice.
|
|
48 |
*
|
|
49 |
* @author Peter Jones
|
|
50 |
**/
|
|
51 |
class StubSkeletonWriter {
|
|
52 |
|
|
53 |
/** rmic environment for this object */
|
|
54 |
private final BatchEnvironment env;
|
|
55 |
|
21278
|
56 |
/** the remote implementation class to generate code for */
|
2
|
57 |
private final RemoteClass remoteClass;
|
|
58 |
|
|
59 |
/** version of the JRMP stub protocol to generate code for */
|
|
60 |
private final StubVersion version;
|
|
61 |
|
|
62 |
/*
|
|
63 |
* binary names of the stub and skeleton classes to generate for
|
|
64 |
* the remote class
|
|
65 |
*/
|
|
66 |
private final String stubClassName;
|
|
67 |
private final String skeletonClassName;
|
|
68 |
|
|
69 |
/* package name and simple names of the stub and skeleton classes */
|
|
70 |
private final String packageName;
|
|
71 |
private final String stubClassSimpleName;
|
|
72 |
private final String skeletonClassSimpleName;
|
|
73 |
|
|
74 |
/** remote methods of class, indexed by operation number */
|
|
75 |
private final RemoteClass.Method[] remoteMethods;
|
|
76 |
|
|
77 |
/**
|
|
78 |
* Names to use for the java.lang.reflect.Method static fields in
|
|
79 |
* the generated stub class corresponding to each remote method.
|
|
80 |
**/
|
|
81 |
private final String[] methodFieldNames;
|
|
82 |
|
|
83 |
/**
|
|
84 |
* Creates a StubSkeletonWriter instance for the specified remote
|
|
85 |
* implementation class. The generated code will implement the
|
|
86 |
* specified JRMP stub protocol version.
|
|
87 |
**/
|
|
88 |
StubSkeletonWriter(BatchEnvironment env,
|
|
89 |
RemoteClass remoteClass,
|
|
90 |
StubVersion version)
|
|
91 |
{
|
|
92 |
this.env = env;
|
|
93 |
this.remoteClass = remoteClass;
|
|
94 |
this.version = version;
|
|
95 |
|
|
96 |
stubClassName = Util.binaryNameOf(remoteClass.classDoc()) + "_Stub";
|
|
97 |
skeletonClassName =
|
|
98 |
Util.binaryNameOf(remoteClass.classDoc()) + "_Skel";
|
|
99 |
|
|
100 |
int i = stubClassName.lastIndexOf('.');
|
|
101 |
packageName = (i != -1 ? stubClassName.substring(0, i) : "");
|
|
102 |
stubClassSimpleName = stubClassName.substring(i + 1);
|
|
103 |
skeletonClassSimpleName = skeletonClassName.substring(i + 1);
|
|
104 |
|
|
105 |
remoteMethods = remoteClass.remoteMethods();
|
|
106 |
methodFieldNames = nameMethodFields(remoteMethods);
|
|
107 |
}
|
|
108 |
|
|
109 |
/**
|
|
110 |
* Returns the binary name of the stub class to generate for the
|
|
111 |
* remote implementation class.
|
|
112 |
**/
|
|
113 |
String stubClassName() {
|
|
114 |
return stubClassName;
|
|
115 |
}
|
|
116 |
|
|
117 |
/**
|
|
118 |
* Returns the binary name of the skeleton class to generate for
|
|
119 |
* the remote implementation class.
|
|
120 |
**/
|
|
121 |
String skeletonClassName() {
|
|
122 |
return skeletonClassName;
|
|
123 |
}
|
|
124 |
|
|
125 |
/**
|
|
126 |
* Writes the stub class for the remote class to a stream.
|
|
127 |
**/
|
|
128 |
void writeStub(IndentingWriter p) throws IOException {
|
|
129 |
|
|
130 |
/*
|
|
131 |
* Write boiler plate comment.
|
|
132 |
*/
|
|
133 |
p.pln("// Stub class generated by rmic, do not edit.");
|
|
134 |
p.pln("// Contents subject to change without notice.");
|
|
135 |
p.pln();
|
|
136 |
|
|
137 |
/*
|
|
138 |
* If remote implementation class was in a particular package,
|
|
139 |
* declare the stub class to be in the same package.
|
|
140 |
*/
|
|
141 |
if (!packageName.equals("")) {
|
|
142 |
p.pln("package " + packageName + ";");
|
|
143 |
p.pln();
|
|
144 |
}
|
|
145 |
|
|
146 |
/*
|
|
147 |
* Declare the stub class; implement all remote interfaces.
|
|
148 |
*/
|
|
149 |
p.plnI("public final class " + stubClassSimpleName);
|
|
150 |
p.pln("extends " + REMOTE_STUB);
|
|
151 |
ClassDoc[] remoteInterfaces = remoteClass.remoteInterfaces();
|
|
152 |
if (remoteInterfaces.length > 0) {
|
|
153 |
p.p("implements ");
|
|
154 |
for (int i = 0; i < remoteInterfaces.length; i++) {
|
|
155 |
if (i > 0) {
|
|
156 |
p.p(", ");
|
|
157 |
}
|
|
158 |
p.p(remoteInterfaces[i].qualifiedName());
|
|
159 |
}
|
|
160 |
p.pln();
|
|
161 |
}
|
|
162 |
p.pOlnI("{");
|
|
163 |
|
|
164 |
if (version == StubVersion.V1_1 ||
|
|
165 |
version == StubVersion.VCOMPAT)
|
|
166 |
{
|
|
167 |
writeOperationsArray(p);
|
|
168 |
p.pln();
|
|
169 |
writeInterfaceHash(p);
|
|
170 |
p.pln();
|
|
171 |
}
|
|
172 |
|
|
173 |
if (version == StubVersion.VCOMPAT ||
|
|
174 |
version == StubVersion.V1_2)
|
|
175 |
{
|
|
176 |
p.pln("private static final long serialVersionUID = " +
|
|
177 |
STUB_SERIAL_VERSION_UID + ";");
|
|
178 |
p.pln();
|
|
179 |
|
|
180 |
/*
|
|
181 |
* We only need to declare and initialize the static fields of
|
|
182 |
* Method objects for each remote method if there are any remote
|
|
183 |
* methods; otherwise, skip this code entirely, to avoid generating
|
|
184 |
* a try/catch block for a checked exception that cannot occur
|
|
185 |
* (see bugid 4125181).
|
|
186 |
*/
|
|
187 |
if (methodFieldNames.length > 0) {
|
|
188 |
if (version == StubVersion.VCOMPAT) {
|
|
189 |
p.pln("private static boolean useNewInvoke;");
|
|
190 |
}
|
|
191 |
writeMethodFieldDeclarations(p);
|
|
192 |
p.pln();
|
|
193 |
|
|
194 |
/*
|
|
195 |
* Initialize java.lang.reflect.Method fields for each remote
|
|
196 |
* method in a static initializer.
|
|
197 |
*/
|
|
198 |
p.plnI("static {");
|
|
199 |
p.plnI("try {");
|
|
200 |
if (version == StubVersion.VCOMPAT) {
|
|
201 |
/*
|
|
202 |
* Fat stubs must determine whether the API required for
|
|
203 |
* the JDK 1.2 stub protocol is supported in the current
|
|
204 |
* runtime, so that it can use it if supported. This is
|
|
205 |
* determined by using the Reflection API to test if the
|
|
206 |
* new invoke method on RemoteRef exists, and setting the
|
|
207 |
* static boolean "useNewInvoke" to true if it does, or
|
|
208 |
* to false if a NoSuchMethodException is thrown.
|
|
209 |
*/
|
|
210 |
p.plnI(REMOTE_REF + ".class.getMethod(\"invoke\",");
|
|
211 |
p.plnI("new java.lang.Class[] {");
|
|
212 |
p.pln(REMOTE + ".class,");
|
|
213 |
p.pln("java.lang.reflect.Method.class,");
|
|
214 |
p.pln("java.lang.Object[].class,");
|
|
215 |
p.pln("long.class");
|
|
216 |
p.pOln("});");
|
|
217 |
p.pO();
|
|
218 |
p.pln("useNewInvoke = true;");
|
|
219 |
}
|
|
220 |
writeMethodFieldInitializers(p);
|
|
221 |
p.pOlnI("} catch (java.lang.NoSuchMethodException e) {");
|
|
222 |
if (version == StubVersion.VCOMPAT) {
|
|
223 |
p.pln("useNewInvoke = false;");
|
|
224 |
} else {
|
|
225 |
p.plnI("throw new java.lang.NoSuchMethodError(");
|
|
226 |
p.pln("\"stub class initialization failed\");");
|
|
227 |
p.pO();
|
|
228 |
}
|
|
229 |
p.pOln("}"); // end try/catch block
|
|
230 |
p.pOln("}"); // end static initializer
|
|
231 |
p.pln();
|
|
232 |
}
|
|
233 |
}
|
|
234 |
|
|
235 |
writeStubConstructors(p);
|
|
236 |
p.pln();
|
|
237 |
|
|
238 |
/*
|
|
239 |
* Write each stub method.
|
|
240 |
*/
|
|
241 |
if (remoteMethods.length > 0) {
|
|
242 |
p.pln("// methods from remote interfaces");
|
|
243 |
for (int i = 0; i < remoteMethods.length; ++i) {
|
|
244 |
p.pln();
|
|
245 |
writeStubMethod(p, i);
|
|
246 |
}
|
|
247 |
}
|
|
248 |
|
|
249 |
p.pOln("}"); // end stub class
|
|
250 |
}
|
|
251 |
|
|
252 |
/**
|
|
253 |
* Writes the constructors for the stub class.
|
|
254 |
**/
|
|
255 |
private void writeStubConstructors(IndentingWriter p)
|
|
256 |
throws IOException
|
|
257 |
{
|
|
258 |
p.pln("// constructors");
|
|
259 |
|
|
260 |
/*
|
|
261 |
* Only stubs compatible with the JDK 1.1 stub protocol need
|
|
262 |
* a no-arg constructor; later versions use reflection to find
|
|
263 |
* the constructor that directly takes a RemoteRef argument.
|
|
264 |
*/
|
|
265 |
if (version == StubVersion.V1_1 ||
|
|
266 |
version == StubVersion.VCOMPAT)
|
|
267 |
{
|
|
268 |
p.plnI("public " + stubClassSimpleName + "() {");
|
|
269 |
p.pln("super();");
|
|
270 |
p.pOln("}");
|
|
271 |
}
|
|
272 |
|
|
273 |
p.plnI("public " + stubClassSimpleName + "(" + REMOTE_REF + " ref) {");
|
|
274 |
p.pln("super(ref);");
|
|
275 |
p.pOln("}");
|
|
276 |
}
|
|
277 |
|
|
278 |
/**
|
|
279 |
* Writes the stub method for the remote method with the given
|
|
280 |
* operation number.
|
|
281 |
**/
|
|
282 |
private void writeStubMethod(IndentingWriter p, int opnum)
|
|
283 |
throws IOException
|
|
284 |
{
|
|
285 |
RemoteClass.Method method = remoteMethods[opnum];
|
|
286 |
MethodDoc methodDoc = method.methodDoc();
|
|
287 |
String methodName = methodDoc.name();
|
|
288 |
Type[] paramTypes = method.parameterTypes();
|
|
289 |
String paramNames[] = nameParameters(paramTypes);
|
|
290 |
Type returnType = methodDoc.returnType();
|
|
291 |
ClassDoc[] exceptions = method.exceptionTypes();
|
|
292 |
|
|
293 |
/*
|
|
294 |
* Declare stub method; throw exceptions declared in remote
|
|
295 |
* interface(s).
|
|
296 |
*/
|
|
297 |
p.pln("// implementation of " +
|
|
298 |
Util.getFriendlyUnqualifiedSignature(methodDoc));
|
|
299 |
p.p("public " + returnType.toString() + " " + methodName + "(");
|
|
300 |
for (int i = 0; i < paramTypes.length; i++) {
|
|
301 |
if (i > 0) {
|
|
302 |
p.p(", ");
|
|
303 |
}
|
|
304 |
p.p(paramTypes[i].toString() + " " + paramNames[i]);
|
|
305 |
}
|
|
306 |
p.plnI(")");
|
|
307 |
if (exceptions.length > 0) {
|
|
308 |
p.p("throws ");
|
|
309 |
for (int i = 0; i < exceptions.length; i++) {
|
|
310 |
if (i > 0) {
|
|
311 |
p.p(", ");
|
|
312 |
}
|
|
313 |
p.p(exceptions[i].qualifiedName());
|
|
314 |
}
|
|
315 |
p.pln();
|
|
316 |
}
|
|
317 |
p.pOlnI("{");
|
|
318 |
|
|
319 |
/*
|
|
320 |
* The RemoteRef.invoke methods throw Exception, but unless
|
|
321 |
* this stub method throws Exception as well, we must catch
|
|
322 |
* Exceptions thrown from the invocation. So we must catch
|
|
323 |
* Exception and rethrow something we can throw:
|
|
324 |
* UnexpectedException, which is a subclass of
|
|
325 |
* RemoteException. But for any subclasses of Exception that
|
|
326 |
* we can throw, like RemoteException, RuntimeException, and
|
|
327 |
* any of the exceptions declared by this stub method, we want
|
|
328 |
* them to pass through unmodified, so first we must catch any
|
|
329 |
* such exceptions and rethrow them directly.
|
|
330 |
*
|
|
331 |
* We have to be careful generating the rethrowing catch
|
|
332 |
* blocks here, because javac will flag an error if there are
|
|
333 |
* any unreachable catch blocks, i.e. if the catch of an
|
|
334 |
* exception class follows a previous catch of it or of one of
|
|
335 |
* its superclasses. The following method invocation takes
|
|
336 |
* care of these details.
|
|
337 |
*/
|
|
338 |
List<ClassDoc> catchList = computeUniqueCatchList(exceptions);
|
|
339 |
|
|
340 |
/*
|
|
341 |
* If we need to catch any particular exceptions (i.e. this method
|
|
342 |
* does not declare java.lang.Exception), put the entire stub
|
|
343 |
* method in a try block.
|
|
344 |
*/
|
|
345 |
if (catchList.size() > 0) {
|
|
346 |
p.plnI("try {");
|
|
347 |
}
|
|
348 |
|
|
349 |
if (version == StubVersion.VCOMPAT) {
|
|
350 |
p.plnI("if (useNewInvoke) {");
|
|
351 |
}
|
|
352 |
if (version == StubVersion.VCOMPAT ||
|
|
353 |
version == StubVersion.V1_2)
|
|
354 |
{
|
|
355 |
if (!Util.isVoid(returnType)) {
|
|
356 |
p.p("Object $result = "); // REMIND: why $?
|
|
357 |
}
|
|
358 |
p.p("ref.invoke(this, " + methodFieldNames[opnum] + ", ");
|
|
359 |
if (paramTypes.length > 0) {
|
|
360 |
p.p("new java.lang.Object[] {");
|
|
361 |
for (int i = 0; i < paramTypes.length; i++) {
|
|
362 |
if (i > 0)
|
|
363 |
p.p(", ");
|
|
364 |
p.p(wrapArgumentCode(paramTypes[i], paramNames[i]));
|
|
365 |
}
|
|
366 |
p.p("}");
|
|
367 |
} else {
|
|
368 |
p.p("null");
|
|
369 |
}
|
|
370 |
p.pln(", " + method.methodHash() + "L);");
|
|
371 |
if (!Util.isVoid(returnType)) {
|
|
372 |
p.pln("return " +
|
|
373 |
unwrapArgumentCode(returnType, "$result") + ";");
|
|
374 |
}
|
|
375 |
}
|
|
376 |
if (version == StubVersion.VCOMPAT) {
|
|
377 |
p.pOlnI("} else {");
|
|
378 |
}
|
|
379 |
if (version == StubVersion.V1_1 ||
|
|
380 |
version == StubVersion.VCOMPAT)
|
|
381 |
{
|
|
382 |
p.pln(REMOTE_CALL + " call = ref.newCall((" + REMOTE_OBJECT +
|
|
383 |
") this, operations, " + opnum + ", interfaceHash);");
|
|
384 |
|
|
385 |
if (paramTypes.length > 0) {
|
|
386 |
p.plnI("try {");
|
|
387 |
p.pln("java.io.ObjectOutput out = call.getOutputStream();");
|
|
388 |
writeMarshalArguments(p, "out", paramTypes, paramNames);
|
|
389 |
p.pOlnI("} catch (java.io.IOException e) {");
|
|
390 |
p.pln("throw new " + MARSHAL_EXCEPTION +
|
|
391 |
"(\"error marshalling arguments\", e);");
|
|
392 |
p.pOln("}");
|
|
393 |
}
|
|
394 |
|
|
395 |
p.pln("ref.invoke(call);");
|
|
396 |
|
|
397 |
if (Util.isVoid(returnType)) {
|
|
398 |
p.pln("ref.done(call);");
|
|
399 |
} else {
|
|
400 |
p.pln(returnType.toString() + " $result;");
|
|
401 |
// REMIND: why $?
|
|
402 |
p.plnI("try {");
|
|
403 |
p.pln("java.io.ObjectInput in = call.getInputStream();");
|
|
404 |
boolean objectRead =
|
|
405 |
writeUnmarshalArgument(p, "in", returnType, "$result");
|
|
406 |
p.pln(";");
|
|
407 |
p.pOlnI("} catch (java.io.IOException e) {");
|
|
408 |
p.pln("throw new " + UNMARSHAL_EXCEPTION +
|
|
409 |
"(\"error unmarshalling return\", e);");
|
|
410 |
/*
|
|
411 |
* If any only if readObject has been invoked, we must catch
|
|
412 |
* ClassNotFoundException as well as IOException.
|
|
413 |
*/
|
|
414 |
if (objectRead) {
|
|
415 |
p.pOlnI("} catch (java.lang.ClassNotFoundException e) {");
|
|
416 |
p.pln("throw new " + UNMARSHAL_EXCEPTION +
|
|
417 |
"(\"error unmarshalling return\", e);");
|
|
418 |
}
|
|
419 |
p.pOlnI("} finally {");
|
|
420 |
p.pln("ref.done(call);");
|
|
421 |
p.pOln("}");
|
|
422 |
p.pln("return $result;");
|
|
423 |
}
|
|
424 |
}
|
|
425 |
if (version == StubVersion.VCOMPAT) {
|
|
426 |
p.pOln("}"); // end if/else (useNewInvoke) block
|
|
427 |
}
|
|
428 |
|
|
429 |
/*
|
|
430 |
* If we need to catch any particular exceptions, finally write
|
|
431 |
* the catch blocks for them, rethrow any other Exceptions with an
|
|
432 |
* UnexpectedException, and end the try block.
|
|
433 |
*/
|
|
434 |
if (catchList.size() > 0) {
|
|
435 |
for (ClassDoc catchClass : catchList) {
|
|
436 |
p.pOlnI("} catch (" + catchClass.qualifiedName() + " e) {");
|
|
437 |
p.pln("throw e;");
|
|
438 |
}
|
|
439 |
p.pOlnI("} catch (java.lang.Exception e) {");
|
|
440 |
p.pln("throw new " + UNEXPECTED_EXCEPTION +
|
|
441 |
"(\"undeclared checked exception\", e);");
|
|
442 |
p.pOln("}"); // end try/catch block
|
|
443 |
}
|
|
444 |
|
|
445 |
p.pOln("}"); // end stub method
|
|
446 |
}
|
|
447 |
|
|
448 |
/**
|
|
449 |
* Computes the exceptions that need to be caught and rethrown in
|
|
450 |
* a stub method before wrapping Exceptions in
|
|
451 |
* UnexpectedExceptions, given the exceptions declared in the
|
|
452 |
* throws clause of the method. Returns a list containing the
|
|
453 |
* exception to catch. Each exception is guaranteed to be unique,
|
|
454 |
* i.e. not a subclass of any of the other exceptions in the list,
|
|
455 |
* so the catch blocks for these exceptions may be generated in
|
|
456 |
* any order relative to each other.
|
|
457 |
*
|
|
458 |
* RemoteException and RuntimeException are each automatically
|
|
459 |
* placed in the returned list (unless any of their superclasses
|
|
460 |
* are already present), since those exceptions should always be
|
|
461 |
* directly rethrown by a stub method.
|
|
462 |
*
|
|
463 |
* The returned list will be empty if java.lang.Exception or one
|
|
464 |
* of its superclasses is in the throws clause of the method,
|
|
465 |
* indicating that no exceptions need to be caught.
|
|
466 |
**/
|
|
467 |
private List<ClassDoc> computeUniqueCatchList(ClassDoc[] exceptions) {
|
|
468 |
List<ClassDoc> uniqueList = new ArrayList<ClassDoc>();
|
|
469 |
|
|
470 |
uniqueList.add(env.docRuntimeException());
|
|
471 |
uniqueList.add(env.docRemoteException()); // always catch/rethrow these
|
|
472 |
|
|
473 |
/* For each exception declared by the stub method's throws clause: */
|
|
474 |
nextException:
|
|
475 |
for (ClassDoc ex : exceptions) {
|
|
476 |
if (env.docException().subclassOf(ex)) {
|
|
477 |
/*
|
|
478 |
* If java.lang.Exception (or a superclass) was declared
|
|
479 |
* in the throws clause of this stub method, then we don't
|
|
480 |
* have to bother catching anything; clear the list and
|
|
481 |
* return.
|
|
482 |
*/
|
|
483 |
uniqueList.clear();
|
|
484 |
break;
|
|
485 |
} else if (!ex.subclassOf(env.docException())) {
|
|
486 |
/*
|
|
487 |
* Ignore other Throwables that do not extend Exception,
|
|
488 |
* because they cannot be thrown by the invoke methods.
|
|
489 |
*/
|
|
490 |
continue;
|
|
491 |
}
|
|
492 |
/*
|
|
493 |
* Compare this exception against the current list of
|
|
494 |
* exceptions that need to be caught:
|
|
495 |
*/
|
|
496 |
for (Iterator<ClassDoc> i = uniqueList.iterator(); i.hasNext();) {
|
|
497 |
ClassDoc ex2 = i.next();
|
|
498 |
if (ex.subclassOf(ex2)) {
|
|
499 |
/*
|
|
500 |
* If a superclass of this exception is already on
|
|
501 |
* the list to catch, then ignore this one and continue;
|
|
502 |
*/
|
|
503 |
continue nextException;
|
|
504 |
} else if (ex2.subclassOf(ex)) {
|
|
505 |
/*
|
|
506 |
* If a subclass of this exception is on the list
|
|
507 |
* to catch, then remove it;
|
|
508 |
*/
|
|
509 |
i.remove();
|
|
510 |
}
|
|
511 |
}
|
|
512 |
/* This exception is unique: add it to the list to catch. */
|
|
513 |
uniqueList.add(ex);
|
|
514 |
}
|
|
515 |
return uniqueList;
|
|
516 |
}
|
|
517 |
|
|
518 |
/**
|
|
519 |
* Writes the skeleton for the remote class to a stream.
|
|
520 |
**/
|
|
521 |
void writeSkeleton(IndentingWriter p) throws IOException {
|
|
522 |
if (version == StubVersion.V1_2) {
|
|
523 |
throw new AssertionError(
|
|
524 |
"should not generate skeleton for version " + version);
|
|
525 |
}
|
|
526 |
|
|
527 |
/*
|
|
528 |
* Write boiler plate comment.
|
|
529 |
*/
|
|
530 |
p.pln("// Skeleton class generated by rmic, do not edit.");
|
|
531 |
p.pln("// Contents subject to change without notice.");
|
|
532 |
p.pln();
|
|
533 |
|
|
534 |
/*
|
|
535 |
* If remote implementation class was in a particular package,
|
|
536 |
* declare the skeleton class to be in the same package.
|
|
537 |
*/
|
|
538 |
if (!packageName.equals("")) {
|
|
539 |
p.pln("package " + packageName + ";");
|
|
540 |
p.pln();
|
|
541 |
}
|
|
542 |
|
|
543 |
/*
|
|
544 |
* Declare the skeleton class.
|
|
545 |
*/
|
|
546 |
p.plnI("public final class " + skeletonClassSimpleName);
|
|
547 |
p.pln("implements " + SKELETON);
|
|
548 |
p.pOlnI("{");
|
|
549 |
|
|
550 |
writeOperationsArray(p);
|
|
551 |
p.pln();
|
|
552 |
|
|
553 |
writeInterfaceHash(p);
|
|
554 |
p.pln();
|
|
555 |
|
|
556 |
/*
|
|
557 |
* Define the getOperations() method.
|
|
558 |
*/
|
|
559 |
p.plnI("public " + OPERATION + "[] getOperations() {");
|
|
560 |
p.pln("return (" + OPERATION + "[]) operations.clone();");
|
|
561 |
p.pOln("}");
|
|
562 |
p.pln();
|
|
563 |
|
|
564 |
/*
|
|
565 |
* Define the dispatch() method.
|
|
566 |
*/
|
|
567 |
p.plnI("public void dispatch(" + REMOTE + " obj, " +
|
|
568 |
REMOTE_CALL + " call, int opnum, long hash)");
|
|
569 |
p.pln("throws java.lang.Exception");
|
|
570 |
p.pOlnI("{");
|
|
571 |
|
|
572 |
if (version == StubVersion.VCOMPAT) {
|
|
573 |
p.plnI("if (opnum < 0) {");
|
|
574 |
if (remoteMethods.length > 0) {
|
|
575 |
for (int opnum = 0; opnum < remoteMethods.length; opnum++) {
|
|
576 |
if (opnum > 0)
|
|
577 |
p.pO("} else ");
|
|
578 |
p.plnI("if (hash == " +
|
|
579 |
remoteMethods[opnum].methodHash() + "L) {");
|
|
580 |
p.pln("opnum = " + opnum + ";");
|
|
581 |
}
|
|
582 |
p.pOlnI("} else {");
|
|
583 |
}
|
|
584 |
/*
|
|
585 |
* Skeleton throws UnmarshalException if it does not recognize
|
|
586 |
* the method hash; this is what UnicastServerRef.dispatch()
|
|
587 |
* would do.
|
|
588 |
*/
|
|
589 |
p.pln("throw new " +
|
|
590 |
UNMARSHAL_EXCEPTION + "(\"invalid method hash\");");
|
|
591 |
if (remoteMethods.length > 0) {
|
|
592 |
p.pOln("}");
|
|
593 |
}
|
|
594 |
/*
|
|
595 |
* Ignore the validation of the interface hash if the
|
|
596 |
* operation number was negative, since it is really a
|
|
597 |
* method hash instead.
|
|
598 |
*/
|
|
599 |
p.pOlnI("} else {");
|
|
600 |
}
|
|
601 |
|
|
602 |
p.plnI("if (hash != interfaceHash)");
|
|
603 |
p.pln("throw new " +
|
|
604 |
SKELETON_MISMATCH_EXCEPTION + "(\"interface hash mismatch\");");
|
|
605 |
p.pO();
|
|
606 |
|
|
607 |
if (version == StubVersion.VCOMPAT) {
|
|
608 |
p.pOln("}"); // end if/else (opnum < 0) block
|
|
609 |
}
|
|
610 |
p.pln();
|
|
611 |
|
|
612 |
/*
|
|
613 |
* Cast remote object reference to the remote implementation
|
|
614 |
* class, if it's not private. We don't use the binary name
|
|
615 |
* of the class like previous implementations did because that
|
|
616 |
* would not compile with javac (since 1.4.1). If the remote
|
|
617 |
* implementation class is private, then we can't cast to it
|
|
618 |
* like previous implementations did because that also would
|
|
619 |
* not compile with javac-- so instead, we'll have to try to
|
|
620 |
* cast to the remote interface for each remote method.
|
|
621 |
*/
|
|
622 |
if (!remoteClass.classDoc().isPrivate()) {
|
|
623 |
p.pln(remoteClass.classDoc().qualifiedName() + " server = (" +
|
|
624 |
remoteClass.classDoc().qualifiedName() + ") obj;");
|
|
625 |
}
|
|
626 |
|
|
627 |
/*
|
|
628 |
* Process call according to the operation number.
|
|
629 |
*/
|
|
630 |
p.plnI("switch (opnum) {");
|
|
631 |
for (int opnum = 0; opnum < remoteMethods.length; opnum++) {
|
|
632 |
writeSkeletonDispatchCase(p, opnum);
|
|
633 |
}
|
|
634 |
p.pOlnI("default:");
|
|
635 |
/*
|
|
636 |
* Skeleton throws UnmarshalException if it does not recognize
|
|
637 |
* the operation number; this is consistent with the case of an
|
|
638 |
* unrecognized method hash.
|
|
639 |
*/
|
|
640 |
p.pln("throw new " + UNMARSHAL_EXCEPTION +
|
|
641 |
"(\"invalid method number\");");
|
|
642 |
p.pOln("}"); // end switch statement
|
|
643 |
|
|
644 |
p.pOln("}"); // end dispatch() method
|
|
645 |
|
|
646 |
p.pOln("}"); // end skeleton class
|
|
647 |
}
|
|
648 |
|
|
649 |
/**
|
|
650 |
* Writes the case block for the skeleton's dispatch method for
|
|
651 |
* the remote method with the given "opnum".
|
|
652 |
**/
|
|
653 |
private void writeSkeletonDispatchCase(IndentingWriter p, int opnum)
|
|
654 |
throws IOException
|
|
655 |
{
|
|
656 |
RemoteClass.Method method = remoteMethods[opnum];
|
|
657 |
MethodDoc methodDoc = method.methodDoc();
|
|
658 |
String methodName = methodDoc.name();
|
|
659 |
Type paramTypes[] = method.parameterTypes();
|
|
660 |
String paramNames[] = nameParameters(paramTypes);
|
|
661 |
Type returnType = methodDoc.returnType();
|
|
662 |
|
|
663 |
p.pOlnI("case " + opnum + ": // " +
|
|
664 |
Util.getFriendlyUnqualifiedSignature(methodDoc));
|
|
665 |
/*
|
|
666 |
* Use nested block statement inside case to provide an independent
|
|
667 |
* namespace for local variables used to unmarshal parameters for
|
|
668 |
* this remote method.
|
|
669 |
*/
|
|
670 |
p.pOlnI("{");
|
|
671 |
|
|
672 |
if (paramTypes.length > 0) {
|
|
673 |
/*
|
|
674 |
* Declare local variables to hold arguments.
|
|
675 |
*/
|
|
676 |
for (int i = 0; i < paramTypes.length; i++) {
|
|
677 |
p.pln(paramTypes[i].toString() + " " + paramNames[i] + ";");
|
|
678 |
}
|
|
679 |
|
|
680 |
/*
|
|
681 |
* Unmarshal arguments from call stream.
|
|
682 |
*/
|
|
683 |
p.plnI("try {");
|
|
684 |
p.pln("java.io.ObjectInput in = call.getInputStream();");
|
|
685 |
boolean objectsRead = writeUnmarshalArguments(p, "in",
|
|
686 |
paramTypes, paramNames);
|
|
687 |
p.pOlnI("} catch (java.io.IOException e) {");
|
|
688 |
p.pln("throw new " + UNMARSHAL_EXCEPTION +
|
|
689 |
"(\"error unmarshalling arguments\", e);");
|
|
690 |
/*
|
|
691 |
* If any only if readObject has been invoked, we must catch
|
|
692 |
* ClassNotFoundException as well as IOException.
|
|
693 |
*/
|
|
694 |
if (objectsRead) {
|
|
695 |
p.pOlnI("} catch (java.lang.ClassNotFoundException e) {");
|
|
696 |
p.pln("throw new " + UNMARSHAL_EXCEPTION +
|
|
697 |
"(\"error unmarshalling arguments\", e);");
|
|
698 |
}
|
|
699 |
p.pOlnI("} finally {");
|
|
700 |
p.pln("call.releaseInputStream();");
|
|
701 |
p.pOln("}");
|
|
702 |
} else {
|
|
703 |
p.pln("call.releaseInputStream();");
|
|
704 |
}
|
|
705 |
|
|
706 |
if (!Util.isVoid(returnType)) {
|
|
707 |
/*
|
|
708 |
* Declare variable to hold return type, if not void.
|
|
709 |
*/
|
|
710 |
p.p(returnType.toString() + " $result = ");
|
|
711 |
// REMIND: why $?
|
|
712 |
}
|
|
713 |
|
|
714 |
/*
|
|
715 |
* Invoke the method on the server object. If the remote
|
|
716 |
* implementation class is private, then we don't have a
|
|
717 |
* reference cast to it, and so we try to cast to the remote
|
|
718 |
* object reference to the method's declaring interface here.
|
|
719 |
*/
|
|
720 |
String target = remoteClass.classDoc().isPrivate() ?
|
|
721 |
"((" + methodDoc.containingClass().qualifiedName() + ") obj)" :
|
|
722 |
"server";
|
|
723 |
p.p(target + "." + methodName + "(");
|
|
724 |
for (int i = 0; i < paramNames.length; i++) {
|
|
725 |
if (i > 0)
|
|
726 |
p.p(", ");
|
|
727 |
p.p(paramNames[i]);
|
|
728 |
}
|
|
729 |
p.pln(");");
|
|
730 |
|
|
731 |
/*
|
|
732 |
* Always invoke getResultStream(true) on the call object to send
|
|
733 |
* the indication of a successful invocation to the caller. If
|
|
734 |
* the return type is not void, keep the result stream and marshal
|
|
735 |
* the return value.
|
|
736 |
*/
|
|
737 |
p.plnI("try {");
|
|
738 |
if (!Util.isVoid(returnType)) {
|
|
739 |
p.p("java.io.ObjectOutput out = ");
|
|
740 |
}
|
|
741 |
p.pln("call.getResultStream(true);");
|
|
742 |
if (!Util.isVoid(returnType)) {
|
|
743 |
writeMarshalArgument(p, "out", returnType, "$result");
|
|
744 |
p.pln(";");
|
|
745 |
}
|
|
746 |
p.pOlnI("} catch (java.io.IOException e) {");
|
|
747 |
p.pln("throw new " +
|
|
748 |
MARSHAL_EXCEPTION + "(\"error marshalling return\", e);");
|
|
749 |
p.pOln("}");
|
|
750 |
|
|
751 |
p.pln("break;"); // break from switch statement
|
|
752 |
|
|
753 |
p.pOlnI("}"); // end nested block statement
|
|
754 |
p.pln();
|
|
755 |
}
|
|
756 |
|
|
757 |
/**
|
|
758 |
* Writes declaration and initializer for "operations" static array.
|
|
759 |
**/
|
|
760 |
private void writeOperationsArray(IndentingWriter p)
|
|
761 |
throws IOException
|
|
762 |
{
|
|
763 |
p.plnI("private static final " + OPERATION + "[] operations = {");
|
|
764 |
for (int i = 0; i < remoteMethods.length; i++) {
|
|
765 |
if (i > 0)
|
|
766 |
p.pln(",");
|
|
767 |
p.p("new " + OPERATION + "(\"" +
|
|
768 |
remoteMethods[i].operationString() + "\")");
|
|
769 |
}
|
|
770 |
p.pln();
|
|
771 |
p.pOln("};");
|
|
772 |
}
|
|
773 |
|
|
774 |
/**
|
|
775 |
* Writes declaration and initializer for "interfaceHash" static field.
|
|
776 |
**/
|
|
777 |
private void writeInterfaceHash(IndentingWriter p)
|
|
778 |
throws IOException
|
|
779 |
{
|
|
780 |
p.pln("private static final long interfaceHash = " +
|
|
781 |
remoteClass.interfaceHash() + "L;");
|
|
782 |
}
|
|
783 |
|
|
784 |
/**
|
|
785 |
* Writes declaration for java.lang.reflect.Method static fields
|
|
786 |
* corresponding to each remote method in a stub.
|
|
787 |
**/
|
|
788 |
private void writeMethodFieldDeclarations(IndentingWriter p)
|
|
789 |
throws IOException
|
|
790 |
{
|
|
791 |
for (String name : methodFieldNames) {
|
|
792 |
p.pln("private static java.lang.reflect.Method " + name + ";");
|
|
793 |
}
|
|
794 |
}
|
|
795 |
|
|
796 |
/**
|
|
797 |
* Writes code to initialize the static fields for each method
|
|
798 |
* using the Java Reflection API.
|
|
799 |
**/
|
|
800 |
private void writeMethodFieldInitializers(IndentingWriter p)
|
|
801 |
throws IOException
|
|
802 |
{
|
|
803 |
for (int i = 0; i < methodFieldNames.length; i++) {
|
|
804 |
p.p(methodFieldNames[i] + " = ");
|
|
805 |
/*
|
|
806 |
* Look up the Method object in the somewhat arbitrary
|
|
807 |
* interface that we find in the Method object.
|
|
808 |
*/
|
|
809 |
RemoteClass.Method method = remoteMethods[i];
|
|
810 |
MethodDoc methodDoc = method.methodDoc();
|
|
811 |
String methodName = methodDoc.name();
|
|
812 |
Type paramTypes[] = method.parameterTypes();
|
|
813 |
|
|
814 |
p.p(methodDoc.containingClass().qualifiedName() + ".class.getMethod(\"" +
|
|
815 |
methodName + "\", new java.lang.Class[] {");
|
|
816 |
for (int j = 0; j < paramTypes.length; j++) {
|
|
817 |
if (j > 0)
|
|
818 |
p.p(", ");
|
|
819 |
p.p(paramTypes[j].toString() + ".class");
|
|
820 |
}
|
|
821 |
p.pln("});");
|
|
822 |
}
|
|
823 |
}
|
|
824 |
|
|
825 |
|
|
826 |
/*
|
|
827 |
* Following are a series of static utility methods useful during
|
|
828 |
* the code generation process:
|
|
829 |
*/
|
|
830 |
|
|
831 |
/**
|
|
832 |
* Generates an array of names for fields correspondins to the
|
|
833 |
* given array of remote methods. Each name in the returned array
|
|
834 |
* is guaranteed to be unique.
|
|
835 |
*
|
|
836 |
* The name of a method is included in its corresponding field
|
|
837 |
* name to enhance readability of the generated code.
|
|
838 |
**/
|
|
839 |
private static String[] nameMethodFields(RemoteClass.Method[] methods) {
|
|
840 |
String[] names = new String[methods.length];
|
|
841 |
for (int i = 0; i < names.length; i++) {
|
|
842 |
names[i] = "$method_" + methods[i].methodDoc().name() + "_" + i;
|
|
843 |
}
|
|
844 |
return names;
|
|
845 |
}
|
|
846 |
|
|
847 |
/**
|
|
848 |
* Generates an array of names for parameters corresponding to the
|
|
849 |
* given array of types for the parameters. Each name in the
|
|
850 |
* returned array is guaranteed to be unique.
|
|
851 |
*
|
|
852 |
* A representation of the type of a parameter is included in its
|
|
853 |
* corresponding parameter name to enhance the readability of the
|
|
854 |
* generated code.
|
|
855 |
**/
|
|
856 |
private static String[] nameParameters(Type[] types) {
|
|
857 |
String[] names = new String[types.length];
|
|
858 |
for (int i = 0; i < names.length; i++) {
|
|
859 |
names[i] = "$param_" +
|
|
860 |
generateNameFromType(types[i]) + "_" + (i + 1);
|
|
861 |
}
|
|
862 |
return names;
|
|
863 |
}
|
|
864 |
|
|
865 |
/**
|
|
866 |
* Generates a readable string representing the given type
|
|
867 |
* suitable for embedding within a Java identifier.
|
|
868 |
**/
|
|
869 |
private static String generateNameFromType(Type type) {
|
|
870 |
String name = type.typeName().replace('.', '$');
|
|
871 |
int dimensions = type.dimension().length() / 2;
|
|
872 |
for (int i = 0; i < dimensions; i++) {
|
|
873 |
name = "arrayOf_" + name;
|
|
874 |
}
|
|
875 |
return name;
|
|
876 |
}
|
|
877 |
|
|
878 |
/**
|
|
879 |
* Writes a snippet of Java code to marshal a value named "name"
|
|
880 |
* of type "type" to the java.io.ObjectOutput stream named
|
|
881 |
* "stream".
|
|
882 |
*
|
|
883 |
* Primitive types are marshalled with their corresponding methods
|
|
884 |
* in the java.io.DataOutput interface, and objects (including
|
|
885 |
* arrays) are marshalled using the writeObject method.
|
|
886 |
**/
|
|
887 |
private static void writeMarshalArgument(IndentingWriter p,
|
|
888 |
String streamName,
|
|
889 |
Type type, String name)
|
|
890 |
throws IOException
|
|
891 |
{
|
|
892 |
if (type.dimension().length() > 0 || type.asClassDoc() != null) {
|
|
893 |
p.p(streamName + ".writeObject(" + name + ")");
|
|
894 |
} else if (type.typeName().equals("boolean")) {
|
|
895 |
p.p(streamName + ".writeBoolean(" + name + ")");
|
|
896 |
} else if (type.typeName().equals("byte")) {
|
|
897 |
p.p(streamName + ".writeByte(" + name + ")");
|
|
898 |
} else if (type.typeName().equals("char")) {
|
|
899 |
p.p(streamName + ".writeChar(" + name + ")");
|
|
900 |
} else if (type.typeName().equals("short")) {
|
|
901 |
p.p(streamName + ".writeShort(" + name + ")");
|
|
902 |
} else if (type.typeName().equals("int")) {
|
|
903 |
p.p(streamName + ".writeInt(" + name + ")");
|
|
904 |
} else if (type.typeName().equals("long")) {
|
|
905 |
p.p(streamName + ".writeLong(" + name + ")");
|
|
906 |
} else if (type.typeName().equals("float")) {
|
|
907 |
p.p(streamName + ".writeFloat(" + name + ")");
|
|
908 |
} else if (type.typeName().equals("double")) {
|
|
909 |
p.p(streamName + ".writeDouble(" + name + ")");
|
|
910 |
} else {
|
|
911 |
throw new AssertionError(type);
|
|
912 |
}
|
|
913 |
}
|
|
914 |
|
|
915 |
/**
|
|
916 |
* Writes Java statements to marshal a series of values in order
|
|
917 |
* as named in the "names" array, with types as specified in the
|
|
918 |
* "types" array, to the java.io.ObjectOutput stream named
|
|
919 |
* "stream".
|
|
920 |
**/
|
|
921 |
private static void writeMarshalArguments(IndentingWriter p,
|
|
922 |
String streamName,
|
|
923 |
Type[] types, String[] names)
|
|
924 |
throws IOException
|
|
925 |
{
|
|
926 |
assert types.length == names.length;
|
|
927 |
|
|
928 |
for (int i = 0; i < types.length; i++) {
|
|
929 |
writeMarshalArgument(p, streamName, types[i], names[i]);
|
|
930 |
p.pln(";");
|
|
931 |
}
|
|
932 |
}
|
|
933 |
|
|
934 |
/**
|
|
935 |
* Writes a snippet of Java code to unmarshal a value of type
|
|
936 |
* "type" from the java.io.ObjectInput stream named "stream" into
|
|
937 |
* a variable named "name" (if "name" is null, the value is
|
|
938 |
* unmarshalled and discarded).
|
|
939 |
*
|
|
940 |
* Primitive types are unmarshalled with their corresponding
|
|
941 |
* methods in the java.io.DataInput interface, and objects
|
|
942 |
* (including arrays) are unmarshalled using the readObject
|
|
943 |
* method.
|
|
944 |
*
|
|
945 |
* Returns true if code to invoke readObject was written, and
|
|
946 |
* false otherwise.
|
|
947 |
**/
|
|
948 |
private static boolean writeUnmarshalArgument(IndentingWriter p,
|
|
949 |
String streamName,
|
|
950 |
Type type, String name)
|
|
951 |
throws IOException
|
|
952 |
{
|
|
953 |
boolean readObject = false;
|
|
954 |
|
|
955 |
if (name != null) {
|
|
956 |
p.p(name + " = ");
|
|
957 |
}
|
|
958 |
|
|
959 |
if (type.dimension().length() > 0 || type.asClassDoc() != null) {
|
|
960 |
p.p("(" + type.toString() + ") " + streamName + ".readObject()");
|
|
961 |
readObject = true;
|
|
962 |
} else if (type.typeName().equals("boolean")) {
|
|
963 |
p.p(streamName + ".readBoolean()");
|
|
964 |
} else if (type.typeName().equals("byte")) {
|
|
965 |
p.p(streamName + ".readByte()");
|
|
966 |
} else if (type.typeName().equals("char")) {
|
|
967 |
p.p(streamName + ".readChar()");
|
|
968 |
} else if (type.typeName().equals("short")) {
|
|
969 |
p.p(streamName + ".readShort()");
|
|
970 |
} else if (type.typeName().equals("int")) {
|
|
971 |
p.p(streamName + ".readInt()");
|
|
972 |
} else if (type.typeName().equals("long")) {
|
|
973 |
p.p(streamName + ".readLong()");
|
|
974 |
} else if (type.typeName().equals("float")) {
|
|
975 |
p.p(streamName + ".readFloat()");
|
|
976 |
} else if (type.typeName().equals("double")) {
|
|
977 |
p.p(streamName + ".readDouble()");
|
|
978 |
} else {
|
|
979 |
throw new AssertionError(type);
|
|
980 |
}
|
|
981 |
|
|
982 |
return readObject;
|
|
983 |
}
|
|
984 |
|
|
985 |
/**
|
|
986 |
* Writes Java statements to unmarshal a series of values in order
|
|
987 |
* of types as in the "types" array from the java.io.ObjectInput
|
|
988 |
* stream named "stream" into variables as named in "names" (for
|
|
989 |
* any element of "names" that is null, the corresponding value is
|
|
990 |
* unmarshalled and discarded).
|
|
991 |
**/
|
|
992 |
private static boolean writeUnmarshalArguments(IndentingWriter p,
|
|
993 |
String streamName,
|
|
994 |
Type[] types,
|
|
995 |
String[] names)
|
|
996 |
throws IOException
|
|
997 |
{
|
|
998 |
assert types.length == names.length;
|
|
999 |
|
|
1000 |
boolean readObject = false;
|
|
1001 |
for (int i = 0; i < types.length; i++) {
|
|
1002 |
if (writeUnmarshalArgument(p, streamName, types[i], names[i])) {
|
|
1003 |
readObject = true;
|
|
1004 |
}
|
|
1005 |
p.pln(";");
|
|
1006 |
}
|
|
1007 |
return readObject;
|
|
1008 |
}
|
|
1009 |
|
|
1010 |
/**
|
|
1011 |
* Returns a snippet of Java code to wrap a value named "name" of
|
|
1012 |
* type "type" into an object as appropriate for use by the Java
|
|
1013 |
* Reflection API.
|
|
1014 |
*
|
|
1015 |
* For primitive types, an appropriate wrapper class is
|
|
1016 |
* instantiated with the primitive value. For object types
|
|
1017 |
* (including arrays), no wrapping is necessary, so the value is
|
|
1018 |
* named directly.
|
|
1019 |
**/
|
|
1020 |
private static String wrapArgumentCode(Type type, String name) {
|
|
1021 |
if (type.dimension().length() > 0 || type.asClassDoc() != null) {
|
|
1022 |
return name;
|
|
1023 |
} else if (type.typeName().equals("boolean")) {
|
|
1024 |
return ("(" + name +
|
|
1025 |
" ? java.lang.Boolean.TRUE : java.lang.Boolean.FALSE)");
|
|
1026 |
} else if (type.typeName().equals("byte")) {
|
|
1027 |
return "new java.lang.Byte(" + name + ")";
|
|
1028 |
} else if (type.typeName().equals("char")) {
|
|
1029 |
return "new java.lang.Character(" + name + ")";
|
|
1030 |
} else if (type.typeName().equals("short")) {
|
|
1031 |
return "new java.lang.Short(" + name + ")";
|
|
1032 |
} else if (type.typeName().equals("int")) {
|
|
1033 |
return "new java.lang.Integer(" + name + ")";
|
|
1034 |
} else if (type.typeName().equals("long")) {
|
|
1035 |
return "new java.lang.Long(" + name + ")";
|
|
1036 |
} else if (type.typeName().equals("float")) {
|
|
1037 |
return "new java.lang.Float(" + name + ")";
|
|
1038 |
} else if (type.typeName().equals("double")) {
|
|
1039 |
return "new java.lang.Double(" + name + ")";
|
|
1040 |
} else {
|
|
1041 |
throw new AssertionError(type);
|
|
1042 |
}
|
|
1043 |
}
|
|
1044 |
|
|
1045 |
/**
|
|
1046 |
* Returns a snippet of Java code to unwrap a value named "name"
|
|
1047 |
* into a value of type "type", as appropriate for the Java
|
|
1048 |
* Reflection API.
|
|
1049 |
*
|
|
1050 |
* For primitive types, the value is assumed to be of the
|
|
1051 |
* corresponding wrapper class, and a method is called on the
|
|
1052 |
* wrapper to retrieve the primitive value. For object types
|
|
1053 |
* (include arrays), no unwrapping is necessary; the value is
|
|
1054 |
* simply cast to the expected real object type.
|
|
1055 |
**/
|
|
1056 |
private static String unwrapArgumentCode(Type type, String name) {
|
|
1057 |
if (type.dimension().length() > 0 || type.asClassDoc() != null) {
|
|
1058 |
return "((" + type.toString() + ") " + name + ")";
|
|
1059 |
} else if (type.typeName().equals("boolean")) {
|
|
1060 |
return "((java.lang.Boolean) " + name + ").booleanValue()";
|
|
1061 |
} else if (type.typeName().equals("byte")) {
|
|
1062 |
return "((java.lang.Byte) " + name + ").byteValue()";
|
|
1063 |
} else if (type.typeName().equals("char")) {
|
|
1064 |
return "((java.lang.Character) " + name + ").charValue()";
|
|
1065 |
} else if (type.typeName().equals("short")) {
|
|
1066 |
return "((java.lang.Short) " + name + ").shortValue()";
|
|
1067 |
} else if (type.typeName().equals("int")) {
|
|
1068 |
return "((java.lang.Integer) " + name + ").intValue()";
|
|
1069 |
} else if (type.typeName().equals("long")) {
|
|
1070 |
return "((java.lang.Long) " + name + ").longValue()";
|
|
1071 |
} else if (type.typeName().equals("float")) {
|
|
1072 |
return "((java.lang.Float) " + name + ").floatValue()";
|
|
1073 |
} else if (type.typeName().equals("double")) {
|
|
1074 |
return "((java.lang.Double) " + name + ").doubleValue()";
|
|
1075 |
} else {
|
|
1076 |
throw new AssertionError(type);
|
|
1077 |
}
|
|
1078 |
}
|
|
1079 |
}
|