/** Read annotation entry from classfile. */ private AnnotationInfo readAnnotation(final DataInputStream inp, Object[] constantPool) throws IOException { String annotationFieldDescriptor = readRefdString(inp, constantPool); String annotationClassName; if (annotationFieldDescriptor.charAt(0) == 'L' && annotationFieldDescriptor.charAt(annotationFieldDescriptor.length() - 1) == ';') { // Lcom/xyz/Annotation; -> com.xyz.Annotation annotationClassName = annotationFieldDescriptor .substring(1, annotationFieldDescriptor.length() - 1) .replace('/', '.'); } else { // Should not happen annotationClassName = annotationFieldDescriptor; } AnnotationInfo annotation = new AnnotationInfo(classInfoLoader.get(annotationClassName)); int numElementValuePairs = inp.readUnsignedShort(); for (int i = 0; i < numElementValuePairs; i++) { String name = readRefdString(inp, constantPool); final Object value = readAnnotationElementValue(inp, constantPool); annotation.setAttribute(name, value); } return annotation; }
/** * Read the full class information * * @return The object */ public ClassInfo resolve() { if (loaded) { return this; } if (isArray()) { loaded = true; return this; } // Simple cases switch (name) { case "B": theClass = Byte.TYPE; break; case "C": theClass = Character.TYPE; break; case "D": theClass = Double.TYPE; break; case "F": theClass = Float.TYPE; break; case "I": theClass = Integer.TYPE; break; case "J": theClass = Long.TYPE; break; case "S": theClass = Short.TYPE; break; case "Z": theClass = Boolean.TYPE; break; default: final InputStream stream = classInfoLoader.getStream(name); if (stream != null) { try { readFromInputStream(stream); } catch (IOException e) { throw new RuntimeException(format("Could not read class %s", name), e); } } else { try { theClass = classInfoLoader.classLoader.loadClass(name); } catch (ClassNotFoundException e) { throw new RuntimeException(format("Could not find class %s", name), e); } } } loaded = true; return this; }
public ClassInfo getComponentType() { if (!isArray()) return null; return classInfoLoader.get(name.substring(1)); }
/** Directly examine contents of classfile binary header. */ private void readFromInputStream(final InputStream inputStream) throws IOException { DataInputStream inp = new DataInputStream(new BufferedInputStream(inputStream, 1024)); // Magic if (inp.readInt() != 0xCAFEBABE) { // Not classfile throw new IOException("Not a class file"); } // Minor version inp.readUnsignedShort(); // Major version inp.readUnsignedShort(); // Constant pool count (1-indexed, zeroth entry not used) int cpCount = inp.readUnsignedShort(); // Constant pool Object[] constantPool = new Object[cpCount]; for (int i = 1; i < cpCount; ++i) { final int tag = inp.readUnsignedByte(); switch (tag) { case 1: // Modified UTF8 constantPool[i] = inp.readUTF(); break; case 3: // int constantPool[i] = inp.readInt(); break; case 4: // float constantPool[i] = inp.readFloat(); break; case 5: // long constantPool[i] = inp.readLong(); i++; break; case 6: // double constantPool[i] = inp.readDouble(); i++; // double slot break; case 7: // Class case 8: // String // Forward or backward reference a Modified UTF8 entry constantPool[i] = inp.readUnsignedShort(); break; case 9: // field ref case 10: // method ref case 11: // interface ref case 12: // name and type inp.skipBytes(4); // two shorts break; case 15: // method handle inp.skipBytes(3); break; case 16: // method type inp.skipBytes(2); break; case 18: // invoke dynamic inp.skipBytes(4); break; default: throw new ClassFormatError("Unkown tag value for constant pool entry: " + tag); } } // Access flags int flags = inp.readUnsignedShort(); isInterface = (flags & 0x0200) != 0; // This class name, with slashes replaced with dots String name = readRefdString(inp, constantPool).replace('/', '.'); if (this.name == null) { this.name = name; } else { if (!this.name.equals(name)) throw new IllegalStateException( format("Class name %s and %s do not match", name, this.name)); } // Superclass name, with slashes replaced with dots final String superclassName = toClassName(readRefdString(inp, constantPool)); superclass = superclassName == null ? null : classInfoLoader.get(superclassName); // Interfaces int interfaceCount = inp.readUnsignedShort(); for (int i = 0; i < interfaceCount; i++) { interfaces.add(classInfoLoader.get(toClassName(readRefdString(inp, constantPool)))); } // Fields int fieldCount = inp.readUnsignedShort(); for (int i = 0; i < fieldCount; i++) { inp.skipBytes(2); // access_flags final String fieldName = readRefdString(inp, constantPool); // name_index, String fieldDescriptor = readRefdString(inp, constantPool); // name_index, if (fieldDescriptor.startsWith("L") && fieldDescriptor.endsWith(";")) { fieldDescriptor = fieldDescriptor.substring(1, fieldDescriptor.length() - 1).replace("/", "."); } final FieldInfo fieldInfo = new FieldInfo(fieldName, classInfoLoader.get(fieldDescriptor)); fields.put(fieldName, fieldInfo); int attributesCount = inp.readUnsignedShort(); for (int j = 0; j < attributesCount; j++) { String attributeName = readRefdString(inp, constantPool); int attributeLength = inp.readInt(); if ("RuntimeVisibleAnnotations".equals(attributeName)) { int annotationCount = inp.readUnsignedShort(); for (int m = 0; m < annotationCount; m++) { AnnotationInfo annotation = readAnnotation(inp, constantPool); fieldInfo.annotations.put(annotation.annotationClass.getName(), annotation); } } else { inp.skipBytes(attributeLength); } } } // Methods int methodCount = inp.readUnsignedShort(); for (int i = 0; i < methodCount; i++) { inp.skipBytes(6); // access_flags, name_index, descriptor_index int attributesCount = inp.readUnsignedShort(); for (int j = 0; j < attributesCount; j++) { inp.skipBytes(2); // attribute_name_index int attributeLength = inp.readInt(); inp.skipBytes(attributeLength); } } // Attributes (including class annotations) int attributesCount = inp.readUnsignedShort(); for (int i = 0; i < attributesCount; i++) { String attributeName = readRefdString(inp, constantPool); int attributeLength = inp.readInt(); if ("RuntimeVisibleAnnotations".equals(attributeName)) { int annotationCount = inp.readUnsignedShort(); for (int m = 0; m < annotationCount; m++) { AnnotationInfo annotation = readAnnotation(inp, constantPool); annotations.put(annotation.annotationClass.getName(), annotation); } } else { inp.skipBytes(attributeLength); } } }