
org.fife.rsta.ac.java.classreader.ClassFile Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of languagesupport Show documentation
Show all versions of languagesupport Show documentation
A library adding code completion and other advanced features for Java, JavaScript, Perl, and other languages to RSyntaxTextArea.
/* * 03/21/2010 * * Copyright (C) 2010 Robert Futrell * robert_futrell at users.sourceforge.net * http://fifesoft.com/rsyntaxtextarea * * This library is distributed under a modified BSD license. See the included * RSTALanguageSupport.License.txt file for details. */ package org.fife.rsta.ac.java.classreader; import java.io.*; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.fife.rsta.ac.java.classreader.attributes.*; import org.fife.rsta.ac.java.classreader.constantpool.*; /** * Class representing a
* if none. This is a list of {@link MethodInfo}s. * @see #getMethodInfoByName(String, int) */ public ListClassFile
structure. * * @author Robert Futrell * @version 1.0 */ public class ClassFile implements AccessFlags { private static final boolean DEBUG = false; /** * The class file's minor version number. */ private int minorVersion; // u2 /** * The class file's major version number. */ private int majorVersion; // u2 /** * Constant pool infos. */ private ConstantPoolInfo[] constantPool; // Length constant_pool_count-1 !! /** * Permissions and properties of this class or interface. */ private int accessFlags; // u2 /** * Index into {@link #constantPool} for aConstantClassInfo
* structure representing the class or interface defined in this class file. */ private int thisClass; // u2 /** * Index into {@link #constantPool} for aConstantClassInfo
* structure representing the superclass of this class or interface. If * this value is0
then this class must be class *java.lang.Object
. If this is an interface, then this index * must point to information about classjava.lang.Object
. */ private int superClass; // u2 /** * Indices into {@code constantPool} forConstantClassInfo
s * representing the implemented interfaces of this class or interface. */ int[] interfaces; // u2[] /** * Structures giving complete descriptions of the fields in this class * or interface. */ private FieldInfo[] fields; /** * Structures giving complete descriptions of the methods in this class or * interface. */ private MethodInfo[] methods; /** * Whether this class is deprecated. */ private boolean deprecated; /** * Attributes of this class or interface. */ private AttributeInfo[] attributes; /** * Parameter types, such as "String" inList<String>
. */ private ListparamTypes; /** * A mapping of type parameters to type arguments. This is set via * {@link #setTypeParamsToTypeArgs(Map)} during code completion of members of an * instance variable whose type is represented by this class file. This * ClassFile
doesn't use this field itself; rather, it's there * for consumers (such as the Java code completion API) to use. */ private MaptypeMap; public static final String DEPRECATED = "Deprecated"; public static final String ENCLOSING_METHOD = "EnclosingMethod"; public static final String INNER_CLASSES = "InnerClasses"; public static final String RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations"; public static final String SIGNATURE = "Signature"; public static final String SOURCE_FILE = "SourceFile"; public static final String BOOTSTRAP_METHODS = "BootstrapMethods"; /** * The 4-byte class file header, " CAFEBABE
". */ private static final byte[] HEADER = { (byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE }; public ClassFile(File classFile) throws IOException { try (DataInputStream in = new DataInputStream(new BufferedInputStream( new FileInputStream(classFile)))) { init(in); } } public ClassFile(DataInputStream in) throws IOException { init(in); } private void debugPrint(String text) { if (DEBUG) { System.out.println(text); } } /** * Returns the access flags for this class or interface. * * @return The access flags, as a bit field. * @see AccessFlags */ public int getAccessFlags() { return accessFlags; } /** * Returns the specified attribute of this class file. * * @param index The index of the attribute. * @return The attribute. * @see #getAttributeCount() */ public AttributeInfo getAttribute(int index) { return attributes[index]; } /** * Returns the number of attributes of this class file. * * @return The number of attributes. * @see #getAttribute(int) */ public int getAttributeCount() { return attributes==null ? 0 : attributes.length; } /** * Returns the name of this class or interface. * * @param fullyQualified Whether the name should be fully-qualified. * @return The name of this class or interface. * @see #getSuperClassName(boolean) */ public String getClassName(boolean fullyQualified) { return getClassNameFromConstantPool(thisClass, fullyQualified); } /** * Given an index into the constant pool of a {@link ConstantClassInfo}, * this method returns the fully-qualified name of the class it points to. * * @param cpIndex The index into the constant pool. Note that * this value is1
-based. * @param fullyQualified Whether the returned class name should be fully * qualified. * @return The fully-qualified class or interface name. */ protected String getClassNameFromConstantPool(int cpIndex, boolean fullyQualified) { ConstantPoolInfo cpi = getConstantPoolInfo(cpIndex); if (cpi instanceof ConstantClassInfo) { ConstantClassInfo cci = (ConstantClassInfo)cpi; int index = cci.getNameIndex(); ConstantUtf8Info cui = (ConstantUtf8Info)getConstantPoolInfo(index); String className = cui.getRepresentedString(false); if (fullyQualified) { className = className.replace('/', '.'); } else { className = className.substring(className.lastIndexOf('/')+1); } return className.replace('$', '.'); } // cpi is never null throw new InternalError("Expected ConstantClassInfo, found " + cpi.getClass().toString()); } /** * Returns the size of the constant pool, plus1
. * * @return The size of the constant pool, plus1
. * @see #getConstantPoolInfo(int) */ public int getConstantPoolCount() { return constantPool.length + 1; } /** * Returns the constant pool entry at the specified index. Note that * constant pool entries are1
-based (that is, valid indices * are1 - getConstantPoolCount()-1
). * * @param index The index into the constant pool to retrieve. * @return The constant pool entry, ornull
if *index
is0
(e.g. this *ClassFile
object represents *java.lang.Object
). * @see #getConstantPoolCount() */ public ConstantPoolInfo getConstantPoolInfo(int index) { return index!=0 ? constantPool[index-1] : null; } /** * Returns the number of fields declared in this class file. * * @return The number of fields. * @see #getFieldInfo(int) */ public int getFieldCount() { return fields==null ? 0 : fields.length; } /** * Returns the specified field's information. * * @param index The index of the field info. * @return The field's information. * @see #getFieldCount() * @see #getFieldInfoByName(String) */ public FieldInfo getFieldInfo(int index) { return fields[index]; } /** * Returns a field's information by name. * * @param name The name of the field. * @return The field's information. * @see #getFieldCount() * @see #getFieldInfo(int) */ public FieldInfo getFieldInfoByName(String name) { for (int i=0; inull getMethodInfoByName(String name) { return getMethodInfoByName(name, -1); } /** * Returns all method overloads with the specified name and number of * arguments. * * @param name The method name. * @param argCount The number of arguments. If this is less than zero, * all overloads will be returned, regardless of argument count. * @return Any method overloads with the given name and argument count, or * null
if none. This is a list of * {@link MethodInfo}s. * @see #getMethodInfoByName(String) */ public ListgetMethodInfoByName(String name, int argCount) { List methods = null; for (int i=0; i (1); // Usually just 1 } methods.add(info); } } } return methods; } /** * Returns the package for this class or interface. * * @return The package, or null
if this class or interface * is not in a package. * @see #getClassName(boolean) */ public String getPackageName() { String className = getClassName(true); int dot = className.lastIndexOf('.'); return dot==-1 ? null : className.substring(0, dot); } public ListgetParamTypes() { return paramTypes; } /** * Returns the fully-qualified name of the superclass of this class or * interface. * * @param fullyQualified Whether the returned value should be fully * qualified. * @return The name of the superclass of this class or interface. If this * is an interface, then " java.lang.Object
" is * returned. If this class file represents *java.lang.Object
, thennull
is * returned. * @see #getClassName(boolean) */ public String getSuperClassName(boolean fullyQualified) { if (superClass==0) { // This is java.lang.Object return null; } return getClassNameFromConstantPool(superClass, fullyQualified); } /** * Returns the currently set type argument for the specified type parameter. * * @param typeParam The type parameter. * @return The type argument, or "Object
" if no type * parameters have been set. This is because, if the user types, * say, "java.util.List list;
" in Java 5+, the * type defaults toObject
. The code completion API * may set the type argument mapping tonull
if no * type arguments are scanned, thus we need to return *Object
in this case. * @see #setTypeParamsToTypeArgs(Map) */ public String getTypeArgument(String typeParam) { // If no type arguments are specified for a class that's supposed to // have them (according to calling code), return "Object", as Java // assumes this. return typeMap==null ? "Object" : (String)typeMap.get(typeParam); } /** * Returns the string value represented by aConstantUtf8Info
* entry in the constant pool. * * @param index The index into the constant pool of a *ConstantUtf8Info
structure. This should be *1
-based. * @return The string represented. */ public String getUtf8ValueFromConstantPool(int index) { ConstantPoolInfo cpi = getConstantPoolInfo(index); ConstantUtf8Info cui = (ConstantUtf8Info)cpi; return cui.getRepresentedString(false); } /** * Returns the version number of this class, as a string. * * @return The class's version number, in the form *major.minor
. */ public String getVersionString() { return majorVersion + "." + minorVersion; } /** * Parses the class file from a given input stream. * * @param in * @throws IOException If an error occurs reading the class file. */ private void init(DataInputStream in) throws IOException { readHeader(in); readVersion(in); readConstantPoolInfos(in); readAccessFlags(in); readThisClass(in); readSuperClass(in); readInterfaces(in); readFields(in); readMethods(in); readAttributes(in); } /** * Returns whether this class is deprecated. * * @return Whether this class is deprecated. */ public boolean isDeprecated() { return deprecated; } /** * Reads this class or interface's access flags. * * @param in * @throws IOException If an error occurs reading the access flags. */ private void readAccessFlags(DataInputStream in) throws IOException { accessFlags = in.readUnsignedShort(); debugPrint("Access flags: " + accessFlags); } /** * Reads a single attribute of this class file. * * @param in The input stream to read from. * @return The attribute. * @throws IOException If an IO error occurs. */ private AttributeInfo readAttribute(DataInputStream in) throws IOException { AttributeInfo ai = null; int attributeNameIndex = in.readUnsignedShort(); int attributeLength = in.readInt(); String attrName = getUtf8ValueFromConstantPool(attributeNameIndex); debugPrint("Found class attribute: " + attrName); if (SOURCE_FILE.equals(attrName)) { // 4.7.7 int sourceFileIndex = in.readUnsignedShort(); SourceFile sf = new SourceFile(this, sourceFileIndex); ai = sf; } else if (BOOTSTRAP_METHODS.equals(attrName)) { // 4.7.23 //String name = getClassFile().getClassName(false) + "." + getName(); //System.out.println(name + ": Attribute " + attrName + " not supported"); Util.skipBytes(in, attributeLength); //ai = null; } else if (SIGNATURE.equals(attrName)) { // 4.8.8 int signatureIndex = in.readUnsignedShort(); String sig = getUtf8ValueFromConstantPool(signatureIndex); //System.out.println("... Signature: " + sig); ai = new Signature(this, sig); paramTypes = ((Signature)ai).getClassParamTypes(); } else if (INNER_CLASSES.equals(attrName)) { // 4.8.5 //String name = getClassName(false) + "." + getName(); //System.out.println(name + ": Attribute " + attrName + " not supported"); Util.skipBytes(in, attributeLength); //ai = null; } else if (ENCLOSING_METHOD.equals(attrName)) { // 4.8.6 //String name = getClassName(false) + "." + getName(); //System.out.println(name + ": Attribute " + attrName + " not supported"); Util.skipBytes(in, attributeLength); // 2 u2's, class_index and method_index //ai = null; } else if (DEPRECATED.equals(attrName)) { // 4.7.10 // No need to read anything else, attributeLength==0 deprecated = true; } else if (RUNTIME_VISIBLE_ANNOTATIONS.equals(attrName)) { // 4.8.15 //String name = getClassFile().getClassName(false) + "." + getName(); //System.out.println(name + ": Attribute " + attrName + " not supported"); Util.skipBytes(in, attributeLength); //ai = null; } // TODO: Handle other useful Attribute types, if any. else { // An unknown/unsupported attribute. debugPrint("Unsupported class attribute: "+ attrName); ai = AttributeInfo.readUnsupportedAttribute(this, in, attrName, attributeLength); } return ai; } /** * Reads this class file's attributes. * * @param in The input stream to read from. * @throws IOException If an IO error occurs. */ private void readAttributes(DataInputStream in) throws IOException { int attributeCount = in.readUnsignedShort(); if (attributeCount>0) { attributes = new AttributeInfo[attributeCount]; for (int i=0; i0) { fields = new FieldInfo[fieldCount]; for (int i=0; i 0xCAFEBABE class file header. * * @param in * @throws IOException If the header is invalid. */ private void readHeader(DataInputStream in) throws IOException { for (byte b1 : HEADER) { byte b = in.readByte(); if (b != b1) { throw new IOException("\"CAFEBABE\" header not found"); } } } /** * Reads the array of indices into the constant pool for the names of the * interfaces implemented by this class or interface. * * @param in * @throws IOException If an IO error occurs reading the input stream. */ private void readInterfaces(DataInputStream in) throws IOException { int interfaceCount = in.readUnsignedShort(); if (interfaceCount>0) { interfaces = new int[interfaceCount]; for (int i=0; i 0) { methods = new MethodInfo[methodCount]; for (int i=0; i ClassFile * does not directly use this field; it is there for code completion API's * to use to extract the necessary types of arguments, return values, etc., * of methods (see the {@link MethodInfo} class). * * @param typeMap A mapping of type parameters to type arguments (both * String
s). * @see #getTypeArgument(String) */ public void setTypeParamsToTypeArgs(MaptypeMap) { this.typeMap = typeMap; for (int i=0; i
© 2015 - 2025 Weber Informatics LLC | Privacy Policy