ObjectReader.java revision 9883:903a2e023ffb
1/* 2 * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. 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 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25package sun.jvm.hotspot.utilities; 26 27import java.lang.reflect.Modifier; 28import java.util.*; 29import sun.jvm.hotspot.debugger.*; 30import sun.jvm.hotspot.oops.*; 31import sun.jvm.hotspot.runtime.*; 32import sun.jvm.hotspot.utilities.*; 33 34/** 35 * ObjectReader can "deserialize" objects from debuggee. 36 * 37 * Class Loading: 38 * 39 * ObjectReader loads classes using the given class loader. If no 40 * class loader is supplied, it uses a ProcImageClassLoader, which 41 * loads classes from debuggee core or process. 42 43 * Object creation: 44 * 45 * This class uses no-arg constructor to construct objects. But if 46 * there is no no-arg constructor in a given class, then it tries to 47 * use other constructors with 'default' values - null for object 48 * types, 0, 0.0, false etc. for primitives. If this process fails to 49 * construct an instance (because of null checking by constructor or 0 50 * being invalid for an int arg etc.), then null is returned. While 51 * constructing complete object graph 'null' is inserted silently on 52 * failure and the deserialization continues to construct best-effort 53 * object graph. 54 * 55 * Debug messages: 56 * 57 * The flag sun.jvm.hotspot.utilities.ObjectReader.DEBUG may be set to 58 * non-null to get debug error messages and stack traces. 59 * 60 * JDK version: 61 * 62 * JDK classes are loaded by bootstrap class loader and not by the 63 * supplied class loader or ProcImageClassLoader. This may create 64 * problems if a JDK class evolves. i.e., if SA runs a JDK version 65 * different from that of the debuggee, there is a possibility of 66 * schema change. It is recommended that the matching JDK version be 67 * used to run SA for proper object deserialization. 68 * 69 */ 70 71public class ObjectReader { 72 73 private static final boolean DEBUG; 74 static { 75 DEBUG = System.getProperty("sun.jvm.hotspot.utilities.ObjectReader.DEBUG") != null; 76 } 77 78 public ObjectReader(ClassLoader cl) { 79 this.cl = cl; 80 this.oopToObjMap = new HashMap(); 81 this.fieldMap = new HashMap(); 82 } 83 84 public ObjectReader() { 85 this(new ProcImageClassLoader()); 86 } 87 88 static void debugPrintln(String msg) { 89 if (DEBUG) { 90 System.err.println("DEBUG>" + msg); 91 } 92 } 93 94 static void debugPrintStackTrace(Exception exp) { 95 if (DEBUG) { 96 StackTraceElement[] els = exp.getStackTrace(); 97 for (int i = 0; i < els.length; i++) { 98 System.err.println("DEBUG>" + els[i].toString()); 99 } 100 } 101 } 102 103 public Object readObject(Oop oop) throws ClassNotFoundException { 104 if (oop instanceof Instance) { 105 return readInstance((Instance) oop); 106 } else if (oop instanceof TypeArray){ 107 return readPrimitiveArray((TypeArray)oop); 108 } else if (oop instanceof ObjArray){ 109 return readObjectArray((ObjArray)oop); 110 } else { 111 return null; 112 } 113 } 114 115 protected final Object getDefaultPrimitiveValue(Class clz) { 116 if (clz == Boolean.TYPE) { 117 return Boolean.FALSE; 118 } else if (clz == Character.TYPE) { 119 return new Character(' '); 120 } else if (clz == Byte.TYPE) { 121 return new Byte((byte) 0); 122 } else if (clz == Short.TYPE) { 123 return new Short((short) 0); 124 } else if (clz == Integer.TYPE) { 125 return new Integer(0); 126 } else if (clz == Long.TYPE) { 127 return new Long(0L); 128 } else if (clz == Float.TYPE) { 129 return new Float(0.0f); 130 } else if (clz == Double.TYPE) { 131 return new Double(0.0); 132 } else { 133 throw new RuntimeException("should not reach here!"); 134 } 135 } 136 137 protected Symbol javaLangString; 138 protected Symbol javaUtilHashtableEntry; 139 protected Symbol javaUtilHashtable; 140 protected Symbol javaUtilProperties; 141 142 protected Symbol getVMSymbol(String name) { 143 return VM.getVM().getSymbolTable().probe(name); 144 } 145 146 protected Symbol javaLangString() { 147 if (javaLangString == null) { 148 javaLangString = getVMSymbol("java/lang/String"); 149 } 150 return javaLangString; 151 } 152 153 protected Symbol javaUtilHashtableEntry() { 154 if (javaUtilHashtableEntry == null) { 155 javaUtilHashtableEntry = getVMSymbol("java/util/Hashtable$Entry"); 156 } 157 return javaUtilHashtableEntry; 158 } 159 160 protected Symbol javaUtilHashtable() { 161 if (javaUtilHashtable == null) { 162 javaUtilHashtable = getVMSymbol("java/util/Hashtable"); 163 } 164 return javaUtilHashtable; 165 } 166 167 protected Symbol javaUtilProperties() { 168 if (javaUtilProperties == null) { 169 javaUtilProperties = getVMSymbol("java/util/Properties"); 170 } 171 return javaUtilProperties; 172 } 173 174 private void setHashtableEntry(java.util.Hashtable p, Oop oop) { 175 InstanceKlass ik = (InstanceKlass)oop.getKlass(); 176 OopField keyField = (OopField)ik.findField("key", "Ljava/lang/Object;"); 177 OopField valueField = (OopField)ik.findField("value", "Ljava/lang/Object;"); 178 OopField nextField = (OopField)ik.findField("next", "Ljava/util/Hashtable$Entry;"); 179 if (DEBUG) { 180 if (Assert.ASSERTS_ENABLED) { 181 Assert.that(ik.getName().equals(javaUtilHashtableEntry()), "Not a Hashtable$Entry?"); 182 Assert.that(keyField != null && valueField != null && nextField != null, "Invalid fields!"); 183 } 184 } 185 186 Object key = null; 187 Object value = null; 188 Oop next = null; 189 try { 190 key = readObject(keyField.getValue(oop)); 191 value = readObject(valueField.getValue(oop)); 192 next = (Oop)nextField.getValue(oop); 193 // For Properties, should use setProperty(k, v). Since it only runs in SA 194 // using put(k, v) should be OK. 195 p.put(key, value); 196 if (next != null) { 197 setHashtableEntry(p, next); 198 } 199 } catch (ClassNotFoundException ce) { 200 if( DEBUG) { 201 debugPrintln("Class not found " + ce); 202 debugPrintStackTrace(ce); 203 } 204 } 205 } 206 207 protected Object getHashtable(Instance oop, boolean isProperties) { 208 InstanceKlass k = (InstanceKlass)oop.getKlass(); 209 OopField tableField = (OopField)k.findField("table", "[Ljava/util/Hashtable$Entry;"); 210 if (tableField == null) { 211 debugPrintln("Could not find field of [Ljava/util/Hashtable$Entry;"); 212 return null; 213 } 214 java.util.Hashtable table = (isProperties) ? new java.util.Properties() 215 : new java.util.Hashtable(); 216 ObjArray kvs = (ObjArray)tableField.getValue(oop); 217 long size = kvs.getLength(); 218 debugPrintln("Hashtable$Entry Size = " + size); 219 for (long i=0; i<size; i++) { 220 Oop entry = kvs.getObjAt(i); 221 if (entry != null && entry.isInstance()) { 222 setHashtableEntry(table, entry); 223 } 224 } 225 return table; 226 } 227 228 public Object readInstance(Instance oop) throws ClassNotFoundException { 229 Object result = getFromObjTable(oop); 230 if (result == null) { 231 InstanceKlass kls = (InstanceKlass) oop.getKlass(); 232 // Handle java.lang.String instances differently. As part of JSR-133, fields of immutable 233 // classes have been made final. The algorithm below will not be able to read Strings from 234 // debuggee (can't use reflection to set final fields). But, need to read Strings is very 235 // important. 236 // Same for Hashtable, key and hash are final, could not be set in the algorithm too. 237 // FIXME: need a framework to handle many other special cases. 238 if (kls.getName().equals(javaLangString())) { 239 return OopUtilities.stringOopToString(oop); 240 } 241 242 if (kls.getName().equals(javaUtilHashtable())) { 243 return getHashtable(oop, false); 244 } 245 246 if (kls.getName().equals(javaUtilProperties())) { 247 return getHashtable(oop, true); 248 } 249 250 Class clz = readClass(kls); 251 try { 252 result = clz.newInstance(); 253 } catch (Exception ex) { 254 // no-arg constructor failed to create object. Let us try 255 // to call constructors one-by-one with default arguments 256 // (null for objects, 0/0.0 etc. for primitives) till we 257 // succeed or fail on all constructors. 258 259 java.lang.reflect.Constructor[] ctrs = clz.getDeclaredConstructors(); 260 for (int n = 0; n < ctrs.length; n++) { 261 java.lang.reflect.Constructor c = ctrs[n]; 262 Class[] paramTypes = c.getParameterTypes(); 263 Object[] params = new Object[paramTypes.length]; 264 for (int i = 0; i < params.length; i++) { 265 if (paramTypes[i].isPrimitive()) { 266 params[i] = getDefaultPrimitiveValue(paramTypes[i]); 267 } 268 } 269 try { 270 c.setAccessible(true); 271 result = c.newInstance(params); 272 break; 273 } catch (Exception exp) { 274 if (DEBUG) { 275 debugPrintln("Can't create object using " + c); 276 debugPrintStackTrace(exp); 277 } 278 } 279 } 280 } 281 282 if (result != null) { 283 putIntoObjTable(oop, result); 284 oop.iterate(new FieldSetter(result), false); 285 } 286 } 287 return result; 288 } 289 290 public Object readPrimitiveArray(final TypeArray array) { 291 292 Object result = getFromObjTable(array); 293 if (result == null) { 294 int length = (int) array.getLength(); 295 TypeArrayKlass klass = (TypeArrayKlass) array.getKlass(); 296 int type = (int) klass.getElementType(); 297 switch (type) { 298 case TypeArrayKlass.T_BOOLEAN: { 299 final boolean[] arrayObj = new boolean[length]; 300 array.iterate(new DefaultOopVisitor() { 301 public void doBoolean(BooleanField field, boolean isVMField) { 302 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID(); 303 arrayObj[ifd.getIndex()] = field.getValue(array); 304 } 305 }, false); 306 result = arrayObj; 307 } 308 break; 309 310 case TypeArrayKlass.T_CHAR: { 311 final char[] arrayObj = new char[length]; 312 array.iterate(new DefaultOopVisitor() { 313 public void doChar(CharField field, boolean isVMField) { 314 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID(); 315 arrayObj[ifd.getIndex()] = field.getValue(array); 316 } 317 }, false); 318 result = arrayObj; 319 } 320 break; 321 322 case TypeArrayKlass.T_FLOAT: { 323 final float[] arrayObj = new float[length]; 324 array.iterate(new DefaultOopVisitor() { 325 public void doFloat(FloatField field, boolean isVMField) { 326 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID(); 327 arrayObj[ifd.getIndex()] = field.getValue(array); 328 } 329 }, false); 330 result = arrayObj; 331 } 332 break; 333 334 case TypeArrayKlass.T_DOUBLE: { 335 final double[] arrayObj = new double[length]; 336 array.iterate(new DefaultOopVisitor() { 337 public void doDouble(DoubleField field, boolean isVMField) { 338 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID(); 339 arrayObj[ifd.getIndex()] = field.getValue(array); 340 } 341 }, false); 342 result = arrayObj; 343 } 344 break; 345 346 case TypeArrayKlass.T_BYTE: { 347 final byte[] arrayObj = new byte[length]; 348 array.iterate(new DefaultOopVisitor() { 349 public void doByte(ByteField field, boolean isVMField) { 350 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID(); 351 arrayObj[ifd.getIndex()] = field.getValue(array); 352 } 353 }, false); 354 result = arrayObj; 355 } 356 break; 357 358 case TypeArrayKlass.T_SHORT: { 359 final short[] arrayObj = new short[length]; 360 array.iterate(new DefaultOopVisitor() { 361 public void doShort(ShortField field, boolean isVMField) { 362 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID(); 363 arrayObj[ifd.getIndex()] = field.getValue(array); 364 } 365 }, false); 366 result = arrayObj; 367 } 368 break; 369 370 case TypeArrayKlass.T_INT: { 371 final int[] arrayObj = new int[length]; 372 array.iterate(new DefaultOopVisitor() { 373 public void doInt(IntField field, boolean isVMField) { 374 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID(); 375 arrayObj[ifd.getIndex()] = field.getValue(array); 376 } 377 }, false); 378 result = arrayObj; 379 } 380 break; 381 382 case TypeArrayKlass.T_LONG: { 383 final long[] arrayObj = new long[length]; 384 array.iterate(new DefaultOopVisitor() { 385 public void doLong(LongField field, boolean isVMField) { 386 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID(); 387 arrayObj[ifd.getIndex()] = field.getValue(array); 388 } 389 }, false); 390 result = arrayObj; 391 } 392 break; 393 394 default: 395 throw new RuntimeException("should not reach here!"); 396 } 397 398 putIntoObjTable(array, result); 399 } 400 return result; 401 } 402 403 protected final boolean isRobust(OopHandle handle) { 404 return RobustOopDeterminator.oopLooksValid(handle); 405 } 406 407 public Object readObjectArray(final ObjArray array) throws ClassNotFoundException { 408 Object result = getFromObjTable(array); 409 if (result == null) { 410 int length = (int) array.getLength(); 411 ObjArrayKlass klass = (ObjArrayKlass) array.getKlass(); 412 Klass bottomKls = klass.getBottomKlass(); 413 Class bottomCls = null; 414 final int dimension = (int) klass.getDimension(); 415 int[] dimArray = null; 416 if (bottomKls instanceof InstanceKlass) { 417 bottomCls = readClass((InstanceKlass) bottomKls); 418 dimArray = new int[dimension]; 419 } else { // instanceof TypeArrayKlass 420 TypeArrayKlass botKls = (TypeArrayKlass) bottomKls; 421 dimArray = new int[dimension -1]; 422 } 423 // initialize the length 424 dimArray[0] = length; 425 final Object[] arrayObj = (Object[]) java.lang.reflect.Array.newInstance(bottomCls, dimArray); 426 putIntoObjTable(array, arrayObj); 427 result = arrayObj; 428 array.iterate(new DefaultOopVisitor() { 429 public void doOop(OopField field, boolean isVMField) { 430 OopHandle handle = field.getValueAsOopHandle(getObj()); 431 if (! isRobust(handle)) { 432 return; 433 } 434 435 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID(); 436 try { 437 arrayObj[ifd.getIndex()] = readObject(field.getValue(getObj())); 438 } catch (Exception e) { 439 if (DEBUG) { 440 debugPrintln("Array element set failed for " + ifd); 441 debugPrintStackTrace(e); 442 } 443 } 444 } 445 }, false); 446 } 447 return result; 448 } 449 450 protected class FieldSetter extends DefaultOopVisitor { 451 protected Object obj; 452 453 public FieldSetter(Object obj) { 454 this.obj = obj; 455 } 456 457 private void printFieldSetError(java.lang.reflect.Field f, Exception ex) { 458 if (DEBUG) { 459 if (f != null) debugPrintln("Field set failed for " + f); 460 debugPrintStackTrace(ex); 461 } 462 } 463 464 // Callback methods for each field type in an object 465 public void doOop(OopField field, boolean isVMField) { 466 OopHandle handle = field.getValueAsOopHandle(getObj()); 467 if (! isRobust(handle) ) { 468 return; 469 } 470 471 java.lang.reflect.Field f = null; 472 try { 473 f = readField(field); 474 if (Modifier.isFinal(f.getModifiers())) return; 475 f.setAccessible(true); 476 f.set(obj, readObject(field.getValue(getObj()))); 477 } catch (Exception ex) { 478 printFieldSetError(f, ex); 479 } 480 } 481 482 public void doByte(ByteField field, boolean isVMField) { 483 java.lang.reflect.Field f = null; 484 try { 485 f = readField(field); 486 if (Modifier.isFinal(f.getModifiers())) return; 487 f.setAccessible(true); 488 f.setByte(obj, field.getValue(getObj())); 489 } catch (Exception ex) { 490 printFieldSetError(f, ex); 491 } 492 } 493 494 public void doChar(CharField field, boolean isVMField) { 495 java.lang.reflect.Field f = null; 496 try { 497 f = readField(field); 498 if (Modifier.isFinal(f.getModifiers())) return; 499 f.setAccessible(true); 500 f.setChar(obj, field.getValue(getObj())); 501 } catch (Exception ex) { 502 printFieldSetError(f, ex); 503 } 504 } 505 506 public void doBoolean(BooleanField field, boolean isVMField) { 507 java.lang.reflect.Field f = null; 508 try { 509 f = readField(field); 510 if (Modifier.isFinal(f.getModifiers())) return; 511 f.setAccessible(true); 512 f.setBoolean(obj, field.getValue(getObj())); 513 } catch (Exception ex) { 514 printFieldSetError(f, ex); 515 } 516 } 517 518 public void doShort(ShortField field, boolean isVMField) { 519 java.lang.reflect.Field f = null; 520 try { 521 f = readField(field); 522 if (Modifier.isFinal(f.getModifiers())) return; 523 f.setAccessible(true); 524 f.setShort(obj, field.getValue(getObj())); 525 } catch (Exception ex) { 526 printFieldSetError(f, ex); 527 } 528 } 529 530 public void doInt(IntField field, boolean isVMField) { 531 java.lang.reflect.Field f = null; 532 try { 533 f = readField(field); 534 if (Modifier.isFinal(f.getModifiers())) return; 535 f.setAccessible(true); 536 f.setInt(obj, field.getValue(getObj())); 537 } catch (Exception ex) { 538 printFieldSetError(f, ex); 539 } 540 } 541 542 public void doLong(LongField field, boolean isVMField) { 543 java.lang.reflect.Field f = null; 544 try { 545 f = readField(field); 546 if (Modifier.isFinal(f.getModifiers())) return; 547 f.setAccessible(true); 548 f.setLong(obj, field.getValue(getObj())); 549 } catch (Exception ex) { 550 printFieldSetError(f, ex); 551 } 552 } 553 554 public void doFloat(FloatField field, boolean isVMField) { 555 java.lang.reflect.Field f = null; 556 try { 557 f = readField(field); 558 if (Modifier.isFinal(f.getModifiers())) return; 559 f.setAccessible(true); 560 f.setFloat(obj, field.getValue(getObj())); 561 } catch (Exception ex) { 562 printFieldSetError(f, ex); 563 } 564 } 565 566 public void doDouble(DoubleField field, boolean isVMField) { 567 java.lang.reflect.Field f = null; 568 try { 569 f = readField(field); 570 if (Modifier.isFinal(f.getModifiers())) return; 571 f.setAccessible(true); 572 f.setDouble(obj, field.getValue(getObj())); 573 } catch (Exception ex) { 574 printFieldSetError(f, ex); 575 } 576 } 577 578 public void doCInt(CIntField field, boolean isVMField) { 579 throw new RuntimeException("should not reach here!"); 580 } 581 } 582 583 public Class readClass(InstanceKlass kls) throws ClassNotFoundException { 584 Class cls = (Class) getFromObjTable(kls); 585 if (cls == null) { 586 cls = Class.forName(kls.getName().asString().replace('/', '.'), true, cl); 587 putIntoObjTable(kls, cls); 588 } 589 return cls; 590 } 591 592 public Object readMethodOrConstructor(sun.jvm.hotspot.oops.Method m) 593 throws NoSuchMethodException, ClassNotFoundException { 594 String name = m.getName().asString(); 595 if (name.equals("<init>")) { 596 return readConstructor(m); 597 } else { 598 return readMethod(m); 599 } 600 } 601 602 public java.lang.reflect.Method readMethod(sun.jvm.hotspot.oops.Method m) 603 throws NoSuchMethodException, ClassNotFoundException { 604 java.lang.reflect.Method result = (java.lang.reflect.Method) getFromObjTable(m); 605 if (result == null) { 606 Class clz = readClass((InstanceKlass)m.getMethodHolder()); 607 String name = m.getName().asString(); 608 Class[] paramTypes = getParamTypes(m.getSignature()); 609 result = clz.getMethod(name, paramTypes); 610 putIntoObjTable(m, result); 611 } 612 return result; 613 } 614 615 public java.lang.reflect.Constructor readConstructor(sun.jvm.hotspot.oops.Method m) 616 throws NoSuchMethodException, ClassNotFoundException { 617 java.lang.reflect.Constructor result = (java.lang.reflect.Constructor) getFromObjTable(m); 618 if (result == null) { 619 Class clz = readClass((InstanceKlass)m.getMethodHolder()); 620 String name = m.getName().asString(); 621 Class[] paramTypes = getParamTypes(m.getSignature()); 622 result = clz.getDeclaredConstructor(paramTypes); 623 putIntoObjTable(m, result); 624 } 625 return result; 626 } 627 628 public java.lang.reflect.Field readField(sun.jvm.hotspot.oops.Field f) 629 throws NoSuchFieldException, ClassNotFoundException { 630 java.lang.reflect.Field result = (java.lang.reflect.Field) fieldMap.get(f); 631 if (result == null) { 632 FieldIdentifier fieldId = f.getID(); 633 Class clz = readClass((InstanceKlass) f.getFieldHolder()); 634 String name = fieldId.getName(); 635 try { 636 result = clz.getField(name); 637 } catch (NoSuchFieldException nsfe) { 638 result = clz.getDeclaredField(name); 639 } 640 fieldMap.put(f, result); 641 } 642 return result; 643 } 644 645 protected final ClassLoader cl; 646 protected Map oopToObjMap; // Map<Oop, Object> 647 protected Map fieldMap; // Map<sun.jvm.hotspot.oops.Field, java.lang.reflect.Field> 648 649 protected void putIntoObjTable(Oop oop, Object obj) { 650 oopToObjMap.put(oop, obj); 651 } 652 653 protected Object getFromObjTable(Oop oop) { 654 return oopToObjMap.get(oop); 655 } 656 657 protected void putIntoObjTable(Metadata oop, Object obj) { 658 oopToObjMap.put(oop, obj); 659 } 660 661 protected Object getFromObjTable(Metadata oop) { 662 return oopToObjMap.get(oop); 663 } 664 665 protected class SignatureParser extends SignatureIterator { 666 protected Vector tmp = new Vector(); // Vector<Class> 667 668 public SignatureParser(Symbol s) { 669 super(s); 670 } 671 672 public void doBool () { tmp.add(Boolean.TYPE); } 673 public void doChar () { tmp.add(Character.TYPE); } 674 public void doFloat () { tmp.add(Float.TYPE); } 675 public void doDouble() { tmp.add(Double.TYPE); } 676 public void doByte () { tmp.add(Byte.TYPE); } 677 public void doShort () { tmp.add(Short.TYPE); } 678 public void doInt () { tmp.add(Integer.TYPE); } 679 public void doLong () { tmp.add(Long.TYPE); } 680 public void doVoid () { 681 if(isReturnType()) { 682 tmp.add(Void.TYPE); 683 } else { 684 throw new RuntimeException("should not reach here"); 685 } 686 } 687 688 public void doObject(int begin, int end) { 689 tmp.add(getClass(begin, end)); 690 } 691 692 public void doArray (int begin, int end) { 693 int inner = arrayInnerBegin(begin); 694 Class elemCls = null; 695 switch (_signature.getByteAt(inner)) { 696 case 'B': elemCls = Boolean.TYPE; break; 697 case 'C': elemCls = Character.TYPE; break; 698 case 'D': elemCls = Double.TYPE; break; 699 case 'F': elemCls = Float.TYPE; break; 700 case 'I': elemCls = Integer.TYPE; break; 701 case 'J': elemCls = Long.TYPE; break; 702 case 'S': elemCls = Short.TYPE; break; 703 case 'Z': elemCls = Boolean.TYPE; break; 704 case 'L': elemCls = getClass(inner + 1, end); break; 705 default: break; 706 } 707 708 int dimension = inner - begin; 709 // create 0 x 0 ... array and get class from that 710 int[] dimArray = new int[dimension]; 711 tmp.add(java.lang.reflect.Array.newInstance(elemCls, dimArray).getClass()); 712 } 713 714 protected Class getClass(int begin, int end) { 715 String className = getClassName(begin, end); 716 try { 717 return Class.forName(className, true, cl); 718 } catch (Exception e) { 719 if (DEBUG) { 720 debugPrintln("Can't load class " + className); 721 } 722 throw new RuntimeException(e); 723 } 724 } 725 726 protected String getClassName(int begin, int end) { 727 StringBuffer buf = new StringBuffer(); 728 for (int i = begin; i < end; i++) { 729 char c = (char) (_signature.getByteAt(i) & 0xFF); 730 if (c == '/') { 731 buf.append('.'); 732 } else { 733 buf.append(c); 734 } 735 } 736 return buf.toString(); 737 } 738 739 protected int arrayInnerBegin(int begin) { 740 while (_signature.getByteAt(begin) == '[') { 741 ++begin; 742 } 743 return begin; 744 } 745 746 public int getNumParams() { 747 return tmp.size(); 748 } 749 750 public Enumeration getParamTypes() { 751 return tmp.elements(); 752 } 753 } 754 755 protected Class[] getParamTypes(Symbol signature) { 756 SignatureParser sp = new SignatureParser(signature); 757 sp.iterateParameters(); 758 Class result[] = new Class[sp.getNumParams()]; 759 Enumeration e = sp.getParamTypes(); 760 int i = 0; 761 while (e.hasMoreElements()) { 762 result[i] = (Class) e.nextElement(); 763 i++; 764 } 765 return result; 766 } 767} 768