diff options
author | chiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3> | 2004-04-05 09:24:26 +0000 |
---|---|---|
committer | chiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3> | 2004-04-05 09:24:26 +0000 |
commit | f56bd9e72f3032f66241f864725f208e0df03839 (patch) | |
tree | 15074c6e93bc08dd0af9ec4dc207bf9822a3f7b4 /src/main/javassist/bytecode/ClassFile.java | |
parent | ed96cc41015dae453237abc3934c2570e770bf53 (diff) | |
download | javassist-f56bd9e72f3032f66241f864725f208e0df03839.tar.gz javassist-f56bd9e72f3032f66241f864725f208e0df03839.zip |
changed the stuff related to ClassPool.
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@76 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
Diffstat (limited to 'src/main/javassist/bytecode/ClassFile.java')
-rw-r--r-- | src/main/javassist/bytecode/ClassFile.java | 1212 |
1 files changed, 580 insertions, 632 deletions
diff --git a/src/main/javassist/bytecode/ClassFile.java b/src/main/javassist/bytecode/ClassFile.java index b156176d..9e759b0d 100644 --- a/src/main/javassist/bytecode/ClassFile.java +++ b/src/main/javassist/bytecode/ClassFile.java @@ -32,636 +32,584 @@ import javassist.bytecode.annotation.AnnotationGroup; * * @see javassist.CtClass#getClassFile() */ -public final class ClassFile -{ - ConstPool constPool; - int thisClass; - int accessFlags; - int superClass; - int[] interfaces; - LinkedList fields; - LinkedList methods; - LinkedList attributes; - AnnotationGroup runtimeInvisible; - AnnotationGroup runtimeVisible; - - String thisclassname; // not JVM-internal name - - /** - * Constructs a class file from a byte stream. - */ - public ClassFile(DataInputStream in) throws IOException - { - read(in); - } - - /** - * Constructs a class file including no members. - * - * @param isInterface true if this is an interface. - * false if this is a class. - * @param classname a fully-qualified class name - * @param superclass a fully-qualified super class name - */ - public ClassFile(boolean isInterface, - String classname, String superclass) - { - constPool = new ConstPool(classname); - thisClass = constPool.getThisClassInfo(); - if (isInterface) - accessFlags = AccessFlag.SUPER | AccessFlag.INTERFACE - | AccessFlag.ABSTRACT; - else - accessFlags = AccessFlag.SUPER; - - initSuperclass(superclass); - interfaces = null; - fields = new LinkedList(); - methods = new LinkedList(); - thisclassname = classname; - - attributes = new LinkedList(); - attributes.add(new SourceFileAttribute(constPool, - getSourcefileName(thisclassname))); - } - - private void initSuperclass(String superclass) - { - if (superclass != null) - superClass = constPool.addClassInfo(superclass); - else - superClass = constPool.addClassInfo("java.lang.Object"); - } - - private static String getSourcefileName(String qname) - { - int index = qname.lastIndexOf('.'); - if (index >= 0) - qname = qname.substring(index + 1); - - return qname + ".java"; - } - - /** - * Returns a constant pool table. - */ - public ConstPool getConstPool() - { - return constPool; - } - - /** - * Returns true if this is an interface. - */ - public boolean isInterface() - { - return (accessFlags & AccessFlag.INTERFACE) != 0; - } - - /** - * Returns true if this is a final class or interface. - */ - public boolean isFinal() - { - return (accessFlags & AccessFlag.FINAL) != 0; - } - - /** - * Returns true if this is an abstract class or an interface. - */ - public boolean isAbstract() - { - return (accessFlags & AccessFlag.ABSTRACT) != 0; - } - - /** - * Returns access flags. - * - * @see javassist.bytecode.AccessFlag - */ - public int getAccessFlags() - { - return accessFlags; - } - - /** - * Changes access flags. - * - * @see javassist.bytecode.AccessFlag - */ - public void setAccessFlags(int acc) - { - accessFlags = acc | AccessFlag.SUPER; - } - - /** - * Returns the class name. - */ - public String getName() - { - return thisclassname; - } - - /** - * Sets the class name. This method substitutes the new name - * for all occurrences of the old class name in the class file. - */ - public void setName(String name) - { - renameClass(thisclassname, name); - } - - /** - * Returns the super class name. - */ - public String getSuperclass() - { - return constPool.getClassInfo(superClass); - } - - /** - * Returns the index of the constant pool entry representing - * the super class. - */ - public int getSuperclassId() - { - return superClass; - } - - /** - * Sets the super class. - * - * <p>This method modifies constructors so that they call - * constructors declared in the new super class. - */ - public void setSuperclass(String superclass) - throws CannotCompileException - { - if (superclass == null) - superclass = "java.lang.Object"; - - try - { - superClass = constPool.addClassInfo(superclass); - LinkedList list = methods; - int n = list.size(); - for (int i = 0; i < n; ++i) - { - MethodInfo minfo = (MethodInfo) list.get(i); - minfo.setSuperclass(superclass); - } - } - catch (BadBytecode e) - { - throw new CannotCompileException(e); - } - } - - /** - * Replaces all occurrences of a class name in the class file. - * - * <p>If class X is substituted for class Y in the class file, - * X and Y must have the same signature. If Y provides a method - * m(), X must provide it even if X inherits m() from the super class. - * If this fact is not guaranteed, the bytecode verifier may cause - * an error. - * - * @param oldname the replaced class name - * @param newname the substituted class name - */ - public final void renameClass(String oldname, String newname) - { - LinkedList list; - int n; - - if (oldname.equals(newname)) - return; - - if (oldname.equals(thisclassname)) - thisclassname = newname; - - oldname = Descriptor.toJvmName(oldname); - newname = Descriptor.toJvmName(newname); - constPool.renameClass(oldname, newname); - - list = methods; - n = list.size(); - for (int i = 0; i < n; ++i) - { - MethodInfo minfo = (MethodInfo) list.get(i); - String desc = minfo.getDescriptor(); - minfo.setDescriptor(Descriptor.rename(desc, oldname, newname)); - } - - list = fields; - n = list.size(); - for (int i = 0; i < n; ++i) - { - FieldInfo finfo = (FieldInfo) list.get(i); - String desc = finfo.getDescriptor(); - finfo.setDescriptor(Descriptor.rename(desc, oldname, newname)); - } - } - - /** - * Replaces all occurrences of several class names in the class file. - * - * @param classnames specifies which class name is replaced - * with which new name. Class names must - * be described with the JVM-internal - * representation like - * <code>java/lang/Object</code>. - * - * @see #renameClass(String,String) - */ - public final void renameClass(Map classnames) - { - String jvmNewThisName - = (String) classnames.get(Descriptor.toJvmName(thisclassname)); - if (jvmNewThisName != null) - thisclassname = Descriptor.toJavaName(jvmNewThisName); - - constPool.renameClass(classnames); - - LinkedList list = methods; - int n = list.size(); - for (int i = 0; i < n; ++i) - { - MethodInfo minfo = (MethodInfo) list.get(i); - String desc = minfo.getDescriptor(); - minfo.setDescriptor(Descriptor.rename(desc, classnames)); - } - - list = fields; - n = list.size(); - for (int i = 0; i < n; ++i) - { - FieldInfo finfo = (FieldInfo) list.get(i); - String desc = finfo.getDescriptor(); - finfo.setDescriptor(Descriptor.rename(desc, classnames)); - } - } - - /** - * Returns the names of the interfaces implemented by the class. - */ - public String[] getInterfaces() - { - if (interfaces == null) - return new String[0]; - else - { - int n = interfaces.length; - String[] list = new String[n]; - for (int i = 0; i < n; ++i) - list[i] = constPool.getClassInfo(interfaces[i]); - - return list; - } - } - - /** - * Sets the interfaces. - * - * @param nameList the names of the interfaces. - */ - public void setInterfaces(String[] nameList) - { - if (nameList != null) - { - int n = nameList.length; - interfaces = new int[n]; - for (int i = 0; i < n; ++i) - interfaces[i] = constPool.addClassInfo(nameList[i]); - } - } - - /** - * Appends an interface to the - * interfaces implemented by the class. - */ - public void addInterface(String name) - { - int info = constPool.addClassInfo(name); - if (interfaces == null) - { - interfaces = new int[1]; - interfaces[0] = info; - } - else - { - int n = interfaces.length; - int[] newarray = new int[n + 1]; - System.arraycopy(interfaces, 0, newarray, 0, n); - newarray[n] = info; - interfaces = newarray; - } - } - - /** - * Returns all the fields declared in the class. - * - * @return a list of <code>FieldInfo</code>. - * @see FieldInfo - */ - public List getFields() - { - return fields; - } - - /** - * Appends a field to the class. - */ - public void addField(FieldInfo finfo) throws CannotCompileException - { - testExistingField(finfo.getName(), finfo.getDescriptor()); - fields.add(finfo); - } - - private void addField0(FieldInfo finfo) - { - fields.add(finfo); - } - - private void testExistingField(String name, String descriptor) - throws CannotCompileException - { - ListIterator it = fields.listIterator(0); - while (it.hasNext()) - { - FieldInfo minfo = (FieldInfo) it.next(); - if (minfo.getName().equals(name)) - throw new CannotCompileException("duplicate field: " + name); - } - } - - /** - * Returns all the methods declared in the class. - * - * @return a list of <code>MethodInfo</code>. - * @see MethodInfo - */ - public List getMethods() - { - return methods; - } - - /** - * Returns the method with the specified name. If there are multiple - * methods with that name, this method returns one of them. - * - * @return null if no such a method is found. - */ - public MethodInfo getMethod(String name) - { - LinkedList list = methods; - int n = list.size(); - for (int i = 0; i < n; ++i) - { - MethodInfo minfo = (MethodInfo) list.get(i); - if (minfo.getName().equals(name)) - return minfo; - } - - return null; - } - - /** - * Returns a static initializer (class initializer), or null if - * it does not exist. - */ - public MethodInfo getStaticInitializer() - { - return getMethod(MethodInfo.nameClinit); - } - - /** - * Appends a method to the class. - */ - public void addMethod(MethodInfo minfo) throws CannotCompileException - { - testExistingMethod(minfo.getName(), minfo.getDescriptor()); - methods.add(minfo); - } - - private void addMethod0(MethodInfo minfo) - { - methods.add(minfo); - } - - private void testExistingMethod(String name, String descriptor) - throws CannotCompileException - { - ListIterator it = methods.listIterator(0); - while (it.hasNext()) - { - MethodInfo minfo = (MethodInfo) it.next(); - if (minfo.getName().equals(name) - && Descriptor.eqSignature(minfo.getDescriptor(), descriptor)) - throw new CannotCompileException("duplicate method: " + name); - } - } - - /** - * Returns all the attributes. - * - * @return a list of <code>AttributeInfo</code> objects. - * @see AttributeInfo - */ - public List getAttributes() - { - return attributes; - } - - /** - * Create an empty (null) attribute "RuntimeInvisibleAnnotations" - * Usually used so that you can start adding annotations to a particular thing - */ - public void createRuntimeInvisibleGroup() - { - if (runtimeInvisible == null) - { - AttributeInfo attr = new AttributeInfo(constPool, "RuntimeInvisibleAnnotations"); - addAttribute(attr); - runtimeInvisible = new AnnotationGroup(attr); - } - } - - /** - * Create an empty (null) attribute "RuntimeVisibleAnnotations" - * Usually used so that you can start adding annotations to a particular thing - */ - public void createRuntimeVisibleGroup() - { - if (runtimeVisible == null) - { - AttributeInfo attr = new AttributeInfo(constPool, "RuntimeVisibleAnnotations"); - addAttribute(attr); - runtimeVisible = new AnnotationGroup(attr); - } - } - - /** - * Return access object for getting info about annotations - * This returns runtime invisible annotations as pertains to the - * CLASS RetentionPolicy - * @return - */ - public AnnotationGroup getRuntimeInvisibleAnnotations() - { - if (runtimeInvisible != null) return runtimeInvisible; - AttributeInfo invisible = getAttribute("RuntimeInvisibleAnnotations"); - if (invisible == null) return null; - runtimeInvisible = new AnnotationGroup(invisible); - return runtimeInvisible; - } - - /** - * Return access object for getting info about annotations - * This returns runtime visible annotations as pertains to the - * RUNTIME RetentionPolicy - * @return - */ - public AnnotationGroup getRuntimeVisibleAnnotations() - { - if (runtimeVisible != null) return runtimeVisible; - AttributeInfo visible = getAttribute("RuntimeVisibleAnnotations"); - if (visible == null) return null; - runtimeVisible = new AnnotationGroup(visible); - return runtimeVisible; - } - - /** - * Returns the attribute with the specified name. - * - * @param name attribute name - */ - public AttributeInfo getAttribute(String name) - { - LinkedList list = attributes; - int n = list.size(); - for (int i = 0; i < n; ++i) - { - AttributeInfo ai = (AttributeInfo) list.get(i); - if (ai.getName().equals(name)) - return ai; - } - - return null; - } - - /** - * Appends an attribute. If there is already an attribute with - * the same name, the new one substitutes for it. - */ - public void addAttribute(AttributeInfo info) - { - AttributeInfo.remove(attributes, info.getName()); - attributes.add(info); - } - - /** - * Returns the source file containing this class. - * - * @return null if this information is not available. - */ - public String getSourceFile() - { - SourceFileAttribute sf - = (SourceFileAttribute) getAttribute(SourceFileAttribute.tag); - if (sf == null) - return null; - else - return sf.getFileName(); - } - - private void read(DataInputStream in) throws IOException - { - int i, n; - int magic = in.readInt(); - if (magic != 0xCAFEBABE) - throw new IOException("non class file"); - - int major = in.readUnsignedShort(); - int minor = in.readUnsignedShort(); - constPool = new ConstPool(in); - accessFlags = in.readUnsignedShort(); - thisClass = in.readUnsignedShort(); - constPool.setThisClassInfo(thisClass); - superClass = in.readUnsignedShort(); - n = in.readUnsignedShort(); - if (n == 0) - interfaces = null; - else - { - interfaces = new int[n]; - for (i = 0; i < n; ++i) - interfaces[i] = in.readUnsignedShort(); - } - - ConstPool cp = constPool; - n = in.readUnsignedShort(); - fields = new LinkedList(); - for (i = 0; i < n; ++i) - addField0(new FieldInfo(cp, in)); - - n = in.readUnsignedShort(); - methods = new LinkedList(); - for (i = 0; i < n; ++i) - addMethod0(new MethodInfo(cp, in)); - - attributes = new LinkedList(); - n = in.readUnsignedShort(); - for (i = 0; i < n; ++i) - addAttribute(AttributeInfo.read(cp, in)); - - thisclassname = constPool.getClassInfo(thisClass); - } - - /** - * Writes a class file represened by this object - * into an output stream. - */ - public void write(DataOutputStream out) throws IOException - { - int i, n; - - out.writeInt(0xCAFEBABE); // magic - out.writeShort(3); // major version - out.writeShort(45); // minor version - constPool.write(out); // constant pool - out.writeShort(accessFlags); - out.writeShort(thisClass); - out.writeShort(superClass); - - if (interfaces == null) - n = 0; - else - n = interfaces.length; - - out.writeShort(n); - for (i = 0; i < n; ++i) - out.writeShort(interfaces[i]); - - LinkedList list = fields; - n = list.size(); - out.writeShort(n); - for (i = 0; i < n; ++i) - { - FieldInfo finfo = (FieldInfo) list.get(i); - finfo.write(out); - } - - list = methods; - n = list.size(); - out.writeShort(n); - for (i = 0; i < n; ++i) - { - MethodInfo minfo = (MethodInfo) list.get(i); - minfo.write(out); - } - - out.writeShort(attributes.size()); - AttributeInfo.writeAll(attributes, out); - } +public final class ClassFile { + ConstPool constPool; + int thisClass; + int accessFlags; + int superClass; + int[] interfaces; + LinkedList fields; + LinkedList methods; + LinkedList attributes; + AnnotationGroup runtimeInvisible; + AnnotationGroup runtimeVisible; + + String thisclassname; // not JVM-internal name + + /** + * Constructs a class file from a byte stream. + */ + public ClassFile(DataInputStream in) throws IOException { + read(in); + } + + /** + * Constructs a class file including no members. + * + * @param isInterface true if this is an interface. + * false if this is a class. + * @param classname a fully-qualified class name + * @param superclass a fully-qualified super class name + */ + public ClassFile(boolean isInterface, + String classname, String superclass) { + constPool = new ConstPool(classname); + thisClass = constPool.getThisClassInfo(); + if (isInterface) + accessFlags = AccessFlag.SUPER | AccessFlag.INTERFACE + | AccessFlag.ABSTRACT; + else + accessFlags = AccessFlag.SUPER; + + initSuperclass(superclass); + interfaces = null; + fields = new LinkedList(); + methods = new LinkedList(); + thisclassname = classname; + + attributes = new LinkedList(); + attributes.add(new SourceFileAttribute(constPool, + getSourcefileName(thisclassname))); + } + + private void initSuperclass(String superclass) { + if (superclass != null) + superClass = constPool.addClassInfo(superclass); + else + superClass = constPool.addClassInfo("java.lang.Object"); + } + + private static String getSourcefileName(String qname) { + int index = qname.lastIndexOf('.'); + if (index >= 0) + qname = qname.substring(index + 1); + + return qname + ".java"; + } + + /** + * Returns a constant pool table. + */ + public ConstPool getConstPool() { + return constPool; + } + + /** + * Returns true if this is an interface. + */ + public boolean isInterface() { + return (accessFlags & AccessFlag.INTERFACE) != 0; + } + + /** + * Returns true if this is a final class or interface. + */ + public boolean isFinal() { + return (accessFlags & AccessFlag.FINAL) != 0; + } + + /** + * Returns true if this is an abstract class or an interface. + */ + public boolean isAbstract() { + return (accessFlags & AccessFlag.ABSTRACT) != 0; + } + + /** + * Returns access flags. + * + * @see javassist.bytecode.AccessFlag + */ + public int getAccessFlags() { + return accessFlags; + } + + /** + * Changes access flags. + * + * @see javassist.bytecode.AccessFlag + */ + public void setAccessFlags(int acc) { + accessFlags = acc | AccessFlag.SUPER; + } + + /** + * Returns the class name. + */ + public String getName() { + return thisclassname; + } + + /** + * Sets the class name. This method substitutes the new name + * for all occurrences of the old class name in the class file. + */ + public void setName(String name) { + renameClass(thisclassname, name); + } + + /** + * Returns the super class name. + */ + public String getSuperclass() { + return constPool.getClassInfo(superClass); + } + + /** + * Returns the index of the constant pool entry representing + * the super class. + */ + public int getSuperclassId() { + return superClass; + } + + /** + * Sets the super class. + * + * <p>This method modifies constructors so that they call + * constructors declared in the new super class. + */ + public void setSuperclass(String superclass) + throws CannotCompileException + { + if (superclass == null) + superclass = "java.lang.Object"; + + try { + superClass = constPool.addClassInfo(superclass); + LinkedList list = methods; + int n = list.size(); + for (int i = 0; i < n; ++i) { + MethodInfo minfo = (MethodInfo)list.get(i); + minfo.setSuperclass(superclass); + } + } + catch (BadBytecode e) { + throw new CannotCompileException(e); + } + } + + /** + * Replaces all occurrences of a class name in the class file. + * + * <p>If class X is substituted for class Y in the class file, + * X and Y must have the same signature. If Y provides a method + * m(), X must provide it even if X inherits m() from the super class. + * If this fact is not guaranteed, the bytecode verifier may cause + * an error. + * + * @param oldname the replaced class name + * @param newname the substituted class name + */ + public final void renameClass(String oldname, String newname) { + LinkedList list; + int n; + + if (oldname.equals(newname)) + return; + + if (oldname.equals(thisclassname)) + thisclassname = newname; + + oldname = Descriptor.toJvmName(oldname); + newname = Descriptor.toJvmName(newname); + constPool.renameClass(oldname, newname); + + list = methods; + n = list.size(); + for (int i = 0; i < n; ++i) { + MethodInfo minfo = (MethodInfo)list.get(i); + String desc = minfo.getDescriptor(); + minfo.setDescriptor(Descriptor.rename(desc, oldname, newname)); + } + + list = fields; + n = list.size(); + for (int i = 0; i < n; ++i) { + FieldInfo finfo = (FieldInfo)list.get(i); + String desc = finfo.getDescriptor(); + finfo.setDescriptor(Descriptor.rename(desc, oldname, newname)); + } + } + + /** + * Replaces all occurrences of several class names in the class file. + * + * @param classnames specifies which class name is replaced + * with which new name. Class names must + * be described with the JVM-internal + * representation like + * <code>java/lang/Object</code>. + * + * @see #renameClass(String,String) + */ + public final void renameClass(Map classnames) { + String jvmNewThisName + = (String)classnames.get(Descriptor.toJvmName(thisclassname)); + if (jvmNewThisName != null) + thisclassname = Descriptor.toJavaName(jvmNewThisName); + + constPool.renameClass(classnames); + + LinkedList list = methods; + int n = list.size(); + for (int i = 0; i < n; ++i) { + MethodInfo minfo = (MethodInfo)list.get(i); + String desc = minfo.getDescriptor(); + minfo.setDescriptor(Descriptor.rename(desc, classnames)); + } + + list = fields; + n = list.size(); + for (int i = 0; i < n; ++i) { + FieldInfo finfo = (FieldInfo)list.get(i); + String desc = finfo.getDescriptor(); + finfo.setDescriptor(Descriptor.rename(desc, classnames)); + } + } + + /** + * Returns the names of the interfaces implemented by the class. + */ + public String[] getInterfaces() { + if (interfaces == null) + return new String[0]; + else { + int n = interfaces.length; + String[] list = new String[n]; + for (int i = 0; i < n; ++i) + list[i] = constPool.getClassInfo(interfaces[i]); + + return list; + } + } + + /** + * Sets the interfaces. + * + * @param nameList the names of the interfaces. + */ + public void setInterfaces(String[] nameList) { + if (nameList != null) { + int n = nameList.length; + interfaces = new int[n]; + for (int i = 0; i < n; ++i) + interfaces[i] = constPool.addClassInfo(nameList[i]); + } + } + + /** + * Appends an interface to the + * interfaces implemented by the class. + */ + public void addInterface(String name) { + int info = constPool.addClassInfo(name); + if (interfaces == null) { + interfaces = new int[1]; + interfaces[0] = info; + } + else { + int n = interfaces.length; + int[] newarray = new int[n + 1]; + System.arraycopy(interfaces, 0, newarray, 0, n); + newarray[n] = info; + interfaces = newarray; + } + } + + /** + * Returns all the fields declared in the class. + * + * @return a list of <code>FieldInfo</code>. + * @see FieldInfo + */ + public List getFields() { + return fields; + } + + /** + * Appends a field to the class. + */ + public void addField(FieldInfo finfo) throws CannotCompileException { + testExistingField(finfo.getName(), finfo.getDescriptor()); + fields.add(finfo); + } + + private void addField0(FieldInfo finfo) { + fields.add(finfo); + } + + private void testExistingField(String name, String descriptor) + throws CannotCompileException + { + ListIterator it = fields.listIterator(0); + while (it.hasNext()) { + FieldInfo minfo = (FieldInfo)it.next(); + if (minfo.getName().equals(name)) + throw new CannotCompileException("duplicate field: " + name); + } + } + + /** + * Returns all the methods declared in the class. + * + * @return a list of <code>MethodInfo</code>. + * @see MethodInfo + */ + public List getMethods() { + return methods; + } + + /** + * Returns the method with the specified name. If there are multiple + * methods with that name, this method returns one of them. + * + * @return null if no such a method is found. + */ + public MethodInfo getMethod(String name) { + LinkedList list = methods; + int n = list.size(); + for (int i = 0; i < n; ++i) { + MethodInfo minfo = (MethodInfo)list.get(i); + if (minfo.getName().equals(name)) + return minfo; + } + + return null; + } + + /** + * Returns a static initializer (class initializer), or null if + * it does not exist. + */ + public MethodInfo getStaticInitializer() { + return getMethod(MethodInfo.nameClinit); + } + + /** + * Appends a method to the class. + */ + public void addMethod(MethodInfo minfo) throws CannotCompileException { + testExistingMethod(minfo.getName(), minfo.getDescriptor()); + methods.add(minfo); + } + + private void addMethod0(MethodInfo minfo) { + methods.add(minfo); + } + + private void testExistingMethod(String name, String descriptor) + throws CannotCompileException + { + ListIterator it = methods.listIterator(0); + while (it.hasNext()) { + MethodInfo minfo = (MethodInfo)it.next(); + if (minfo.getName().equals(name) + && Descriptor.eqSignature(minfo.getDescriptor(), descriptor)) + throw new CannotCompileException("duplicate method: " + name); + } + } + + /** + * Returns all the attributes. + * + * @return a list of <code>AttributeInfo</code> objects. + * @see AttributeInfo + */ + public List getAttributes() { + return attributes; + } + + /** + * Create an empty (null) attribute "RuntimeInvisibleAnnotations" + * Usually used so that you can start adding annotations to a particular thing + */ + public void createRuntimeInvisibleGroup() { + if (runtimeInvisible == null) { + AttributeInfo attr = + new AttributeInfo(constPool, "RuntimeInvisibleAnnotations"); + addAttribute(attr); + runtimeInvisible = new AnnotationGroup(attr); + } + } + + /** + * Create an empty (null) attribute "RuntimeVisibleAnnotations" + * Usually used so that you can start adding annotations to a particular thing + */ + public void createRuntimeVisibleGroup() { + if (runtimeVisible == null) { + AttributeInfo attr = + new AttributeInfo(constPool, "RuntimeVisibleAnnotations"); + addAttribute(attr); + runtimeVisible = new AnnotationGroup(attr); + } + } + + /** + * Return access object for getting info about annotations + * This returns runtime invisible annotations as pertains to the + * CLASS RetentionPolicy + * @return + */ + public AnnotationGroup getRuntimeInvisibleAnnotations() { + if (runtimeInvisible != null) + return runtimeInvisible; + AttributeInfo invisible = getAttribute("RuntimeInvisibleAnnotations"); + if (invisible == null) + return null; + runtimeInvisible = new AnnotationGroup(invisible); + return runtimeInvisible; + } + + /** + * Return access object for getting info about annotations + * This returns runtime visible annotations as pertains to the + * RUNTIME RetentionPolicy + * @return + */ + public AnnotationGroup getRuntimeVisibleAnnotations() { + if (runtimeVisible != null) + return runtimeVisible; + AttributeInfo visible = getAttribute("RuntimeVisibleAnnotations"); + if (visible == null) + return null; + runtimeVisible = new AnnotationGroup(visible); + return runtimeVisible; + } + + /** + * Returns the attribute with the specified name. + * + * @param name attribute name + */ + public AttributeInfo getAttribute(String name) { + LinkedList list = attributes; + int n = list.size(); + for (int i = 0; i < n; ++i) { + AttributeInfo ai = (AttributeInfo)list.get(i); + if (ai.getName().equals(name)) + return ai; + } + + return null; + } + + /** + * Appends an attribute. If there is already an attribute with + * the same name, the new one substitutes for it. + */ + public void addAttribute(AttributeInfo info) { + AttributeInfo.remove(attributes, info.getName()); + attributes.add(info); + } + + /** + * Returns the source file containing this class. + * + * @return null if this information is not available. + */ + public String getSourceFile() { + SourceFileAttribute sf + = (SourceFileAttribute)getAttribute(SourceFileAttribute.tag); + if (sf == null) + return null; + else + return sf.getFileName(); + } + + private void read(DataInputStream in) throws IOException { + int i, n; + int magic = in.readInt(); + if (magic != 0xCAFEBABE) + throw new IOException("non class file"); + + int major = in.readUnsignedShort(); + int minor = in.readUnsignedShort(); + constPool = new ConstPool(in); + accessFlags = in.readUnsignedShort(); + thisClass = in.readUnsignedShort(); + constPool.setThisClassInfo(thisClass); + superClass = in.readUnsignedShort(); + n = in.readUnsignedShort(); + if (n == 0) + interfaces = null; + else { + interfaces = new int[n]; + for (i = 0; i < n; ++i) + interfaces[i] = in.readUnsignedShort(); + } + + ConstPool cp = constPool; + n = in.readUnsignedShort(); + fields = new LinkedList(); + for (i = 0; i < n; ++i) + addField0(new FieldInfo(cp, in)); + + n = in.readUnsignedShort(); + methods = new LinkedList(); + for (i = 0; i < n; ++i) + addMethod0(new MethodInfo(cp, in)); + + attributes = new LinkedList(); + n = in.readUnsignedShort(); + for (i = 0; i < n; ++i) + addAttribute(AttributeInfo.read(cp, in)); + + thisclassname = constPool.getClassInfo(thisClass); + } + + /** + * Writes a class file represened by this object + * into an output stream. + */ + public void write(DataOutputStream out) throws IOException { + int i, n; + + out.writeInt(0xCAFEBABE); // magic + out.writeShort(3); // major version + out.writeShort(45); // minor version + constPool.write(out); // constant pool + out.writeShort(accessFlags); + out.writeShort(thisClass); + out.writeShort(superClass); + + if (interfaces == null) + n = 0; + else + n = interfaces.length; + + out.writeShort(n); + for (i = 0; i < n; ++i) + out.writeShort(interfaces[i]); + + LinkedList list = fields; + n = list.size(); + out.writeShort(n); + for (i = 0; i < n; ++i) { + FieldInfo finfo = (FieldInfo)list.get(i); + finfo.write(out); + } + + list = methods; + n = list.size(); + out.writeShort(n); + for (i = 0; i < n; ++i) { + MethodInfo minfo = (MethodInfo)list.get(i); + minfo.write(out); + } + + out.writeShort(attributes.size()); + AttributeInfo.writeAll(attributes, out); + } } |