Print this page
Split |
Close |
Expand all |
Collapse all |
--- old/src/share/classes/sun/rmi/rmic/RMIGenerator.java
+++ new/src/share/classes/sun/rmi/rmic/RMIGenerator.java
1 1 /*
2 2 * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 4 *
5 5 * This code is free software; you can redistribute it and/or modify it
6 6 * under the terms of the GNU General Public License version 2 only, as
7 7 * published by the Free Software Foundation. Oracle designates this
8 8 * particular file as subject to the "Classpath" exception as provided
9 9 * by Oracle in the LICENSE file that accompanied this code.
10 10 *
11 11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 14 * version 2 for more details (a copy is included in the LICENSE file that
15 15 * accompanied this code).
16 16 *
17 17 * You should have received a copy of the GNU General Public License version
18 18 * 2 along with this work; if not, write to the Free Software Foundation,
19 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 20 *
21 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 22 * or visit www.oracle.com if you need additional information or have any
23 23 * questions.
24 24 */
25 25
26 26 /*****************************************************************************/
27 27 /* Copyright (c) IBM Corporation 1998 */
28 28 /* */
29 29 /* (C) Copyright IBM Corp. 1998 */
30 30 /* */
31 31 /*****************************************************************************/
32 32
33 33 package sun.rmi.rmic;
34 34
35 35 import java.io.File;
36 36 import java.io.FileOutputStream;
37 37 import java.io.OutputStreamWriter;
38 38 import java.io.IOException;
39 39 import java.util.Enumeration;
40 40 import java.util.Hashtable;
41 41 import java.util.Vector;
42 42 import sun.tools.java.Type;
43 43 import sun.tools.java.Identifier;
44 44 import sun.tools.java.ClassDefinition;
45 45 import sun.tools.java.ClassDeclaration;
46 46 import sun.tools.java.ClassNotFound;
47 47 import sun.tools.java.ClassFile;
48 48 import sun.tools.java.MemberDefinition;
49 49 import com.sun.corba.se.impl.util.Utility;
50 50
51 51 /**
52 52 * A Generator object will generate the Java source code of the stub
53 53 * and skeleton classes for an RMI remote implementation class, using
↓ open down ↓ |
53 lines elided |
↑ open up ↑ |
54 54 * a particular stub protocol version.
55 55 *
56 56 * WARNING: The contents of this source file are not part of any
57 57 * supported API. Code that depends on them does so at its own risk:
58 58 * they are subject to change or removal without notice.
59 59 *
60 60 * @author Peter Jones, Bryan Atsatt
61 61 */
62 62 public class RMIGenerator implements RMIConstants, Generator {
63 63
64 - private static final Hashtable<String, Integer> versionOptions = new Hashtable<>();
64 + private static final Hashtable versionOptions = new Hashtable();
65 65 static {
66 66 versionOptions.put("-v1.1", new Integer(STUB_VERSION_1_1));
67 67 versionOptions.put("-vcompat", new Integer(STUB_VERSION_FAT));
68 68 versionOptions.put("-v1.2", new Integer(STUB_VERSION_1_2));
69 69 }
70 70
71 71 /**
72 72 * Default constructor for Main to use.
73 73 */
74 74 public RMIGenerator() {
75 75 version = STUB_VERSION_1_2; // default is -v1.2 (see 4638155)
76 76 }
77 77
78 78 /**
79 79 * Examine and consume command line arguments.
80 80 * @param argv The command line arguments. Ignore null
81 81 * and unknown arguments. Set each consumed argument to null.
82 82 * @param error Report any errors using the main.error() methods.
83 83 * @return true if no errors, false otherwise.
84 84 */
85 85 public boolean parseArgs(String argv[], Main main) {
86 86 String explicitVersion = null;
87 87 for (int i = 0; i < argv.length; i++) {
88 88 if (argv[i] != null) {
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
89 89 String arg = argv[i].toLowerCase();
90 90 if (versionOptions.containsKey(arg)) {
91 91 if (explicitVersion != null &&
92 92 !explicitVersion.equals(arg))
93 93 {
94 94 main.error("rmic.cannot.use.both",
95 95 explicitVersion, arg);
96 96 return false;
97 97 }
98 98 explicitVersion = arg;
99 - version = versionOptions.get(arg);
99 + version = ((Integer) versionOptions.get(arg)).intValue();
100 100 argv[i] = null;
101 101 }
102 102 }
103 103 }
104 104 return true;
105 105 }
106 106
107 107 /**
108 108 * Generate the source files for the stub and/or skeleton classes
109 109 * needed by RMI for the given remote implementation class.
110 110 *
111 111 * @param env compiler environment
112 112 * @param cdef definition of remote implementation class
113 113 * to generate stubs and/or skeletons for
114 114 * @param destDir directory for the root of the package hierarchy
115 115 * for generated files
116 116 */
117 117 public void generate(BatchEnvironment env, ClassDefinition cdef, File destDir) {
118 118 RemoteClass remoteClass = RemoteClass.forClass(env, cdef);
119 119 if (remoteClass == null) // exit if an error occurred
120 120 return;
121 121
122 122 RMIGenerator gen;
123 123 try {
124 124 gen = new RMIGenerator(env, cdef, destDir, remoteClass, version);
125 125 } catch (ClassNotFound e) {
126 126 env.error(0, "rmic.class.not.found", e.name);
127 127 return;
128 128 }
129 129 gen.generate();
130 130 }
131 131
132 132 private void generate() {
133 133 env.addGeneratedFile(stubFile);
134 134
135 135 try {
136 136 IndentingWriter out = new IndentingWriter(
137 137 new OutputStreamWriter(new FileOutputStream(stubFile)));
138 138 writeStub(out);
139 139 out.close();
140 140 if (env.verbose()) {
141 141 env.output(Main.getText("rmic.wrote", stubFile.getPath()));
142 142 }
143 143 env.parseFile(new ClassFile(stubFile));
144 144 } catch (IOException e) {
145 145 env.error(0, "cant.write", stubFile.toString());
146 146 return;
147 147 }
148 148
149 149 if (version == STUB_VERSION_1_1 ||
150 150 version == STUB_VERSION_FAT)
151 151 {
152 152 env.addGeneratedFile(skeletonFile);
153 153
154 154 try {
155 155 IndentingWriter out = new IndentingWriter(
156 156 new OutputStreamWriter(
157 157 new FileOutputStream(skeletonFile)));
158 158 writeSkeleton(out);
159 159 out.close();
160 160 if (env.verbose()) {
161 161 env.output(Main.getText("rmic.wrote",
162 162 skeletonFile.getPath()));
163 163 }
164 164 env.parseFile(new ClassFile(skeletonFile));
165 165 } catch (IOException e) {
166 166 env.error(0, "cant.write", stubFile.toString());
167 167 return;
168 168 }
169 169 } else {
170 170 /*
171 171 * For bugid 4135136: if skeleton files are not being generated
172 172 * for this compilation run, delete old skeleton source or class
173 173 * files for this remote implementation class that were
174 174 * (presumably) left over from previous runs, to avoid user
175 175 * confusion from extraneous or inconsistent generated files.
176 176 */
177 177
178 178 File outputDir = Util.getOutputDirectoryFor(remoteClassName,destDir,env);
179 179 File skeletonClassFile = new File(outputDir,skeletonClassName.getName().toString() + ".class");
180 180
181 181 skeletonFile.delete(); // ignore failures (no big deal)
182 182 skeletonClassFile.delete();
183 183 }
184 184 }
185 185
186 186 /**
187 187 * Return the File object that should be used as the source file
188 188 * for the given Java class, using the supplied destination
189 189 * directory for the top of the package hierarchy.
190 190 */
191 191 protected static File sourceFileForClass(Identifier className,
192 192 Identifier outputClassName,
193 193 File destDir,
194 194 BatchEnvironment env)
195 195 {
196 196 File packageDir = Util.getOutputDirectoryFor(className,destDir,env);
197 197 String outputName = Names.mangleClass(outputClassName).getName().toString();
198 198
199 199 // Is there any existing _Tie equivalent leftover from a
200 200 // previous invocation of rmic -iiop? Only do this once per
201 201 // class by looking for skeleton generation...
202 202
203 203 if (outputName.endsWith("_Skel")) {
204 204 String classNameStr = className.getName().toString();
205 205 File temp = new File(packageDir, Utility.tieName(classNameStr) + ".class");
206 206 if (temp.exists()) {
207 207
208 208 // Found a tie. Is IIOP generation also being done?
209 209
210 210 if (!env.getMain().iiopGeneration) {
211 211
212 212 // No, so write a warning...
213 213
214 214 env.error(0,"warn.rmic.tie.found",
215 215 classNameStr,
216 216 temp.getAbsolutePath());
217 217 }
218 218 }
219 219 }
220 220
221 221 String outputFileName = outputName + ".java";
222 222 return new File(packageDir, outputFileName);
223 223 }
224 224
225 225
226 226 /** rmic environment for this object */
227 227 private BatchEnvironment env;
228 228
229 229 /** the remote class that this instance is generating code for */
230 230 private RemoteClass remoteClass;
231 231
232 232 /** version of the stub protocol to use in code generation */
233 233 private int version;
234 234
235 235 /** remote methods for remote class, indexed by operation number */
236 236 private RemoteClass.Method[] remoteMethods;
237 237
238 238 /**
239 239 * Names for the remote class and the stub and skeleton classes
240 240 * to be generated for it.
241 241 */
242 242 private Identifier remoteClassName;
243 243 private Identifier stubClassName;
244 244 private Identifier skeletonClassName;
245 245
246 246 private ClassDefinition cdef;
247 247 private File destDir;
248 248 private File stubFile;
249 249 private File skeletonFile;
250 250
251 251 /**
252 252 * Names to use for the java.lang.reflect.Method static fields
253 253 * corresponding to each remote method.
254 254 */
255 255 private String[] methodFieldNames;
256 256
257 257 /** cached definition for certain exception classes in this environment */
258 258 private ClassDefinition defException;
259 259 private ClassDefinition defRemoteException;
260 260 private ClassDefinition defRuntimeException;
261 261
262 262 /**
263 263 * Create a new stub/skeleton Generator object for the given
264 264 * remote implementation class to generate code according to
265 265 * the given stub protocol version.
266 266 */
267 267 private RMIGenerator(BatchEnvironment env, ClassDefinition cdef,
268 268 File destDir, RemoteClass remoteClass, int version)
269 269 throws ClassNotFound
270 270 {
271 271 this.destDir = destDir;
272 272 this.cdef = cdef;
273 273 this.env = env;
274 274 this.remoteClass = remoteClass;
275 275 this.version = version;
276 276
277 277 remoteMethods = remoteClass.getRemoteMethods();
278 278
279 279 remoteClassName = remoteClass.getName();
280 280 stubClassName = Names.stubFor(remoteClassName);
281 281 skeletonClassName = Names.skeletonFor(remoteClassName);
282 282
283 283 methodFieldNames = nameMethodFields(remoteMethods);
284 284
285 285 stubFile = sourceFileForClass(remoteClassName,stubClassName, destDir , env);
286 286 skeletonFile = sourceFileForClass(remoteClassName,skeletonClassName, destDir, env);
287 287
288 288 /*
289 289 * Initialize cached definitions for exception classes used
290 290 * in the generation process.
291 291 */
292 292 defException =
293 293 env.getClassDeclaration(idJavaLangException).
294 294 getClassDefinition(env);
295 295 defRemoteException =
296 296 env.getClassDeclaration(idRemoteException).
297 297 getClassDefinition(env);
298 298 defRuntimeException =
299 299 env.getClassDeclaration(idJavaLangRuntimeException).
300 300 getClassDefinition(env);
301 301 }
302 302
303 303 /**
304 304 * Write the stub for the remote class to a stream.
305 305 */
306 306 private void writeStub(IndentingWriter p) throws IOException {
307 307
308 308 /*
309 309 * Write boiler plate comment.
310 310 */
311 311 p.pln("// Stub class generated by rmic, do not edit.");
312 312 p.pln("// Contents subject to change without notice.");
313 313 p.pln();
314 314
315 315 /*
316 316 * If remote implementation class was in a particular package,
317 317 * declare the stub class to be in the same package.
318 318 */
319 319 if (remoteClassName.isQualified()) {
320 320 p.pln("package " + remoteClassName.getQualifier() + ";");
321 321 p.pln();
322 322 }
323 323
324 324 /*
325 325 * Declare the stub class; implement all remote interfaces.
326 326 */
327 327 p.plnI("public final class " +
328 328 Names.mangleClass(stubClassName.getName()));
329 329 p.pln("extends " + idRemoteStub);
330 330 ClassDefinition[] remoteInterfaces = remoteClass.getRemoteInterfaces();
331 331 if (remoteInterfaces.length > 0) {
332 332 p.p("implements ");
333 333 for (int i = 0; i < remoteInterfaces.length; i++) {
334 334 if (i > 0)
335 335 p.p(", ");
336 336 p.p(remoteInterfaces[i].getName().toString());
337 337 }
338 338 p.pln();
339 339 }
340 340 p.pOlnI("{");
341 341
342 342 if (version == STUB_VERSION_1_1 ||
343 343 version == STUB_VERSION_FAT)
344 344 {
345 345 writeOperationsArray(p);
346 346 p.pln();
347 347 writeInterfaceHash(p);
348 348 p.pln();
349 349 }
350 350
351 351 if (version == STUB_VERSION_FAT ||
352 352 version == STUB_VERSION_1_2)
353 353 {
354 354 p.pln("private static final long serialVersionUID = " +
355 355 STUB_SERIAL_VERSION_UID + ";");
356 356 p.pln();
357 357
358 358 /*
359 359 * We only need to declare and initialize the static fields of
360 360 * Method objects for each remote method if there are any remote
361 361 * methods; otherwise, skip this code entirely, to avoid generating
362 362 * a try/catch block for a checked exception that cannot occur
363 363 * (see bugid 4125181).
364 364 */
365 365 if (methodFieldNames.length > 0) {
366 366 if (version == STUB_VERSION_FAT) {
367 367 p.pln("private static boolean useNewInvoke;");
368 368 }
369 369 writeMethodFieldDeclarations(p);
370 370 p.pln();
371 371
372 372 /*
373 373 * Initialize java.lang.reflect.Method fields for each remote
374 374 * method in a static initializer.
375 375 */
376 376 p.plnI("static {");
377 377 p.plnI("try {");
378 378 if (version == STUB_VERSION_FAT) {
379 379 /*
380 380 * Fat stubs must determine whether the API required for
381 381 * the JDK 1.2 stub protocol is supported in the current
382 382 * runtime, so that it can use it if supported. This is
383 383 * determined by using the Reflection API to test if the
384 384 * new invoke method on RemoteRef exists, and setting the
385 385 * static boolean "useNewInvoke" to true if it does, or
386 386 * to false if a NoSuchMethodException is thrown.
387 387 */
388 388 p.plnI(idRemoteRef + ".class.getMethod(\"invoke\",");
389 389 p.plnI("new java.lang.Class[] {");
390 390 p.pln(idRemote + ".class,");
391 391 p.pln("java.lang.reflect.Method.class,");
392 392 p.pln("java.lang.Object[].class,");
393 393 p.pln("long.class");
394 394 p.pOln("});");
395 395 p.pO();
396 396 p.pln("useNewInvoke = true;");
397 397 }
398 398 writeMethodFieldInitializers(p);
399 399 p.pOlnI("} catch (java.lang.NoSuchMethodException e) {");
400 400 if (version == STUB_VERSION_FAT) {
401 401 p.pln("useNewInvoke = false;");
402 402 } else {
403 403 /*
404 404 * REMIND: By throwing an Error here, the application will
405 405 * get the NoSuchMethodError directly when the stub class
406 406 * is initialized. If we throw a RuntimeException
407 407 * instead, the application would get an
408 408 * ExceptionInInitializerError. Would that be more
409 409 * appropriate, and if so, which RuntimeException should
410 410 * be thrown?
411 411 */
412 412 p.plnI("throw new java.lang.NoSuchMethodError(");
413 413 p.pln("\"stub class initialization failed\");");
414 414 p.pO();
415 415 }
416 416 p.pOln("}"); // end try/catch block
417 417 p.pOln("}"); // end static initializer
418 418 p.pln();
419 419 }
420 420 }
421 421
422 422 writeStubConstructors(p);
423 423 p.pln();
424 424
425 425 /*
426 426 * Write each stub method.
427 427 */
428 428 if (remoteMethods.length > 0) {
429 429 p.pln("// methods from remote interfaces");
430 430 for (int i = 0; i < remoteMethods.length; ++i) {
431 431 p.pln();
432 432 writeStubMethod(p, i);
433 433 }
434 434 }
435 435
436 436 p.pOln("}"); // end stub class
437 437 }
438 438
439 439 /**
440 440 * Write the constructors for the stub class.
441 441 */
442 442 private void writeStubConstructors(IndentingWriter p)
443 443 throws IOException
444 444 {
445 445 p.pln("// constructors");
446 446
447 447 /*
448 448 * Only stubs compatible with the JDK 1.1 stub protocol need
449 449 * a no-arg constructor; later versions use reflection to find
450 450 * the constructor that directly takes a RemoteRef argument.
451 451 */
452 452 if (version == STUB_VERSION_1_1 ||
453 453 version == STUB_VERSION_FAT)
454 454 {
455 455 p.plnI("public " + Names.mangleClass(stubClassName.getName()) +
456 456 "() {");
457 457 p.pln("super();");
458 458 p.pOln("}");
459 459 }
460 460
461 461 p.plnI("public " + Names.mangleClass(stubClassName.getName()) +
462 462 "(" + idRemoteRef + " ref) {");
463 463 p.pln("super(ref);");
464 464 p.pOln("}");
465 465 }
466 466
467 467 /**
468 468 * Write the stub method for the remote method with the given "opnum".
469 469 */
470 470 private void writeStubMethod(IndentingWriter p, int opnum)
471 471 throws IOException
472 472 {
473 473 RemoteClass.Method method = remoteMethods[opnum];
474 474 Identifier methodName = method.getName();
475 475 Type methodType = method.getType();
476 476 Type paramTypes[] = methodType.getArgumentTypes();
477 477 String paramNames[] = nameParameters(paramTypes);
478 478 Type returnType = methodType.getReturnType();
479 479 ClassDeclaration[] exceptions = method.getExceptions();
480 480
481 481 /*
482 482 * Declare stub method; throw exceptions declared in remote
483 483 * interface(s).
484 484 */
485 485 p.pln("// implementation of " +
486 486 methodType.typeString(methodName.toString(), true, false));
487 487 p.p("public " + returnType + " " + methodName + "(");
488 488 for (int i = 0; i < paramTypes.length; i++) {
489 489 if (i > 0)
490 490 p.p(", ");
491 491 p.p(paramTypes[i] + " " + paramNames[i]);
492 492 }
493 493 p.plnI(")");
494 494 if (exceptions.length > 0) {
495 495 p.p("throws ");
496 496 for (int i = 0; i < exceptions.length; i++) {
497 497 if (i > 0)
498 498 p.p(", ");
499 499 p.p(exceptions[i].getName().toString());
500 500 }
501 501 p.pln();
502 502 }
503 503 p.pOlnI("{");
504 504
505 505 /*
506 506 * The RemoteRef.invoke methods throw Exception, but unless this
507 507 * stub method throws Exception as well, we must catch Exceptions
508 508 * thrown from the invocation. So we must catch Exception and
509 509 * rethrow something we can throw: UnexpectedException, which is a
510 510 * subclass of RemoteException. But for any subclasses of Exception
511 511 * that we can throw, like RemoteException, RuntimeException, and
↓ open down ↓ |
402 lines elided |
↑ open up ↑ |
512 512 * any of the exceptions declared by this stub method, we want them
513 513 * to pass through unharmed, so first we must catch any such
514 514 * exceptions and rethrow it directly.
515 515 *
516 516 * We have to be careful generating the rethrowing catch blocks
517 517 * here, because javac will flag an error if there are any
518 518 * unreachable catch blocks, i.e. if the catch of an exception class
519 519 * follows a previous catch of it or of one of its superclasses.
520 520 * The following method invocation takes care of these details.
521 521 */
522 - Vector<ClassDefinition> catchList = computeUniqueCatchList(exceptions);
522 + Vector catchList = computeUniqueCatchList(exceptions);
523 523
524 524 /*
525 525 * If we need to catch any particular exceptions (i.e. this method
526 526 * does not declare java.lang.Exception), put the entire stub
527 527 * method in a try block.
528 528 */
529 529 if (catchList.size() > 0) {
530 530 p.plnI("try {");
531 531 }
532 532
533 533 if (version == STUB_VERSION_FAT) {
534 534 p.plnI("if (useNewInvoke) {");
535 535 }
536 536 if (version == STUB_VERSION_FAT ||
537 537 version == STUB_VERSION_1_2)
538 538 {
539 539 if (!returnType.isType(TC_VOID)) {
540 540 p.p("Object $result = "); // REMIND: why $?
541 541 }
542 542 p.p("ref.invoke(this, " + methodFieldNames[opnum] + ", ");
543 543 if (paramTypes.length > 0) {
544 544 p.p("new java.lang.Object[] {");
545 545 for (int i = 0; i < paramTypes.length; i++) {
546 546 if (i > 0)
547 547 p.p(", ");
548 548 p.p(wrapArgumentCode(paramTypes[i], paramNames[i]));
549 549 }
550 550 p.p("}");
551 551 } else {
552 552 p.p("null");
553 553 }
554 554 p.pln(", " + method.getMethodHash() + "L);");
555 555 if (!returnType.isType(TC_VOID)) {
556 556 p.pln("return " +
557 557 unwrapArgumentCode(returnType, "$result") + ";");
558 558 }
559 559 }
560 560 if (version == STUB_VERSION_FAT) {
561 561 p.pOlnI("} else {");
562 562 }
563 563 if (version == STUB_VERSION_1_1 ||
564 564 version == STUB_VERSION_FAT)
565 565 {
566 566 p.pln(idRemoteCall + " call = ref.newCall((" + idRemoteObject +
567 567 ") this, operations, " + opnum + ", interfaceHash);");
568 568
569 569 if (paramTypes.length > 0) {
570 570 p.plnI("try {");
571 571 p.pln("java.io.ObjectOutput out = call.getOutputStream();");
572 572 writeMarshalArguments(p, "out", paramTypes, paramNames);
573 573 p.pOlnI("} catch (java.io.IOException e) {");
574 574 p.pln("throw new " + idMarshalException +
575 575 "(\"error marshalling arguments\", e);");
576 576 p.pOln("}");
577 577 }
578 578
579 579 p.pln("ref.invoke(call);");
580 580
581 581 if (returnType.isType(TC_VOID)) {
582 582 p.pln("ref.done(call);");
583 583 } else {
584 584 p.pln(returnType + " $result;"); // REMIND: why $?
585 585 p.plnI("try {");
586 586 p.pln("java.io.ObjectInput in = call.getInputStream();");
587 587 boolean objectRead =
588 588 writeUnmarshalArgument(p, "in", returnType, "$result");
589 589 p.pln(";");
590 590 p.pOlnI("} catch (java.io.IOException e) {");
591 591 p.pln("throw new " + idUnmarshalException +
592 592 "(\"error unmarshalling return\", e);");
593 593 /*
594 594 * If any only if readObject has been invoked, we must catch
595 595 * ClassNotFoundException as well as IOException.
596 596 */
597 597 if (objectRead) {
598 598 p.pOlnI("} catch (java.lang.ClassNotFoundException e) {");
599 599 p.pln("throw new " + idUnmarshalException +
600 600 "(\"error unmarshalling return\", e);");
601 601 }
602 602 p.pOlnI("} finally {");
603 603 p.pln("ref.done(call);");
604 604 p.pOln("}");
605 605 p.pln("return $result;");
606 606 }
607 607 }
↓ open down ↓ |
75 lines elided |
↑ open up ↑ |
608 608 if (version == STUB_VERSION_FAT) {
609 609 p.pOln("}"); // end if/else (useNewInvoke) block
610 610 }
611 611
612 612 /*
613 613 * If we need to catch any particular exceptions, finally write
614 614 * the catch blocks for them, rethrow any other Exceptions with an
615 615 * UnexpectedException, and end the try block.
616 616 */
617 617 if (catchList.size() > 0) {
618 - for (Enumeration<ClassDefinition> enumeration = catchList.elements();
618 + for (Enumeration enumeration = catchList.elements();
619 619 enumeration.hasMoreElements();)
620 620 {
621 - ClassDefinition def = enumeration.nextElement();
621 + ClassDefinition def = (ClassDefinition) enumeration.nextElement();
622 622 p.pOlnI("} catch (" + def.getName() + " e) {");
623 623 p.pln("throw e;");
624 624 }
625 625 p.pOlnI("} catch (java.lang.Exception e) {");
626 626 p.pln("throw new " + idUnexpectedException +
627 627 "(\"undeclared checked exception\", e);");
628 628 p.pOln("}"); // end try/catch block
629 629 }
630 630
631 631 p.pOln("}"); // end stub method
632 632 }
633 633
634 634 /**
635 635 * Compute the exceptions which need to be caught and rethrown in a
636 636 * stub method before wrapping Exceptions in UnexpectedExceptions,
637 637 * given the exceptions declared in the throws clause of the method.
638 638 * Returns a Vector containing ClassDefinition objects for each
639 639 * exception to catch. Each exception is guaranteed to be unique,
640 640 * i.e. not a subclass of any of the other exceptions in the Vector,
641 641 * so the catch blocks for these exceptions may be generated in any
642 642 * order relative to each other.
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
643 643 *
644 644 * RemoteException and RuntimeException are each automatically placed
645 645 * in the returned Vector (if none of their superclasses are already
646 646 * present), since those exceptions should always be directly rethrown
647 647 * by a stub method.
648 648 *
649 649 * The returned Vector will be empty if java.lang.Exception or one
650 650 * of its superclasses is in the throws clause of the method, indicating
651 651 * that no exceptions need to be caught.
652 652 */
653 - private Vector<ClassDefinition> computeUniqueCatchList(ClassDeclaration[] exceptions) {
654 - Vector<ClassDefinition> uniqueList = new Vector<>(); // unique exceptions to catch
653 + private Vector computeUniqueCatchList(ClassDeclaration[] exceptions) {
654 + Vector uniqueList = new Vector(); // unique exceptions to catch
655 655
656 656 uniqueList.addElement(defRuntimeException);
657 657 uniqueList.addElement(defRemoteException);
658 658
659 659 /* For each exception declared by the stub method's throws clause: */
660 660 nextException:
661 661 for (int i = 0; i < exceptions.length; i++) {
662 662 ClassDeclaration decl = exceptions[i];
663 663 try {
664 664 if (defException.subClassOf(env, decl)) {
665 665 /*
666 666 * (If java.lang.Exception (or a superclass) was declared
667 667 * in the throws clause of this stub method, then we don't
668 668 * have to bother catching anything; clear the list and
669 669 * return.)
670 670 */
671 671 uniqueList.clear();
672 672 break;
673 673 } else if (!defException.superClassOf(env, decl)) {
674 674 /*
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
675 675 * Ignore other Throwables that do not extend Exception,
676 676 * since they do not need to be caught anyway.
677 677 */
678 678 continue;
679 679 }
680 680 /*
681 681 * Compare this exception against the current list of
682 682 * exceptions that need to be caught:
683 683 */
684 684 for (int j = 0; j < uniqueList.size();) {
685 - ClassDefinition def = uniqueList.elementAt(j);
685 + ClassDefinition def =
686 + (ClassDefinition) uniqueList.elementAt(j);
686 687 if (def.superClassOf(env, decl)) {
687 688 /*
688 689 * If a superclass of this exception is already on
689 690 * the list to catch, then ignore and continue;
690 691 */
691 692 continue nextException;
692 693 } else if (def.subClassOf(env, decl)) {
693 694 /*
694 695 * If a subclass of this exception is on the list
695 696 * to catch, then remove it.
696 697 */
697 698 uniqueList.removeElementAt(j);
698 699 } else {
699 700 j++; // else continue comparing
700 701 }
701 702 }
702 703 /* This exception is unique: add it to the list to catch. */
703 704 uniqueList.addElement(decl.getClassDefinition(env));
704 705 } catch (ClassNotFound e) {
705 706 env.error(0, "class.not.found", e.name, decl.getName());
706 707 /*
707 708 * REMIND: We do not exit from this exceptional condition,
708 709 * generating questionable code and likely letting the
709 710 * compiler report a resulting error later.
710 711 */
711 712 }
712 713 }
713 714 return uniqueList;
714 715 }
715 716
716 717 /**
717 718 * Write the skeleton for the remote class to a stream.
718 719 */
719 720 private void writeSkeleton(IndentingWriter p) throws IOException {
720 721 if (version == STUB_VERSION_1_2) {
721 722 throw new Error("should not generate skeleton for version");
722 723 }
723 724
724 725 /*
725 726 * Write boiler plate comment.
726 727 */
727 728 p.pln("// Skeleton class generated by rmic, do not edit.");
728 729 p.pln("// Contents subject to change without notice.");
729 730 p.pln();
730 731
731 732 /*
732 733 * If remote implementation class was in a particular package,
733 734 * declare the skeleton class to be in the same package.
734 735 */
735 736 if (remoteClassName.isQualified()) {
736 737 p.pln("package " + remoteClassName.getQualifier() + ";");
737 738 p.pln();
738 739 }
739 740
740 741 /*
741 742 * Declare the skeleton class.
742 743 */
743 744 p.plnI("public final class " +
744 745 Names.mangleClass(skeletonClassName.getName()));
745 746 p.pln("implements " + idSkeleton);
746 747 p.pOlnI("{");
747 748
748 749 writeOperationsArray(p);
749 750 p.pln();
750 751
751 752 writeInterfaceHash(p);
752 753 p.pln();
753 754
754 755 /*
755 756 * Define the getOperations() method.
756 757 */
757 758 p.plnI("public " + idOperation + "[] getOperations() {");
758 759 p.pln("return (" + idOperation + "[]) operations.clone();");
759 760 p.pOln("}");
760 761 p.pln();
761 762
762 763 /*
763 764 * Define the dispatch() method.
764 765 */
765 766 p.plnI("public void dispatch(" + idRemote + " obj, " +
766 767 idRemoteCall + " call, int opnum, long hash)");
767 768 p.pln("throws java.lang.Exception");
768 769 p.pOlnI("{");
769 770
770 771 if (version == STUB_VERSION_FAT) {
771 772 p.plnI("if (opnum < 0) {");
772 773 if (remoteMethods.length > 0) {
773 774 for (int opnum = 0; opnum < remoteMethods.length; opnum++) {
774 775 if (opnum > 0)
775 776 p.pO("} else ");
776 777 p.plnI("if (hash == " +
777 778 remoteMethods[opnum].getMethodHash() + "L) {");
778 779 p.pln("opnum = " + opnum + ";");
779 780 }
780 781 p.pOlnI("} else {");
781 782 }
782 783 /*
783 784 * Skeleton throws UnmarshalException if it does not recognize
784 785 * the method hash; this is what UnicastServerRef.dispatch()
785 786 * would do.
786 787 */
787 788 p.pln("throw new " +
788 789 idUnmarshalException + "(\"invalid method hash\");");
789 790 if (remoteMethods.length > 0) {
790 791 p.pOln("}");
791 792 }
792 793 /*
793 794 * Ignore the validation of the interface hash if the
794 795 * operation number was negative, since it is really a
795 796 * method hash instead.
796 797 */
797 798 p.pOlnI("} else {");
798 799 }
799 800
800 801 p.plnI("if (hash != interfaceHash)");
801 802 p.pln("throw new " +
802 803 idSkeletonMismatchException + "(\"interface hash mismatch\");");
803 804 p.pO();
804 805
805 806 if (version == STUB_VERSION_FAT) {
806 807 p.pOln("}"); // end if/else (opnum < 0) block
807 808 }
808 809 p.pln();
809 810
810 811 /*
811 812 * Cast remote object instance to our specific implementation class.
812 813 */
813 814 p.pln(remoteClassName + " server = (" + remoteClassName + ") obj;");
814 815
815 816 /*
816 817 * Process call according to the operation number.
817 818 */
818 819 p.plnI("switch (opnum) {");
819 820 for (int opnum = 0; opnum < remoteMethods.length; opnum++) {
820 821 writeSkeletonDispatchCase(p, opnum);
821 822 }
822 823 p.pOlnI("default:");
823 824 /*
824 825 * Skeleton throws UnmarshalException if it does not recognize
825 826 * the operation number; this is consistent with the case of an
826 827 * unrecognized method hash.
827 828 */
828 829 p.pln("throw new " + idUnmarshalException +
829 830 "(\"invalid method number\");");
830 831 p.pOln("}"); // end switch statement
831 832
832 833 p.pOln("}"); // end dispatch() method
833 834
834 835 p.pOln("}"); // end skeleton class
835 836 }
836 837
837 838 /**
838 839 * Write the case block for the skeleton's dispatch method for
839 840 * the remote method with the given "opnum".
840 841 */
841 842 private void writeSkeletonDispatchCase(IndentingWriter p, int opnum)
842 843 throws IOException
843 844 {
844 845 RemoteClass.Method method = remoteMethods[opnum];
845 846 Identifier methodName = method.getName();
846 847 Type methodType = method.getType();
847 848 Type paramTypes[] = methodType.getArgumentTypes();
848 849 String paramNames[] = nameParameters(paramTypes);
849 850 Type returnType = methodType.getReturnType();
850 851
851 852 p.pOlnI("case " + opnum + ": // " +
852 853 methodType.typeString(methodName.toString(), true, false));
853 854 /*
854 855 * Use nested block statement inside case to provide an independent
855 856 * namespace for local variables used to unmarshal parameters for
856 857 * this remote method.
857 858 */
858 859 p.pOlnI("{");
859 860
860 861 if (paramTypes.length > 0) {
861 862 /*
862 863 * Declare local variables to hold arguments.
863 864 */
864 865 for (int i = 0; i < paramTypes.length; i++) {
865 866 p.pln(paramTypes[i] + " " + paramNames[i] + ";");
866 867 }
867 868
868 869 /*
869 870 * Unmarshal arguments from call stream.
870 871 */
871 872 p.plnI("try {");
872 873 p.pln("java.io.ObjectInput in = call.getInputStream();");
873 874 boolean objectsRead = writeUnmarshalArguments(p, "in",
874 875 paramTypes, paramNames);
875 876 p.pOlnI("} catch (java.io.IOException e) {");
876 877 p.pln("throw new " + idUnmarshalException +
877 878 "(\"error unmarshalling arguments\", e);");
878 879 /*
879 880 * If any only if readObject has been invoked, we must catch
880 881 * ClassNotFoundException as well as IOException.
881 882 */
882 883 if (objectsRead) {
883 884 p.pOlnI("} catch (java.lang.ClassNotFoundException e) {");
884 885 p.pln("throw new " + idUnmarshalException +
885 886 "(\"error unmarshalling arguments\", e);");
886 887 }
887 888 p.pOlnI("} finally {");
888 889 p.pln("call.releaseInputStream();");
889 890 p.pOln("}");
890 891 } else {
891 892 p.pln("call.releaseInputStream();");
892 893 }
893 894
894 895 if (!returnType.isType(TC_VOID)) {
895 896 /*
896 897 * Declare variable to hold return type, if not void.
897 898 */
898 899 p.p(returnType + " $result = "); // REMIND: why $?
899 900 }
900 901
901 902 /*
902 903 * Invoke the method on the server object.
903 904 */
904 905 p.p("server." + methodName + "(");
905 906 for (int i = 0; i < paramNames.length; i++) {
906 907 if (i > 0)
907 908 p.p(", ");
908 909 p.p(paramNames[i]);
909 910 }
910 911 p.pln(");");
911 912
912 913 /*
913 914 * Always invoke getResultStream(true) on the call object to send
914 915 * the indication of a successful invocation to the caller. If
915 916 * the return type is not void, keep the result stream and marshal
916 917 * the return value.
917 918 */
918 919 p.plnI("try {");
919 920 if (!returnType.isType(TC_VOID)) {
920 921 p.p("java.io.ObjectOutput out = ");
921 922 }
922 923 p.pln("call.getResultStream(true);");
923 924 if (!returnType.isType(TC_VOID)) {
924 925 writeMarshalArgument(p, "out", returnType, "$result");
925 926 p.pln(";");
926 927 }
927 928 p.pOlnI("} catch (java.io.IOException e) {");
928 929 p.pln("throw new " +
929 930 idMarshalException + "(\"error marshalling return\", e);");
930 931 p.pOln("}");
931 932
932 933 p.pln("break;"); // break from switch statement
933 934
934 935 p.pOlnI("}"); // end nested block statement
935 936 p.pln();
936 937 }
937 938
938 939 /**
939 940 * Write declaration and initializer for "operations" static array.
940 941 */
941 942 private void writeOperationsArray(IndentingWriter p)
942 943 throws IOException
943 944 {
944 945 p.plnI("private static final " + idOperation + "[] operations = {");
945 946 for (int i = 0; i < remoteMethods.length; i++) {
946 947 if (i > 0)
947 948 p.pln(",");
948 949 p.p("new " + idOperation + "(\"" +
949 950 remoteMethods[i].getOperationString() + "\")");
950 951 }
951 952 p.pln();
952 953 p.pOln("};");
953 954 }
954 955
955 956 /**
956 957 * Write declaration and initializer for "interfaceHash" static field.
957 958 */
958 959 private void writeInterfaceHash(IndentingWriter p)
959 960 throws IOException
960 961 {
961 962 p.pln("private static final long interfaceHash = " +
962 963 remoteClass.getInterfaceHash() + "L;");
963 964 }
964 965
965 966 /**
966 967 * Write declaration for java.lang.reflect.Method static fields
967 968 * corresponding to each remote method in a stub.
968 969 */
969 970 private void writeMethodFieldDeclarations(IndentingWriter p)
970 971 throws IOException
971 972 {
972 973 for (int i = 0; i < methodFieldNames.length; i++) {
973 974 p.pln("private static java.lang.reflect.Method " +
974 975 methodFieldNames[i] + ";");
975 976 }
976 977 }
977 978
978 979 /**
979 980 * Write code to initialize the static fields for each method
980 981 * using the Java Reflection API.
981 982 */
982 983 private void writeMethodFieldInitializers(IndentingWriter p)
983 984 throws IOException
984 985 {
985 986 for (int i = 0; i < methodFieldNames.length; i++) {
986 987 p.p(methodFieldNames[i] + " = ");
987 988 /*
988 989 * Here we look up the Method object in the arbitrary interface
989 990 * that we find in the RemoteClass.Method object.
990 991 * REMIND: Is this arbitrary choice OK?
991 992 * REMIND: Should this access be part of RemoteClass.Method's
992 993 * abstraction?
993 994 */
994 995 RemoteClass.Method method = remoteMethods[i];
995 996 MemberDefinition def = method.getMemberDefinition();
996 997 Identifier methodName = method.getName();
997 998 Type methodType = method.getType();
998 999 Type paramTypes[] = methodType.getArgumentTypes();
999 1000
1000 1001 p.p(def.getClassDefinition().getName() + ".class.getMethod(\"" +
1001 1002 methodName + "\", new java.lang.Class[] {");
1002 1003 for (int j = 0; j < paramTypes.length; j++) {
1003 1004 if (j > 0)
1004 1005 p.p(", ");
1005 1006 p.p(paramTypes[j] + ".class");
1006 1007 }
1007 1008 p.pln("});");
1008 1009 }
1009 1010 }
1010 1011
1011 1012
1012 1013 /*
1013 1014 * Following are a series of static utility methods useful during
1014 1015 * the code generation process:
1015 1016 */
1016 1017
1017 1018 /**
1018 1019 * Generate an array of names for fields that correspond to the given
1019 1020 * array of remote methods. Each name in the returned array is
1020 1021 * guaranteed to be unique.
1021 1022 *
1022 1023 * The name of a method is included in its corresponding field name
1023 1024 * to enhance readability of the generated code.
1024 1025 */
1025 1026 private static String[] nameMethodFields(RemoteClass.Method[] methods) {
1026 1027 String[] names = new String[methods.length];
1027 1028 for (int i = 0; i < names.length; i++) {
1028 1029 names[i] = "$method_" + methods[i].getName() + "_" + i;
1029 1030 }
1030 1031 return names;
1031 1032 }
1032 1033
1033 1034 /**
1034 1035 * Generate an array of names for parameters corresponding to the
1035 1036 * given array of types for the parameters. Each name in the returned
1036 1037 * array is guaranteed to be unique.
1037 1038 *
1038 1039 * A representation of the type of a parameter is included in its
1039 1040 * corresponding field name to enhance the readability of the generated
1040 1041 * code.
1041 1042 */
1042 1043 private static String[] nameParameters(Type[] types) {
1043 1044 String[] names = new String[types.length];
1044 1045 for (int i = 0; i < names.length; i++) {
1045 1046 names[i] = "$param_" +
1046 1047 generateNameFromType(types[i]) + "_" + (i + 1);
1047 1048 }
1048 1049 return names;
1049 1050 }
1050 1051
1051 1052 /**
1052 1053 * Generate a readable string representing the given type suitable
1053 1054 * for embedding within a Java identifier.
1054 1055 */
1055 1056 private static String generateNameFromType(Type type) {
1056 1057 int typeCode = type.getTypeCode();
1057 1058 switch (typeCode) {
1058 1059 case TC_BOOLEAN:
1059 1060 case TC_BYTE:
1060 1061 case TC_CHAR:
1061 1062 case TC_SHORT:
1062 1063 case TC_INT:
1063 1064 case TC_LONG:
1064 1065 case TC_FLOAT:
1065 1066 case TC_DOUBLE:
1066 1067 return type.toString();
1067 1068 case TC_ARRAY:
1068 1069 return "arrayOf_" + generateNameFromType(type.getElementType());
1069 1070 case TC_CLASS:
1070 1071 return Names.mangleClass(type.getClassName().getName()).toString();
1071 1072 default:
1072 1073 throw new Error("unexpected type code: " + typeCode);
1073 1074 }
1074 1075 }
1075 1076
1076 1077 /**
1077 1078 * Write a snippet of Java code to marshal a value named "name" of
1078 1079 * type "type" to the java.io.ObjectOutput stream named "stream".
1079 1080 *
1080 1081 * Primitive types are marshalled with their corresponding methods
1081 1082 * in the java.io.DataOutput interface, and objects (including arrays)
1082 1083 * are marshalled using the writeObject method.
1083 1084 */
1084 1085 private static void writeMarshalArgument(IndentingWriter p,
1085 1086 String streamName,
1086 1087 Type type, String name)
1087 1088 throws IOException
1088 1089 {
1089 1090 int typeCode = type.getTypeCode();
1090 1091 switch (typeCode) {
1091 1092 case TC_BOOLEAN:
1092 1093 p.p(streamName + ".writeBoolean(" + name + ")");
1093 1094 break;
1094 1095 case TC_BYTE:
1095 1096 p.p(streamName + ".writeByte(" + name + ")");
1096 1097 break;
1097 1098 case TC_CHAR:
1098 1099 p.p(streamName + ".writeChar(" + name + ")");
1099 1100 break;
1100 1101 case TC_SHORT:
1101 1102 p.p(streamName + ".writeShort(" + name + ")");
1102 1103 break;
1103 1104 case TC_INT:
1104 1105 p.p(streamName + ".writeInt(" + name + ")");
1105 1106 break;
1106 1107 case TC_LONG:
1107 1108 p.p(streamName + ".writeLong(" + name + ")");
1108 1109 break;
1109 1110 case TC_FLOAT:
1110 1111 p.p(streamName + ".writeFloat(" + name + ")");
1111 1112 break;
1112 1113 case TC_DOUBLE:
1113 1114 p.p(streamName + ".writeDouble(" + name + ")");
1114 1115 break;
1115 1116 case TC_ARRAY:
1116 1117 case TC_CLASS:
1117 1118 p.p(streamName + ".writeObject(" + name + ")");
1118 1119 break;
1119 1120 default:
1120 1121 throw new Error("unexpected type code: " + typeCode);
1121 1122 }
1122 1123 }
1123 1124
1124 1125 /**
1125 1126 * Write Java statements to marshal a series of values in order as
1126 1127 * named in the "names" array, with types as specified in the "types"
1127 1128 * array", to the java.io.ObjectOutput stream named "stream".
1128 1129 */
1129 1130 private static void writeMarshalArguments(IndentingWriter p,
1130 1131 String streamName,
1131 1132 Type[] types, String[] names)
1132 1133 throws IOException
1133 1134 {
1134 1135 if (types.length != names.length) {
1135 1136 throw new Error("paramter type and name arrays different sizes");
1136 1137 }
1137 1138
1138 1139 for (int i = 0; i < types.length; i++) {
1139 1140 writeMarshalArgument(p, streamName, types[i], names[i]);
1140 1141 p.pln(";");
1141 1142 }
1142 1143 }
1143 1144
1144 1145 /**
1145 1146 * Write a snippet of Java code to unmarshal a value of type "type"
1146 1147 * from the java.io.ObjectInput stream named "stream" into a variable
1147 1148 * named "name" (if "name" is null, the value in unmarshalled and
1148 1149 * discarded).
1149 1150 *
1150 1151 * Primitive types are unmarshalled with their corresponding methods
1151 1152 * in the java.io.DataInput interface, and objects (including arrays)
1152 1153 * are unmarshalled using the readObject method.
1153 1154 */
1154 1155 private static boolean writeUnmarshalArgument(IndentingWriter p,
1155 1156 String streamName,
1156 1157 Type type, String name)
1157 1158 throws IOException
1158 1159 {
1159 1160 boolean readObject = false;
1160 1161
1161 1162 if (name != null) {
1162 1163 p.p(name + " = ");
1163 1164 }
1164 1165
1165 1166 int typeCode = type.getTypeCode();
1166 1167 switch (type.getTypeCode()) {
1167 1168 case TC_BOOLEAN:
1168 1169 p.p(streamName + ".readBoolean()");
1169 1170 break;
1170 1171 case TC_BYTE:
1171 1172 p.p(streamName + ".readByte()");
1172 1173 break;
1173 1174 case TC_CHAR:
1174 1175 p.p(streamName + ".readChar()");
1175 1176 break;
1176 1177 case TC_SHORT:
1177 1178 p.p(streamName + ".readShort()");
1178 1179 break;
1179 1180 case TC_INT:
1180 1181 p.p(streamName + ".readInt()");
1181 1182 break;
1182 1183 case TC_LONG:
1183 1184 p.p(streamName + ".readLong()");
1184 1185 break;
1185 1186 case TC_FLOAT:
1186 1187 p.p(streamName + ".readFloat()");
1187 1188 break;
1188 1189 case TC_DOUBLE:
1189 1190 p.p(streamName + ".readDouble()");
1190 1191 break;
1191 1192 case TC_ARRAY:
1192 1193 case TC_CLASS:
1193 1194 p.p("(" + type + ") " + streamName + ".readObject()");
1194 1195 readObject = true;
1195 1196 break;
1196 1197 default:
1197 1198 throw new Error("unexpected type code: " + typeCode);
1198 1199 }
1199 1200 return readObject;
1200 1201 }
1201 1202
1202 1203 /**
1203 1204 * Write Java statements to unmarshal a series of values in order of
1204 1205 * types as in the "types" array from the java.io.ObjectInput stream
1205 1206 * named "stream" into variables as named in "names" (for any element
1206 1207 * of "names" that is null, the corresponding value is unmarshalled
1207 1208 * and discarded).
1208 1209 */
1209 1210 private static boolean writeUnmarshalArguments(IndentingWriter p,
1210 1211 String streamName,
1211 1212 Type[] types,
1212 1213 String[] names)
1213 1214 throws IOException
1214 1215 {
1215 1216 if (types.length != names.length) {
1216 1217 throw new Error("paramter type and name arrays different sizes");
1217 1218 }
1218 1219
1219 1220 boolean readObject = false;
1220 1221 for (int i = 0; i < types.length; i++) {
1221 1222 if (writeUnmarshalArgument(p, streamName, types[i], names[i])) {
1222 1223 readObject = true;
1223 1224 }
1224 1225 p.pln(";");
1225 1226 }
1226 1227 return readObject;
1227 1228 }
1228 1229
1229 1230 /**
1230 1231 * Return a snippet of Java code to wrap a value named "name" of
1231 1232 * type "type" into an object as appropriate for use by the
1232 1233 * Java Reflection API.
1233 1234 *
1234 1235 * For primitive types, an appropriate wrapper class instantiated
1235 1236 * with the primitive value. For object types (including arrays),
1236 1237 * no wrapping is necessary, so the value is named directly.
1237 1238 */
1238 1239 private static String wrapArgumentCode(Type type, String name) {
1239 1240 int typeCode = type.getTypeCode();
1240 1241 switch (typeCode) {
1241 1242 case TC_BOOLEAN:
1242 1243 return ("(" + name +
1243 1244 " ? java.lang.Boolean.TRUE : java.lang.Boolean.FALSE)");
1244 1245 case TC_BYTE:
1245 1246 return "new java.lang.Byte(" + name + ")";
1246 1247 case TC_CHAR:
1247 1248 return "new java.lang.Character(" + name + ")";
1248 1249 case TC_SHORT:
1249 1250 return "new java.lang.Short(" + name + ")";
1250 1251 case TC_INT:
1251 1252 return "new java.lang.Integer(" + name + ")";
1252 1253 case TC_LONG:
1253 1254 return "new java.lang.Long(" + name + ")";
1254 1255 case TC_FLOAT:
1255 1256 return "new java.lang.Float(" + name + ")";
1256 1257 case TC_DOUBLE:
1257 1258 return "new java.lang.Double(" + name + ")";
1258 1259 case TC_ARRAY:
1259 1260 case TC_CLASS:
1260 1261 return name;
1261 1262 default:
1262 1263 throw new Error("unexpected type code: " + typeCode);
1263 1264 }
1264 1265 }
1265 1266
1266 1267 /**
1267 1268 * Return a snippet of Java code to unwrap a value named "name" into
1268 1269 * a value of type "type", as appropriate for the Java Reflection API.
1269 1270 *
1270 1271 * For primitive types, the value is assumed to be of the corresponding
1271 1272 * wrapper type, and a method is called on the wrapper type to retrieve
1272 1273 * the primitive value. For object types (include arrays), no
1273 1274 * unwrapping is necessary; the value is simply cast to the expected
1274 1275 * real object type.
1275 1276 */
1276 1277 private static String unwrapArgumentCode(Type type, String name) {
1277 1278 int typeCode = type.getTypeCode();
1278 1279 switch (typeCode) {
1279 1280 case TC_BOOLEAN:
1280 1281 return "((java.lang.Boolean) " + name + ").booleanValue()";
1281 1282 case TC_BYTE:
1282 1283 return "((java.lang.Byte) " + name + ").byteValue()";
1283 1284 case TC_CHAR:
1284 1285 return "((java.lang.Character) " + name + ").charValue()";
1285 1286 case TC_SHORT:
1286 1287 return "((java.lang.Short) " + name + ").shortValue()";
1287 1288 case TC_INT:
1288 1289 return "((java.lang.Integer) " + name + ").intValue()";
1289 1290 case TC_LONG:
1290 1291 return "((java.lang.Long) " + name + ").longValue()";
1291 1292 case TC_FLOAT:
1292 1293 return "((java.lang.Float) " + name + ").floatValue()";
1293 1294 case TC_DOUBLE:
1294 1295 return "((java.lang.Double) " + name + ").doubleValue()";
1295 1296 case TC_ARRAY:
1296 1297 case TC_CLASS:
1297 1298 return "((" + type + ") " + name + ")";
1298 1299 default:
1299 1300 throw new Error("unexpected type code: " + typeCode);
1300 1301 }
1301 1302 }
1302 1303 }
↓ open down ↓ |
607 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX