1 25 26 package org.netbeans.modules.classfile; 27 28 import java.io.*; 29 import java.util.*; 30 31 36 public class ClassFile { 37 38 ConstantPool constantPool; 39 int classAccess; 40 CPClassInfo classInfo; 41 CPClassInfo superClassInfo; 42 CPClassInfo[] interfaces; 43 Variable[] variables; 44 Method[] methods; 45 String sourceFileName; 46 InnerClass[] innerClasses; 47 private AttributeMap attributes; 48 private Map<ClassName,Annotation> annotations; 49 short majorVersion; 50 short minorVersion; 51 String typeSignature; 52 EnclosingMethod enclosingMethod; 53 private boolean includeCode = false; 54 55 56 private static final int BUFFER_SIZE = 4096; 57 58 65 public ClassFile(InputStream classData) throws IOException { 66 this(classData, true); 67 } 68 69 74 public ClassFile(String classFileName) throws IOException { 75 this(classFileName, true); 76 } 77 78 86 public ClassFile(File file, boolean includeCode) throws IOException { 87 InputStream is = null; 88 this.includeCode = includeCode; 89 if( file == null || !file.exists() ) 90 throw new FileNotFoundException(file != null ? 91 file.getPath() : "null"); 92 try { 93 is = new BufferedInputStream( new FileInputStream( file ), BUFFER_SIZE); 94 load(is); 95 } catch (InvalidClassFormatException e) { 96 throw new InvalidClassFormatException(file.getPath() + '(' + 97 e.getMessage() + ')'); 98 } finally { 99 if (is != null) 100 is.close(); 101 } 102 } 103 104 114 public ClassFile(InputStream classData, boolean includeCode) throws IOException { 115 if (classData == null) 116 throw new IOException("input stream not specified"); 117 this.includeCode = includeCode; 118 load(classData); 119 } 120 121 129 public ClassFile(String classFileName, boolean includeCode) throws IOException { 130 InputStream in = null; 131 this.includeCode = includeCode; 132 try { 133 if (classFileName == null) 134 throw new IOException("input stream not specified"); 135 in = new BufferedInputStream(new FileInputStream(classFileName), BUFFER_SIZE); 136 load(in); 137 } catch (InvalidClassFormatException e) { 138 throw new InvalidClassFormatException(classFileName + '(' + 139 e.getMessage() + ')'); 140 } finally { 141 if (in != null) 142 in.close(); 143 } 144 } 145 146 147 150 public final ConstantPool getConstantPool() { 151 return constantPool; 152 } 153 154 private void load(InputStream classData) throws IOException { 155 try { 156 DataInputStream in = new DataInputStream(classData); 157 constantPool = loadClassHeader(in); 158 interfaces = getCPClassList(in, constantPool); 159 variables = Variable.loadFields(in, constantPool, this); 160 methods = Method.loadMethods(in, constantPool, this, includeCode); 161 attributes = AttributeMap.load(in, constantPool); 162 } catch (IOException ioe) { 163 throw new InvalidClassFormatException(ioe); 164 } 165 } 166 167 private ConstantPool loadClassHeader(DataInputStream in) throws IOException { 168 int magic = in.readInt(); 169 if (magic != 0xCAFEBABE) { 170 throw new InvalidClassFormatException(); 171 } 172 173 minorVersion = in.readShort(); 174 majorVersion = in.readShort(); 175 int count = in.readUnsignedShort(); 176 ConstantPool pool = new ConstantPool(count, in); 177 classAccess = in.readUnsignedShort(); 178 classInfo = pool.getClass(in.readUnsignedShort()); 179 if (classInfo == null) 180 throw new InvalidClassFormatException(); 181 int index = in.readUnsignedShort(); 182 if (index != 0) superClassInfo = pool.getClass(index); 184 return pool; 185 } 186 187 static CPClassInfo[] getCPClassList(DataInputStream in, ConstantPool pool) 188 throws IOException { 189 int count = in.readUnsignedShort(); 190 CPClassInfo[] classes = new CPClassInfo[count]; 191 for (int i = 0; i < count; i++) { 192 classes[i] = pool.getClass(in.readUnsignedShort()); 193 } 194 return classes; 195 } 196 197 202 public final int getAccess() { 203 return classAccess; 204 } 205 206 209 public final ClassName getName() { 210 return classInfo.getClassName(); 211 } 212 213 217 public final ClassName getSuperClass() { 218 if (superClassInfo == null) 219 return null; 220 return superClassInfo.getClassName(); 221 } 222 223 226 public final Collection<ClassName> getInterfaces() { 227 List<ClassName> l = new ArrayList<ClassName>(); 228 int n = interfaces.length; 229 for (int i = 0; i < n; i++) 230 l.add(interfaces[i].getClassName()); 231 return l; 232 } 233 234 243 public final Variable getVariable(String name) { 244 int n = variables.length; 245 for (int i = 0; i < n; i++) { 246 Variable v = variables[i]; 247 if (v.getName().equals(name)) 248 return v; 249 } 250 return null; 251 } 252 253 257 public final Collection<Variable> getVariables() { 258 return Arrays.asList(variables); 259 } 260 261 264 public final int getVariableCount() { 265 return variables.length; 266 } 267 268 279 public final Method getMethod(String name, String signature) { 280 int n = methods.length; 281 for (int i = 0; i < n; i++) { 282 Method m = methods[i]; 283 if (m.getName().equals(name) && m.getDescriptor().equals(signature)) 284 return m; 285 } 286 return null; 287 } 288 289 293 public final Collection<Method> getMethods() { 294 return Arrays.asList(methods); 295 } 296 297 300 public final int getMethodCount() { 301 return methods.length; 302 } 303 304 307 public final String getSourceFileName() { 308 if (sourceFileName == null) { 309 DataInputStream in = attributes.getStream("SourceFile"); if (in != null) { 311 try { 312 int ipool = in.readUnsignedShort(); 313 CPUTF8Info entry = (CPUTF8Info)constantPool.get(ipool); 314 sourceFileName = entry.getName(); 315 in.close(); 316 } catch (IOException e) { 317 throw new InvalidClassFileAttributeException("invalid SourceFile attribute", e); 318 } 319 } 320 } 321 return sourceFileName; 322 } 323 324 public final boolean isDeprecated() { 325 return attributes.get("Deprecated") != null; 326 } 327 328 public final boolean isSynthetic() { 329 return (classAccess & Access.SYNTHETIC) == Access.SYNTHETIC || 330 attributes.get("Synthetic") != null; 331 } 332 333 334 337 public final boolean isAnnotation() { 338 return (classAccess & Access.ANNOTATION) == Access.ANNOTATION; 339 } 340 341 344 public final boolean isEnum() { 345 return (classAccess & Access.ENUM) == Access.ENUM; 346 } 347 348 355 public final AttributeMap getAttributes(){ 356 return attributes; 357 } 358 359 public final Collection<InnerClass> getInnerClasses(){ 360 if (innerClasses == null) { 361 DataInputStream in = attributes.getStream("InnerClasses"); if (in != null) { 363 try { 364 innerClasses = 365 InnerClass.loadInnerClasses(in, constantPool); 366 in.close(); 367 } catch (IOException e) { 368 throw new InvalidClassFileAttributeException("invalid InnerClasses attribute", e); 369 } 370 } else 371 innerClasses = new InnerClass[0]; 372 } 373 return Arrays.asList(innerClasses); 374 } 375 376 379 public int getMajorVersion() { 380 return majorVersion; 381 } 382 383 386 public int getMinorVersion() { 387 return minorVersion; 388 } 389 390 395 public String getTypeSignature() { 396 if (typeSignature == null) { 397 DataInputStream in = attributes.getStream("Signature"); if (in != null) { 399 try { 400 CPUTF8Info entry = 401 (CPUTF8Info)constantPool.get(in.readUnsignedShort()); 402 typeSignature = entry.getName(); 403 in.close(); 404 } catch (IOException e) { 405 throw new InvalidClassFileAttributeException("invalid Signature attribute", e); 406 } 407 } 408 } 409 return typeSignature; 410 } 411 412 419 public EnclosingMethod getEnclosingMethod() { 420 if (enclosingMethod == null) { 421 DataInputStream in = 422 attributes.getStream("EnclosingMethod"); if (in != null) { 424 try { 425 int classIndex = in.readUnsignedShort(); 426 int natIndex = in.readUnsignedShort(); 427 CPEntry classInfo = constantPool.get(classIndex); 428 if (classInfo.getTag() == ConstantPool.CONSTANT_Class) 429 enclosingMethod = 430 new EnclosingMethod(constantPool, 431 (CPClassInfo)classInfo, 432 natIndex); 433 else 434 ; in.close(); 436 } catch (IOException e) { 437 throw new InvalidClassFileAttributeException("invalid EnclosingMethod attribute", e); 438 } 439 } 440 } 441 return enclosingMethod; 442 } 443 444 private void loadAnnotations() { 445 if (annotations == null) 446 annotations = buildAnnotationMap(constantPool, attributes); 447 } 448 449 static Map<ClassName,Annotation> buildAnnotationMap(ConstantPool pool, AttributeMap attrs) { 450 Map<ClassName,Annotation> annotations = new HashMap<ClassName,Annotation>(2); 451 DataInputStream in = 452 attrs.getStream("RuntimeVisibleAnnotations"); if (in != null) { 454 try { 455 Annotation.load(in, pool, true, annotations); 456 in.close(); 457 } catch (IOException e) { 458 throw new InvalidClassFileAttributeException("invalid RuntimeVisibleAnnotations attribute", e); 459 } 460 } 461 in = attrs.getStream("RuntimeInvisibleAnnotations"); if (in != null) { 463 try { 464 Annotation.load(in, pool, false, annotations); 465 in.close(); 466 } catch (IOException e) { 467 throw new InvalidClassFileAttributeException("invalid RuntimeInvisibleAnnotations attribute", e); 468 } 469 } 470 return annotations; 471 } 472 473 477 public final Collection<Annotation> getAnnotations() { 478 loadAnnotations(); 479 return annotations.values(); 480 } 481 482 486 public final Annotation getAnnotation(final ClassName annotationClass) { 487 loadAnnotations(); 488 return annotations.get(annotationClass); 489 } 490 491 495 public final boolean isAnnotationPresent(final ClassName annotationClass) { 496 loadAnnotations(); 497 return annotations.get(annotationClass) != null; 498 } 499 500 504 public final Set<ClassName> getAllClassNames() { 505 Set<ClassName> set = new HashSet<ClassName>(); 506 507 Collection c = constantPool.getAllConstants(CPClassInfo.class); 509 for (Iterator i = c.iterator(); i.hasNext();) { 510 CPClassInfo ci = (CPClassInfo)i.next(); 511 set.add(ci.getClassName()); 512 } 513 514 for (int i = 0; i < variables.length; i++) 517 addClassNames(set, variables[i].getDescriptor()); 518 for (int i = 0; i < methods.length; i++) 519 addClassNames(set, methods[i].getDescriptor()); 520 521 return Collections.unmodifiableSet(set); 522 } 523 524 private void addClassNames(Set<ClassName> set, String type) { 525 int i = 0; 526 while ((i = type.indexOf('L', i)) != -1) { 527 int j = type.indexOf(';', i); 528 if (j > i) { 529 String classType = type.substring(i + 1, j); 531 set.add(ClassName.getClassName(classType)); 532 i = j + 1; 533 } else 534 break; 535 } 536 } 537 538 public String toString() { 539 StringBuffer sb = new StringBuffer (); 540 sb.append("ClassFile: "); sb.append(Access.toString(classAccess)); 542 sb.append(' '); 543 sb.append(classInfo); 544 if (isSynthetic()) 545 sb.append(" (synthetic)"); if (isDeprecated()) 547 sb.append(" (deprecated)"); sb.append("\n source: "); sb.append(getSourceFileName()); 550 sb.append("\n super: "); sb.append(superClassInfo); 552 if (getTypeSignature() != null) { 553 sb.append("\n signature: "); sb.append(typeSignature); 555 } 556 if (getEnclosingMethod() != null) { 557 sb.append("\n enclosing method: "); sb.append(enclosingMethod); 559 } 560 sb.append("\n "); 561 loadAnnotations(); 562 if (annotations.size() > 0) { 563 Iterator iter = annotations.values().iterator(); 564 sb.append("annotations: "); 565 while (iter.hasNext()) { 566 sb.append("\n "); 567 sb.append(iter.next().toString()); 568 } 569 sb.append("\n "); 570 } 571 if (interfaces.length > 0) { 572 sb.append(arrayToString("interfaces", interfaces)); sb.append("\n "); 574 } 575 if (getInnerClasses().size() > 0) { 576 sb.append(arrayToString("innerclasses", innerClasses)); sb.append("\n "); 578 } 579 if (variables.length > 0) { 580 sb.append(arrayToString("variables", variables)); sb.append("\n "); 582 } 583 if (methods.length > 0) 584 sb.append(arrayToString("methods", methods)); return sb.toString(); 586 } 587 588 private String arrayToString(String name, Object [] array) { 589 StringBuffer sb = new StringBuffer (); 590 sb.append(name); 591 sb.append(": "); 592 int n = array.length; 593 if (n > 0) { 594 int i = 0; 595 do { 596 sb.append("\n "); 597 sb.append(array[i++].toString()); 598 } while (i < n); 599 } else 600 sb.append("none"); return sb.toString(); 602 } 603 } 604 | Popular Tags |