diff options
author | patriot1burke <patriot1burke@30ef5769-5b8d-40dd-aea6-55b5d6557bb3> | 2004-04-03 02:11:24 +0000 |
---|---|---|
committer | patriot1burke <patriot1burke@30ef5769-5b8d-40dd-aea6-55b5d6557bb3> | 2004-04-03 02:11:24 +0000 |
commit | ed96cc41015dae453237abc3934c2570e770bf53 (patch) | |
tree | a85a78911d6cb464dd571f3b53fe93bb22552e7c | |
parent | 98cf25f68b5aef0df53b6778644d6e41702de8bc (diff) | |
download | javassist-ed96cc41015dae453237abc3934c2570e770bf53.tar.gz javassist-ed96cc41015dae453237abc3934c2570e770bf53.zip |
added annotation support. Only Enum types not supported when adding
annotations. This will also work on JDK 1.4. Well, it should.
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@75 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
19 files changed, 2362 insertions, 1006 deletions
diff --git a/src/main/javassist/bytecode/ClassFile.java b/src/main/javassist/bytecode/ClassFile.java index aa8fefd6..b156176d 100644 --- a/src/main/javassist/bytecode/ClassFile.java +++ b/src/main/javassist/bytecode/ClassFile.java @@ -22,7 +22,9 @@ import java.util.Map; import java.util.LinkedList; import java.util.ListIterator; import java.util.List; + import javassist.CannotCompileException; +import javassist.bytecode.annotation.AnnotationGroup; /** * <code>ClassFile</code> represents a Java <code>.class</code> file, @@ -30,518 +32,636 @@ import javassist.CannotCompileException; * * @see javassist.CtClass#getClassFile() */ -public final class ClassFile { - ConstPool constPool; - int thisClass; - int accessFlags; - int superClass; - int[] interfaces; - LinkedList fields; - LinkedList methods; - LinkedList attributes; - - 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; } - - /** - * 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); + } } diff --git a/src/main/javassist/bytecode/FieldInfo.java b/src/main/javassist/bytecode/FieldInfo.java index b5c39987..6bb937e2 100644 --- a/src/main/javassist/bytecode/FieldInfo.java +++ b/src/main/javassist/bytecode/FieldInfo.java @@ -15,6 +15,8 @@ package javassist.bytecode; +import javassist.bytecode.annotation.AnnotationGroup; + import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; @@ -26,149 +28,228 @@ import java.util.LinkedList; * * @see javassist.CtField#getFieldInfo() */ -public final class FieldInfo { - ConstPool constPool; - int accessFlags; - int name; - int descriptor; - LinkedList attribute; // may be null. - - private FieldInfo(ConstPool cp) { - constPool = cp; - accessFlags = 0; - attribute = null; - } - - /** - * Constructs a <code>field_info</code> structure. - * - * @param cp a constant pool table - * @param fieldName field name - * @param desc field descriptor - * - * @see Descriptor - */ - public FieldInfo(ConstPool cp, String fieldName, String desc) { - this(cp); - name = cp.addUtf8Info(fieldName); - descriptor = cp.addUtf8Info(desc); - } - - FieldInfo(ConstPool cp, DataInputStream in) throws IOException { - this(cp); - read(in); - } - - /** - * Returns the constant pool table used - * by this <code>field_info</code>. - */ - public ConstPool getConstPool() { return constPool; } - - /** - * Returns the field name. - */ - public String getName() { - return constPool.getUtf8Info(name); - } - - /** - * Sets the field name. - */ - public void setName(String newName) { - name = constPool.addUtf8Info(newName); - } - - /** - * Returns the access flags. - * - * @see AccessFlag - */ - public int getAccessFlags() { - return accessFlags; - } - - /** - * Sets the access flags. - * - * @see AccessFlag - */ - public void setAccessFlags(int acc) { - accessFlags = acc; - } - - /** - * Returns the field descriptor. - * - * @see Descriptor - */ - public String getDescriptor() { - return constPool.getUtf8Info(descriptor); - } - - /** - * Sets the field descriptor. - * - * @see Descriptor - */ - public void setDescriptor(String desc) { - if (!desc.equals(getDescriptor())) - descriptor = constPool.addUtf8Info(desc); - } - - /** - * Returns all the attributes. - * - * @return a list of <code>AttributeInfo</code> objects. - * @see AttributeInfo - */ - public List getAttributes() { - if (attribute == null) - attribute = new LinkedList(); - - return attribute; - } - - /** - * Returns the attribute with the specified name. - * - * @param name attribute name - */ - public AttributeInfo getAttribute(String name) { - return AttributeInfo.lookup(attribute, name); - } - - /** - * Appends an attribute. If there is already an attribute with - * the same name, the new one substitutes for it. - */ - public void addAttribute(AttributeInfo info) { - if (attribute == null) - attribute = new LinkedList(); - - AttributeInfo.remove(attribute, info.getName()); - attribute.add(info); - } - - private void read(DataInputStream in) throws IOException { - accessFlags = in.readUnsignedShort(); - name = in.readUnsignedShort(); - descriptor = in.readUnsignedShort(); - int n = in.readUnsignedShort(); - attribute = new LinkedList(); - for (int i = 0; i < n; ++i) - attribute.add(AttributeInfo.read(constPool, in)); - } - - void write(DataOutputStream out) throws IOException { - out.writeShort(accessFlags); - out.writeShort(name); - out.writeShort(descriptor); - if (attribute == null) - out.writeShort(0); - else { - out.writeShort(attribute.size()); - AttributeInfo.writeAll(attribute, out); - } - } +public final class FieldInfo +{ + ConstPool constPool; + int accessFlags; + int name; + int descriptor; + LinkedList attribute; // may be null. + AnnotationGroup runtimeInvisible; + AnnotationGroup runtimeVisible; + + private FieldInfo(ConstPool cp) + { + constPool = cp; + accessFlags = 0; + attribute = null; + } + + /** + * Constructs a <code>field_info</code> structure. + * + * @param cp a constant pool table + * @param fieldName field name + * @param desc field descriptor + * + * @see Descriptor + */ + public FieldInfo(ConstPool cp, String fieldName, String desc) + { + this(cp); + name = cp.addUtf8Info(fieldName); + descriptor = cp.addUtf8Info(desc); + } + + FieldInfo(ConstPool cp, DataInputStream in) throws IOException + { + this(cp); + read(in); + } + + /** + * Returns the constant pool table used + * by this <code>field_info</code>. + */ + public ConstPool getConstPool() + { + return constPool; + } + + /** + * Returns the field name. + */ + public String getName() + { + return constPool.getUtf8Info(name); + } + + /** + * Sets the field name. + */ + public void setName(String newName) + { + name = constPool.addUtf8Info(newName); + } + + /** + * Returns the access flags. + * + * @see AccessFlag + */ + public int getAccessFlags() + { + return accessFlags; + } + + /** + * Sets the access flags. + * + * @see AccessFlag + */ + public void setAccessFlags(int acc) + { + accessFlags = acc; + } + + /** + * Returns the field descriptor. + * + * @see Descriptor + */ + public String getDescriptor() + { + return constPool.getUtf8Info(descriptor); + } + + /** + * Sets the field descriptor. + * + * @see Descriptor + */ + public void setDescriptor(String desc) + { + if (!desc.equals(getDescriptor())) + descriptor = constPool.addUtf8Info(desc); + } + + /** + * Returns all the attributes. + * + * @return a list of <code>AttributeInfo</code> objects. + * @see AttributeInfo + */ + public List getAttributes() + { + if (attribute == null) + attribute = new LinkedList(); + + return attribute; + } + + /** + * Returns the attribute with the specified name. + * + * @param name attribute name + */ + public AttributeInfo getAttribute(String name) + { + return AttributeInfo.lookup(attribute, name); + } + + /** + * Appends an attribute. If there is already an attribute with + * the same name, the new one substitutes for it. + */ + public void addAttribute(AttributeInfo info) + { + if (attribute == null) + attribute = new LinkedList(); + + AttributeInfo.remove(attribute, info.getName()); + attribute.add(info); + } + + /** + * 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; + } + + private void read(DataInputStream in) throws IOException + { + accessFlags = in.readUnsignedShort(); + name = in.readUnsignedShort(); + descriptor = in.readUnsignedShort(); + int n = in.readUnsignedShort(); + attribute = new LinkedList(); + for (int i = 0; i < n; ++i) + attribute.add(AttributeInfo.read(constPool, in)); + } + + void write(DataOutputStream out) throws IOException + { + out.writeShort(accessFlags); + out.writeShort(name); + out.writeShort(descriptor); + if (attribute == null) + out.writeShort(0); + else + { + out.writeShort(attribute.size()); + AttributeInfo.writeAll(attribute, out); + } + } } diff --git a/src/main/javassist/bytecode/MethodInfo.java b/src/main/javassist/bytecode/MethodInfo.java index 5e8113fa..ff887ff4 100644 --- a/src/main/javassist/bytecode/MethodInfo.java +++ b/src/main/javassist/bytecode/MethodInfo.java @@ -15,6 +15,8 @@ package javassist.bytecode; +import javassist.bytecode.annotation.AnnotationGroup; + import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; @@ -28,351 +30,444 @@ import java.util.LinkedList; * @see javassist.CtMethod#getMethodInfo() * @see javassist.CtConstructor#getMethodInfo() */ -public final class MethodInfo { - ConstPool constPool; - int accessFlags; - int name; - int descriptor; - LinkedList attribute; // may be null - - /** - * The name of constructors: <code><init></code>. - */ - public static final String nameInit = "<init>"; - - /** - * The name of class initializer (static initializer): - * <code><clinit></code>. - */ - public static final String nameClinit = "<clinit>"; - - private MethodInfo(ConstPool cp) { - constPool = cp; - attribute = null; - } - - /** - * Constructs a <code>method_info</code> structure. - * - * @param cp a constant pool table - * @param methodname method name - * @param desc method descriptor - * - * @see Descriptor - */ - public MethodInfo(ConstPool cp, String methodname, String desc) { - this(cp); - accessFlags = 0; - name = cp.addUtf8Info(methodname); - descriptor = constPool.addUtf8Info(desc); - } - - MethodInfo(ConstPool cp, DataInputStream in) throws IOException { - this(cp); - read(in); - } - - /** - * Constructs a copy of <code>method_info</code> structure. - * Class names appearing in the source <code>method_info</code> - * are renamed according to <code>classnameMap</code>. - * - * <p>Note: only <code>Code</code> and <code>Exceptions</code> - * attributes are copied from the source. The other attributes - * are ignored. - * - * @param cp a constant pool table - * @param methodname a method name - * @param src a source <code>method_info</code> - * @param classnameMap specifies pairs of replaced and substituted - * name. - * @see Descriptor - */ - public MethodInfo(ConstPool cp, String methodname, MethodInfo src, - Map classnameMap) throws BadBytecode - { - this(cp); - read(src, methodname, classnameMap); - } - - /** - * Returns a method name. - */ - public String getName() { - return constPool.getUtf8Info(name); - } - - /** - * Sets a method name. - */ - public void setName(String newName) { - name = constPool.addUtf8Info(newName); - } - - /** - * Returns true if this is not a constructor or a class initializer - * (static initializer). - */ - public boolean isMethod() { - String n = getName(); - return !n.equals(nameInit) && !n.equals(nameClinit); - } - - /** - * Returns a constant pool table used by this method. - */ - public ConstPool getConstPool() { return constPool; } - - /** - * Returns true if this is a constructor. - */ - public boolean isConstructor() { return getName().equals(nameInit); } - - /** - * Returns true if this is a class initializer (static initializer). - */ - public boolean isStaticInitializer() { - return getName().equals(nameClinit); - } - - /** - * Returns access flags. - * - * @see AccessFlag - */ - public int getAccessFlags() { - return accessFlags; - } - - /** - * Sets access flags. - * - * @see AccessFlag - */ - public void setAccessFlags(int acc) { - accessFlags = acc; - } - - /** - * Returns a method descriptor. - * - * @see Descriptor - */ - public String getDescriptor() { - return constPool.getUtf8Info(descriptor); - } - - /** - * Sets a method descriptor. - * - * @see Descriptor - */ - public void setDescriptor(String desc) { - if (!desc.equals(getDescriptor())) - descriptor = constPool.addUtf8Info(desc); - } - - /** - * Returns all the attributes. - * - * @return a list of <code>AttributeInfo</code> objects. - * @see AttributeInfo - */ - public List getAttributes() { - if (attribute == null) - attribute = new LinkedList(); - - return attribute; - } - - /** - * Returns the attribute with the specified name. - * If it is not found, this method returns null. - * - * @param name attribute name - * @return an <code>AttributeInfo</code> object or null. - */ - public AttributeInfo getAttribute(String name) { - return AttributeInfo.lookup(attribute, name); - } - - /** - * Appends an attribute. If there is already an attribute with - * the same name, the new one substitutes for it. - */ - public void addAttribute(AttributeInfo info) { - if (attribute == null) - attribute = new LinkedList(); - - AttributeInfo.remove(attribute, info.getName()); - attribute.add(info); - } - - /** - * Returns an Exceptions attribute. - * - * @return an Exceptions attribute - * or null if it is not specified. - */ - public ExceptionsAttribute getExceptionsAttribute() { - AttributeInfo info - = AttributeInfo.lookup(attribute, ExceptionsAttribute.class); - return (ExceptionsAttribute)info; - } - - /** - * Returns a Code attribute. - * - * @return a Code attribute - * or null if it is not specified. - */ - public CodeAttribute getCodeAttribute() { - AttributeInfo info - = AttributeInfo.lookup(attribute, CodeAttribute.class); - return (CodeAttribute)info; - } - - /** - * Removes an Exception attribute. - */ - public void removeExceptionsAttribute() { - AttributeInfo.remove(attribute, ExceptionsAttribute.class); - } - - /** - * Adds an Exception attribute. - * - * <p>The added attribute must share the same constant pool table - * as this <code>method_info</code> structure. - */ - public void setExceptionsAttribute(ExceptionsAttribute cattr) { - removeExceptionsAttribute(); - if (attribute == null) - attribute = new LinkedList(); - - attribute.add(cattr); - } - - /** - * Removes a Code attribute. - */ - public void removeCodeAttribute() { - AttributeInfo.remove(attribute, CodeAttribute.class); - } - - /** - * Adds a Code attribute. - * - * <p>The added attribute must share the same constant pool table - * as this <code>method_info</code> structure. - */ - public void setCodeAttribute(CodeAttribute cattr) { - removeCodeAttribute(); - if (attribute == null) - attribute = new LinkedList(); - - attribute.add(cattr); - } - - /** - * Returns the line number of the source line corresponding to the - * specified bytecode contained in this method. - * - * @param pos the position of the bytecode (>= 0). - * an index into the code array. - * @return -1 if this information is not available. - */ - public int getLineNumber(int pos) { - CodeAttribute ca = getCodeAttribute(); - if (ca == null) - return -1; - - LineNumberAttribute ainfo - = (LineNumberAttribute)ca.getAttribute(LineNumberAttribute.tag); - if (ainfo == null) - return -1; - - return ainfo.toLineNumber(pos); - } - - /** - * Changes a super constructor called by this constructor. - * - * <p>This method modifies a call to <code>super()</code>, - * which should be at the - * head of a constructor body, so that a constructor in a different - * super class is called. This method does not change actural - * parameters. Hence the new super class must have a constructor - * with the same signature as the original one. - * - * <p>This method should be called when the super class - * of the class declaring this method is changed. - * - * <p>This method does not perform anything unless this - * <code>MethodInfo</code> represents a constructor. - * - * @param superclass the new super class - */ - public void setSuperclass(String superclass) throws BadBytecode { - if (!isConstructor()) - return; - - CodeAttribute ca = getCodeAttribute(); - byte[] code = ca.getCode(); - CodeIterator iterator = ca.iterator(); - int pos = iterator.skipSuperConstructor(); - if (pos >= 0) { // not this() - ConstPool cp = constPool; - int mref = ByteArray.readU16bit(code, pos + 1); - int nt = cp.getMethodrefNameAndType(mref); - int sc = cp.addClassInfo(superclass); - int mref2 = cp.addMethodrefInfo(sc, nt); - ByteArray.write16bit(mref2, code, pos + 1); - } - } - - private void read(MethodInfo src, String methodname, Map classnames) - throws BadBytecode - { - ConstPool destCp = constPool; - accessFlags = src.accessFlags; - name = destCp.addUtf8Info(methodname); - - ConstPool srcCp = src.constPool; - String desc = srcCp.getUtf8Info(src.descriptor); - String desc2 = Descriptor.rename(desc, classnames); - descriptor = destCp.addUtf8Info(desc2); - - attribute = new LinkedList(); - ExceptionsAttribute eattr = src.getExceptionsAttribute(); - if (eattr != null) - attribute.add(eattr.copy(destCp, classnames)); - - CodeAttribute cattr = src.getCodeAttribute(); - if (cattr != null) - attribute.add(cattr.copy(destCp, classnames)); - } - - private void read(DataInputStream in) throws IOException { - accessFlags = in.readUnsignedShort(); - name = in.readUnsignedShort(); - descriptor = in.readUnsignedShort(); - int n = in.readUnsignedShort(); - attribute = new LinkedList(); - for (int i = 0; i < n; ++i) - attribute.add(AttributeInfo.read(constPool, in)); - } - - void write(DataOutputStream out) throws IOException { - out.writeShort(accessFlags); - out.writeShort(name); - out.writeShort(descriptor); - - if (attribute == null) - out.writeShort(0); - else { - out.writeShort(attribute.size()); - AttributeInfo.writeAll(attribute, out); - } - } +public final class MethodInfo +{ + ConstPool constPool; + int accessFlags; + int name; + int descriptor; + LinkedList attribute; // may be null + AnnotationGroup runtimeInvisible; + AnnotationGroup runtimeVisible; + + /** + * The name of constructors: <code><init></code>. + */ + public static final String nameInit = "<init>"; + + /** + * The name of class initializer (static initializer): + * <code><clinit></code>. + */ + public static final String nameClinit = "<clinit>"; + + private MethodInfo(ConstPool cp) + { + constPool = cp; + attribute = null; + } + + /** + * Constructs a <code>method_info</code> structure. + * + * @param cp a constant pool table + * @param methodname method name + * @param desc method descriptor + * + * @see Descriptor + */ + public MethodInfo(ConstPool cp, String methodname, String desc) + { + this(cp); + accessFlags = 0; + name = cp.addUtf8Info(methodname); + descriptor = constPool.addUtf8Info(desc); + } + + MethodInfo(ConstPool cp, DataInputStream in) throws IOException + { + this(cp); + read(in); + } + + /** + * Constructs a copy of <code>method_info</code> structure. + * Class names appearing in the source <code>method_info</code> + * are renamed according to <code>classnameMap</code>. + * + * <p>Note: only <code>Code</code> and <code>Exceptions</code> + * attributes are copied from the source. The other attributes + * are ignored. + * + * @param cp a constant pool table + * @param methodname a method name + * @param src a source <code>method_info</code> + * @param classnameMap specifies pairs of replaced and substituted + * name. + * @see Descriptor + */ + public MethodInfo(ConstPool cp, String methodname, MethodInfo src, + Map classnameMap) throws BadBytecode + { + this(cp); + read(src, methodname, classnameMap); + } + + /** + * Returns a method name. + */ + public String getName() + { + return constPool.getUtf8Info(name); + } + + /** + * Sets a method name. + */ + public void setName(String newName) + { + name = constPool.addUtf8Info(newName); + } + + /** + * Returns true if this is not a constructor or a class initializer + * (static initializer). + */ + public boolean isMethod() + { + String n = getName(); + return !n.equals(nameInit) && !n.equals(nameClinit); + } + + /** + * Returns a constant pool table used by this method. + */ + public ConstPool getConstPool() + { + return constPool; + } + + /** + * Returns true if this is a constructor. + */ + public boolean isConstructor() + { + return getName().equals(nameInit); + } + + /** + * Returns true if this is a class initializer (static initializer). + */ + public boolean isStaticInitializer() + { + return getName().equals(nameClinit); + } + + /** + * Returns access flags. + * + * @see AccessFlag + */ + public int getAccessFlags() + { + return accessFlags; + } + + /** + * Sets access flags. + * + * @see AccessFlag + */ + public void setAccessFlags(int acc) + { + accessFlags = acc; + } + + /** + * Returns a method descriptor. + * + * @see Descriptor + */ + public String getDescriptor() + { + return constPool.getUtf8Info(descriptor); + } + + /** + * Sets a method descriptor. + * + * @see Descriptor + */ + public void setDescriptor(String desc) + { + if (!desc.equals(getDescriptor())) + descriptor = constPool.addUtf8Info(desc); + } + + /** + * Returns all the attributes. + * + * @return a list of <code>AttributeInfo</code> objects. + * @see AttributeInfo + */ + public List getAttributes() + { + if (attribute == null) + attribute = new LinkedList(); + + return attribute; + } + + /** + * Returns the attribute with the specified name. + * If it is not found, this method returns null. + * + * @param name attribute name + * @return an <code>AttributeInfo</code> object or null. + */ + public AttributeInfo getAttribute(String name) + { + return AttributeInfo.lookup(attribute, name); + } + + /** + * Appends an attribute. If there is already an attribute with + * the same name, the new one substitutes for it. + */ + public void addAttribute(AttributeInfo info) + { + if (attribute == null) + attribute = new LinkedList(); + + AttributeInfo.remove(attribute, info.getName()); + attribute.add(info); + } + + /** + * 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 an Exceptions attribute. + * + * @return an Exceptions attribute + * or null if it is not specified. + */ + public ExceptionsAttribute getExceptionsAttribute() + { + AttributeInfo info + = AttributeInfo.lookup(attribute, ExceptionsAttribute.class); + return (ExceptionsAttribute) info; + } + + /** + * Returns a Code attribute. + * + * @return a Code attribute + * or null if it is not specified. + */ + public CodeAttribute getCodeAttribute() + { + AttributeInfo info + = AttributeInfo.lookup(attribute, CodeAttribute.class); + return (CodeAttribute) info; + } + + /** + * Removes an Exception attribute. + */ + public void removeExceptionsAttribute() + { + AttributeInfo.remove(attribute, ExceptionsAttribute.class); + } + + /** + * Adds an Exception attribute. + * + * <p>The added attribute must share the same constant pool table + * as this <code>method_info</code> structure. + */ + public void setExceptionsAttribute(ExceptionsAttribute cattr) + { + removeExceptionsAttribute(); + if (attribute == null) + attribute = new LinkedList(); + + attribute.add(cattr); + } + + /** + * Removes a Code attribute. + */ + public void removeCodeAttribute() + { + AttributeInfo.remove(attribute, CodeAttribute.class); + } + + /** + * Adds a Code attribute. + * + * <p>The added attribute must share the same constant pool table + * as this <code>method_info</code> structure. + */ + public void setCodeAttribute(CodeAttribute cattr) + { + removeCodeAttribute(); + if (attribute == null) + attribute = new LinkedList(); + + attribute.add(cattr); + } + + /** + * Returns the line number of the source line corresponding to the + * specified bytecode contained in this method. + * + * @param pos the position of the bytecode (>= 0). + * an index into the code array. + * @return -1 if this information is not available. + */ + public int getLineNumber(int pos) + { + CodeAttribute ca = getCodeAttribute(); + if (ca == null) + return -1; + + LineNumberAttribute ainfo + = (LineNumberAttribute) ca.getAttribute(LineNumberAttribute.tag); + if (ainfo == null) + return -1; + + return ainfo.toLineNumber(pos); + } + + /** + * Changes a super constructor called by this constructor. + * + * <p>This method modifies a call to <code>super()</code>, + * which should be at the + * head of a constructor body, so that a constructor in a different + * super class is called. This method does not change actural + * parameters. Hence the new super class must have a constructor + * with the same signature as the original one. + * + * <p>This method should be called when the super class + * of the class declaring this method is changed. + * + * <p>This method does not perform anything unless this + * <code>MethodInfo</code> represents a constructor. + * + * @param superclass the new super class + */ + public void setSuperclass(String superclass) throws BadBytecode + { + if (!isConstructor()) + return; + + CodeAttribute ca = getCodeAttribute(); + byte[] code = ca.getCode(); + CodeIterator iterator = ca.iterator(); + int pos = iterator.skipSuperConstructor(); + if (pos >= 0) + { // not this() + ConstPool cp = constPool; + int mref = ByteArray.readU16bit(code, pos + 1); + int nt = cp.getMethodrefNameAndType(mref); + int sc = cp.addClassInfo(superclass); + int mref2 = cp.addMethodrefInfo(sc, nt); + ByteArray.write16bit(mref2, code, pos + 1); + } + } + + private void read(MethodInfo src, String methodname, Map classnames) + throws BadBytecode + { + ConstPool destCp = constPool; + accessFlags = src.accessFlags; + name = destCp.addUtf8Info(methodname); + + ConstPool srcCp = src.constPool; + String desc = srcCp.getUtf8Info(src.descriptor); + String desc2 = Descriptor.rename(desc, classnames); + descriptor = destCp.addUtf8Info(desc2); + + attribute = new LinkedList(); + ExceptionsAttribute eattr = src.getExceptionsAttribute(); + if (eattr != null) + attribute.add(eattr.copy(destCp, classnames)); + + CodeAttribute cattr = src.getCodeAttribute(); + if (cattr != null) + attribute.add(cattr.copy(destCp, classnames)); + } + + private void read(DataInputStream in) throws IOException + { + accessFlags = in.readUnsignedShort(); + name = in.readUnsignedShort(); + descriptor = in.readUnsignedShort(); + int n = in.readUnsignedShort(); + attribute = new LinkedList(); + for (int i = 0; i < n; ++i) + attribute.add(AttributeInfo.read(constPool, in)); + } + + void write(DataOutputStream out) throws IOException + { + out.writeShort(accessFlags); + out.writeShort(name); + out.writeShort(descriptor); + + if (attribute == null) + out.writeShort(0); + else + { + out.writeShort(attribute.size()); + AttributeInfo.writeAll(attribute, out); + } + } } diff --git a/src/main/javassist/bytecode/annotation/AnnotationGroup.java b/src/main/javassist/bytecode/annotation/AnnotationGroup.java new file mode 100644 index 00000000..82ba92b3 --- /dev/null +++ b/src/main/javassist/bytecode/annotation/AnnotationGroup.java @@ -0,0 +1,124 @@ +/* + * JBoss, the OpenSource J2EE webOS + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package javassist.bytecode.annotation; + +import javassist.bytecode.AttributeInfo; +import javassist.bytecode.ConstPool; + +import java.io.DataInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.List; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.Collection; +import java.util.Iterator; + +/** + * Comment + * + * @author <a href="mailto:bill@jboss.org">Bill Burke</a> + * @version $Revision: 1.1 $ + * + **/ +public class AnnotationGroup +{ + AttributeInfo parent; + LinkedHashMap annotations = new LinkedHashMap(); + public AnnotationGroup(AttributeInfo parent) + { + this.parent = parent; + if (!parent.getName().equals("RuntimeInvisibleAnnotations") && + !parent.getName().equals("RuntimeVisibleAnnotations")) + throw new RuntimeException("Annotation group must be RuntimeInvisibleAnnotations or RuntimeVisibleAnnotations, it was: " + parent.getName()); + + try + { + initialize(); + } + catch (java.io.IOException e) + { + throw new RuntimeException(e); + } + } + + public String getName() + { + return parent.getName(); + } + + public Collection getAnnotations() + { + if (annotations == null) return null; + return annotations.values(); + } + + public AnnotationInfo getAnnotation(String type) + { + if (annotations == null) return null; + return (AnnotationInfo)annotations.get(type); + } + + private void initialize() throws java.io.IOException + { + ConstPool cp = parent.getConstPool(); + byte[] bytes = parent.get(); + if (bytes == null) return; + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + DataInputStream di = new DataInputStream(bais); + short num_annotations = di.readShort(); + for (int i = 0; i < num_annotations; i++) + { + AnnotationInfo info = AnnotationInfo.readAnnotationInfo(cp, di); + annotations.put(info.getAnnotationType(), info); + } + } + + public void addAnnotation(AnnotationInfo info) + { + annotations.put(info.getAnnotationType(), info); + try + { + parent.set(convertToBytes()); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + public void removeAnnotation(String name) + { + annotations.remove(name); + try + { + parent.set(convertToBytes()); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + private byte[] convertToBytes() throws IOException + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + short num_annotations = (short)annotations.size(); + dos.writeShort(num_annotations); + Iterator it = annotations.values().iterator(); + while (it.hasNext()) + { + AnnotationInfo info = (AnnotationInfo)it.next(); + info.write(dos); + } + dos.flush(); + return baos.toByteArray(); + } +} diff --git a/src/main/javassist/bytecode/annotation/AnnotationInfo.java b/src/main/javassist/bytecode/annotation/AnnotationInfo.java new file mode 100644 index 00000000..422b4d17 --- /dev/null +++ b/src/main/javassist/bytecode/annotation/AnnotationInfo.java @@ -0,0 +1,199 @@ +/* + * JBoss, the OpenSource J2EE webOS + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package javassist.bytecode.annotation; + +import javassist.bytecode.ConstPool; +import javassist.CtClass; +import javassist.CtMethod; +import javassist.CtPrimitiveType; + +import java.io.DataInput; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.List; +import java.util.LinkedHashMap; +import java.util.HashMap; +import java.util.Set; +import java.util.Iterator; + +/** + * Comment + * + * @author <a href="mailto:bill@jboss.org">Bill Burke</a> + * @version $Revision: 1.1 $ + * + **/ +public class AnnotationInfo +{ + short type_index; + LinkedHashMap members; + HashMap memberName2Index; + ConstPool cp; + + private AnnotationInfo() + { + + } + + /** + * todo Enums are not supported right now. + * This is for creation at runtime + * @param clazz + */ + public AnnotationInfo(ConstPool cp, CtClass clazz) throws javassist.NotFoundException + { + + if (!clazz.isInterface()) throw new RuntimeException("Only interfaces are allowed for AnnotationInfo creation."); + this.cp = cp; + type_index = (short) cp.addClassInfo(clazz); + CtMethod methods[] = clazz.getDeclaredMethods(); + if (methods.length > 0) + { + members = new LinkedHashMap(); + memberName2Index = new HashMap(); + } + for (int i = 0; i < methods.length; i++) + { + CtClass returnType = methods[i].getReturnType(); + if (returnType.equals(CtPrimitiveType.booleanType)) + { + addMemberValue(methods[i].getName(), new BooleanMemberValue((short) -1)); + } + else if (returnType.equals(CtPrimitiveType.byteType)) + { + addMemberValue(methods[i].getName(), new ByteMemberValue((short) -1)); + } + else if (returnType.equals(CtPrimitiveType.charType)) + { + addMemberValue(methods[i].getName(), new CharMemberValue((short) -1)); + } + else if (returnType.equals(CtPrimitiveType.doubleType)) + { + addMemberValue(methods[i].getName(), new DoubleMemberValue((short) -1)); + } + else if (returnType.equals(CtPrimitiveType.floatType)) + { + addMemberValue(methods[i].getName(), new FloatMemberValue((short) -1)); + } + else if (returnType.equals(CtPrimitiveType.intType)) + { + addMemberValue(methods[i].getName(), new IntegerMemberValue((short) -1)); + } + else if (returnType.equals(CtPrimitiveType.longType)) + { + addMemberValue(methods[i].getName(), new LongMemberValue((short) -1)); + } + else if (returnType.equals(CtPrimitiveType.shortType)) + { + addMemberValue(methods[i].getName(), new ShortMemberValue((short) -1)); + } + else if (returnType.getName().equals("java.lang.Class")) + { + addMemberValue(methods[i].getName(), new ClassMemberValue((short) -1)); + } + else if (returnType.getName().equals("java.lang.String") || returnType.getName().equals("String")) + { + addMemberValue(methods[i].getName(), new StringMemberValue((short) -1)); + } + else if (returnType.isArray()) + { + addMemberValue(methods[i].getName(), new ArrayMemberValue()); + } + else if (returnType.isInterface()) + { + addMemberValue(methods[i].getName(), new AnnotationMemberValue(null)); + } + else + { + throw new RuntimeException("cannot handle member type: " + returnType.getName()); + } + } + } + + private void addMemberValue(String name, MemberValue value) + { + short index = (short) cp.addUtf8Info(name); + members.put(name, value); + memberName2Index.put(name, new Short(index)); + value.cp = this.cp; + } + + public String getAnnotationType() + { + return cp.getClassInfo(type_index); + } + + public Set getMemberNames() + { + if (members == null) return null; + return members.keySet(); + } + + public MemberValue getMemberValue(String member) + { + if (members == null) return null; + return (MemberValue) members.get(member); + } + + public static AnnotationInfo readAnnotationInfo(ConstPool cp, DataInput di) throws java.io.IOException + { + AnnotationInfo info = new AnnotationInfo(); + info.cp = cp; + short type_index = di.readShort(); + info.type_index = type_index; + short num_member_value_pairs = di.readShort(); + if (num_member_value_pairs > 0) + { + info.members = new LinkedHashMap(); + info.memberName2Index = new HashMap(); + } + for (int j = 0; j < num_member_value_pairs; j++) + { + short member_name_index = di.readShort(); + String memberName = cp.getUtf8Info(member_name_index); + MemberValue value = MemberValue.readMemberValue(cp, di); + info.members.put(memberName, value); + info.memberName2Index.put(memberName, new Short(member_name_index)); + } + return info; + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeShort(type_index); + dos.writeShort(members.size()); + Iterator it = members.keySet().iterator(); + while (it.hasNext()) + { + String name = (String) it.next(); + Short index = (Short) memberName2Index.get(name); + dos.writeShort(index.shortValue()); + MemberValue value = (MemberValue) members.get(name); + value.write(dos); + } + } + + public String toString() + { + StringBuffer buf = new StringBuffer("@"); + buf.append(getAnnotationType()); + if (members != null) + { + buf.append("("); + Iterator mit = members.keySet().iterator(); + while (mit.hasNext()) + { + String name = (String) mit.next(); + buf.append(name).append("=").append(getMemberValue(name)); + if (mit.hasNext()) buf.append(", "); + } + buf.append(")"); + } + return buf.toString(); + } +} + diff --git a/src/main/javassist/bytecode/annotation/AnnotationMemberValue.java b/src/main/javassist/bytecode/annotation/AnnotationMemberValue.java new file mode 100644 index 00000000..1b55bd79 --- /dev/null +++ b/src/main/javassist/bytecode/annotation/AnnotationMemberValue.java @@ -0,0 +1,48 @@ +/* + * JBoss, the OpenSource J2EE webOS + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package javassist.bytecode.annotation; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Comment + * + * @author <a href="mailto:bill@jboss.org">Bill Burke</a> + * @version $Revision: 1.1 $ + * + **/ +public class AnnotationMemberValue extends MemberValue +{ + AnnotationInfo annotation; + public AnnotationMemberValue(AnnotationInfo a) + { + tag = '@'; + this.annotation = a; + } + + public AnnotationInfo getNestedAnnotation() + { + return annotation; + } + + public void setNestedAnnotation(AnnotationInfo info) + { + annotation = info; + } + + public String toString() + { + return annotation.toString(); + } + + public void write(DataOutputStream dos) throws IOException + { + super.write(dos); + annotation.write(dos); + } +} diff --git a/src/main/javassist/bytecode/annotation/ArrayMemberValue.java b/src/main/javassist/bytecode/annotation/ArrayMemberValue.java new file mode 100644 index 00000000..70d607ef --- /dev/null +++ b/src/main/javassist/bytecode/annotation/ArrayMemberValue.java @@ -0,0 +1,76 @@ +/* + * JBoss, the OpenSource J2EE webOS + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package javassist.bytecode.annotation; + +import javassist.bytecode.ConstPool; + +import java.io.DataInput; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; + +/** + * Comment + * + * @author <a href="mailto:bill@jboss.org">Bill Burke</a> + * @version $Revision: 1.1 $ + * + **/ +public class ArrayMemberValue extends MemberValue +{ + MemberValue[] values; + public ArrayMemberValue() + { + tag = '['; + } + + public MemberValue[] getValue() + { + return values; + } + + public void setValue(MemberValue[] values) + { + this.values = values; + } + + + public static ArrayMemberValue readArray(ConstPool cp, DataInput di) throws java.io.IOException + { + ArrayMemberValue rtn = new ArrayMemberValue(); + int length = di.readShort(); + ArrayList values = new ArrayList(length); + for (int i = 0; i < length; i++) + { + values.add(MemberValue.readMemberValue(cp, di)); + } + rtn.values = (MemberValue[])values.toArray(new MemberValue[length]); + return rtn; + + } + + public void write(DataOutputStream dos) throws IOException + { + super.write(dos); + dos.writeShort(values.length); + for (int i = 0; i < values.length; i++) + { + values[i].write(dos); + } + } + public String toString() + { + StringBuffer buf = new StringBuffer("{"); + for (int i = 0; i < values.length; i++) + { + buf.append(values[i].toString()); + if (i + 1 < values.length) buf.append(", "); + } + buf.append("}"); + return buf.toString(); + } +} diff --git a/src/main/javassist/bytecode/annotation/BooleanMemberValue.java b/src/main/javassist/bytecode/annotation/BooleanMemberValue.java new file mode 100644 index 00000000..f11354d5 --- /dev/null +++ b/src/main/javassist/bytecode/annotation/BooleanMemberValue.java @@ -0,0 +1,48 @@ +/* + * JBoss, the OpenSource J2EE webOS + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package javassist.bytecode.annotation; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Comment + * + * @author <a href="mailto:bill@jboss.org">Bill Burke</a> + * @version $Revision: 1.1 $ + * + **/ +public class BooleanMemberValue extends MemberValue +{ + short const_value_index; + + public BooleanMemberValue(short cvi) + { + tag = 'Z'; + this.const_value_index = cvi; + } + + public boolean getValue() + { + return cp.getIntegerInfo(const_value_index) == 1; + } + + public void setValue(boolean newVal) + { + const_value_index = (short)cp.addIntegerInfo(newVal ? 1 : 0); + } + + public String toString() + { + return "" + getValue(); + } + public void write(DataOutputStream dos) throws IOException + { + super.write(dos); + dos.writeShort(const_value_index); + } +} diff --git a/src/main/javassist/bytecode/annotation/ByteMemberValue.java b/src/main/javassist/bytecode/annotation/ByteMemberValue.java new file mode 100644 index 00000000..b567b9bd --- /dev/null +++ b/src/main/javassist/bytecode/annotation/ByteMemberValue.java @@ -0,0 +1,48 @@ +/* + * JBoss, the OpenSource J2EE webOS + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package javassist.bytecode.annotation; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Comment + * + * @author <a href="mailto:bill@jboss.org">Bill Burke</a> + * @version $Revision: 1.1 $ + * + **/ +public class ByteMemberValue extends MemberValue +{ + short const_value_index; + + public ByteMemberValue(short const_value_index) + { + tag = 'B'; + this.const_value_index = const_value_index; + } + + public byte getValue() + { + return (byte)cp.getIntegerInfo(const_value_index); + } + + public void setValue(byte newVal) + { + const_value_index = (short)cp.addIntegerInfo(newVal); + } + + public String toString() + { + return "" + getValue(); + } + public void write(DataOutputStream dos) throws IOException + { + super.write(dos); + dos.writeShort(const_value_index); + } +} diff --git a/src/main/javassist/bytecode/annotation/CharMemberValue.java b/src/main/javassist/bytecode/annotation/CharMemberValue.java new file mode 100644 index 00000000..9d9eb17f --- /dev/null +++ b/src/main/javassist/bytecode/annotation/CharMemberValue.java @@ -0,0 +1,47 @@ +/* + * JBoss, the OpenSource J2EE webOS + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package javassist.bytecode.annotation; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Comment + * + * @author <a href="mailto:bill@jboss.org">Bill Burke</a> + * @version $Revision: 1.1 $ + * + **/ +public class CharMemberValue extends MemberValue +{ + short const_value_index; + + public CharMemberValue(short cvi) + { + tag = 'C'; + this.const_value_index = cvi; + } + + public char getValue() + { + return (char)cp.getIntegerInfo(const_value_index); + } + public void setValue(char newVal) + { + const_value_index = (short)cp.addIntegerInfo(newVal); + } + + public String toString() + { + return "" + getValue(); + } + public void write(DataOutputStream dos) throws IOException + { + super.write(dos); + dos.writeShort(const_value_index); + } +} diff --git a/src/main/javassist/bytecode/annotation/ClassMemberValue.java b/src/main/javassist/bytecode/annotation/ClassMemberValue.java new file mode 100644 index 00000000..8931eb05 --- /dev/null +++ b/src/main/javassist/bytecode/annotation/ClassMemberValue.java @@ -0,0 +1,48 @@ +/* + * JBoss, the OpenSource J2EE webOS + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package javassist.bytecode.annotation; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Comment + * + * @author <a href="mailto:bill@jboss.org">Bill Burke</a> + * @version $Revision: 1.1 $ + * + **/ +public class ClassMemberValue extends MemberValue +{ + short class_info_index; + + public ClassMemberValue(short cii) + { + tag = 'c'; + this.class_info_index = cii; + } + + public String getClassName() + { + return cp.getClassInfo(class_info_index); + } + + public void setClassName(String name) + { + class_info_index = (short)cp.addClassInfo(name); + } + + public String toString() + { + return getClassName(); + } + public void write(DataOutputStream dos) throws IOException + { + super.write(dos); + dos.writeShort(class_info_index); + } +} diff --git a/src/main/javassist/bytecode/annotation/DoubleMemberValue.java b/src/main/javassist/bytecode/annotation/DoubleMemberValue.java new file mode 100644 index 00000000..b56e4e7d --- /dev/null +++ b/src/main/javassist/bytecode/annotation/DoubleMemberValue.java @@ -0,0 +1,47 @@ +/* + * JBoss, the OpenSource J2EE webOS + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package javassist.bytecode.annotation; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Comment + * + * @author <a href="mailto:bill@jboss.org">Bill Burke</a> + * @version $Revision: 1.1 $ + * + **/ +public class DoubleMemberValue extends MemberValue +{ + short const_value_index; + + public DoubleMemberValue(short cvi) + { + tag = 'D'; + this.const_value_index = cvi; + } + + public double getValue() + { + return cp.getDoubleInfo(const_value_index); + } + public void setValue(double newVal) + { + const_value_index = (short)cp.addDoubleInfo(newVal); + } + + public String toString() + { + return "" + getValue(); + } + public void write(DataOutputStream dos) throws IOException + { + super.write(dos); + dos.writeShort(const_value_index); + } +} diff --git a/src/main/javassist/bytecode/annotation/EnumMemberValue.java b/src/main/javassist/bytecode/annotation/EnumMemberValue.java new file mode 100644 index 00000000..faf84a74 --- /dev/null +++ b/src/main/javassist/bytecode/annotation/EnumMemberValue.java @@ -0,0 +1,52 @@ +/* + * JBoss, the OpenSource J2EE webOS + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package javassist.bytecode.annotation; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Comment + * + * @author <a href="mailto:bill@jboss.org">Bill Burke</a> + * @version $Revision: 1.1 $ + * + **/ +public class EnumMemberValue extends MemberValue +{ + short type_name_index; + short const_name_index; + + public EnumMemberValue(short type, short cni) + { + tag = 'e'; + this.type_name_index = type; + this.const_name_index = cni; + } + + public String getEnumType() + { + return cp.getUtf8Info(type_name_index); + } + + public String getEnumVal() + { + return cp.getUtf8Info(const_name_index); + } + + public String toString() + { + return getEnumType() + "." + getEnumVal(); + } + + public void write(DataOutputStream dos) throws IOException + { + super.write(dos); + dos.writeShort(type_name_index); + dos.writeShort(const_name_index); + } +} diff --git a/src/main/javassist/bytecode/annotation/FloatMemberValue.java b/src/main/javassist/bytecode/annotation/FloatMemberValue.java new file mode 100644 index 00000000..d36d4b1f --- /dev/null +++ b/src/main/javassist/bytecode/annotation/FloatMemberValue.java @@ -0,0 +1,47 @@ +/* + * JBoss, the OpenSource J2EE webOS + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package javassist.bytecode.annotation; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Comment + * + * @author <a href="mailto:bill@jboss.org">Bill Burke</a> + * @version $Revision: 1.1 $ + * + **/ +public class FloatMemberValue extends MemberValue +{ + short const_value_index; + + public FloatMemberValue(short cvi) + { + tag = 'F'; + this.const_value_index = cvi; + } + + public float getValue() + { + return cp.getFloatInfo(const_value_index); + } + public void setValue(float newVal) + { + const_value_index = (short)cp.addFloatInfo(newVal); + } + + public String toString() + { + return "" + getValue(); + } + public void write(DataOutputStream dos) throws IOException + { + super.write(dos); + dos.writeShort(const_value_index); + } +} diff --git a/src/main/javassist/bytecode/annotation/IntegerMemberValue.java b/src/main/javassist/bytecode/annotation/IntegerMemberValue.java new file mode 100644 index 00000000..fbd78082 --- /dev/null +++ b/src/main/javassist/bytecode/annotation/IntegerMemberValue.java @@ -0,0 +1,48 @@ +/* + * JBoss, the OpenSource J2EE webOS + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package javassist.bytecode.annotation; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Comment + * + * @author <a href="mailto:bill@jboss.org">Bill Burke</a> + * @version $Revision: 1.1 $ + * + **/ +public class IntegerMemberValue extends MemberValue +{ + short const_value_index; + + public IntegerMemberValue(short cvi) + { + tag = 'I'; + this.const_value_index = cvi; + } + + public int getValue() + { + return cp.getIntegerInfo(const_value_index); + } + + public void setValue(int newVal) + { + const_value_index = (short)cp.addIntegerInfo(newVal); + } + + public String toString() + { + return "" + getValue(); + } + public void write(DataOutputStream dos) throws IOException + { + super.write(dos); + dos.writeShort(const_value_index); + } +} diff --git a/src/main/javassist/bytecode/annotation/LongMemberValue.java b/src/main/javassist/bytecode/annotation/LongMemberValue.java new file mode 100644 index 00000000..2922ed4f --- /dev/null +++ b/src/main/javassist/bytecode/annotation/LongMemberValue.java @@ -0,0 +1,47 @@ +/* + * JBoss, the OpenSource J2EE webOS + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package javassist.bytecode.annotation; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Comment + * + * @author <a href="mailto:bill@jboss.org">Bill Burke</a> + * @version $Revision: 1.1 $ + * + **/ +public class LongMemberValue extends MemberValue +{ + short const_value_index; + + public LongMemberValue(short cvi) + { + tag = 'J'; + this.const_value_index = cvi; + } + + public long getValue() + { + return cp.getLongInfo(const_value_index); + } + public void setValue(long newVal) + { + const_value_index = (short)cp.addLongInfo(newVal); + } + + public String toString() + { + return "" + getValue(); + } + public void write(DataOutputStream dos) throws IOException + { + super.write(dos); + dos.writeShort(const_value_index); + } +} diff --git a/src/main/javassist/bytecode/annotation/MemberValue.java b/src/main/javassist/bytecode/annotation/MemberValue.java new file mode 100644 index 00000000..b75c2f56 --- /dev/null +++ b/src/main/javassist/bytecode/annotation/MemberValue.java @@ -0,0 +1,87 @@ +/* + * JBoss, the OpenSource J2EE webOS + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package javassist.bytecode.annotation; + +import javassist.bytecode.ConstPool; + +import java.io.DataInput; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.LinkedHashMap; + +/** + * Comment + * + * @author <a href="mailto:bill@jboss.org">Bill Burke</a> + * @version $Revision: 1.1 $ + * + **/ +public abstract class MemberValue +{ + ConstPool cp; + char tag; + + + public void write(DataOutputStream dos) throws IOException + { + byte btag = (byte)tag; + dos.writeByte(btag); + } + public static MemberValue readMemberValue(ConstPool cp, DataInput di) throws java.io.IOException + { + byte btag = di.readByte(); + char tag = (char) btag; + MemberValue rtn = null; + switch (tag) + { + case 'B': + rtn = new ByteMemberValue(di.readShort()); + break; + case 'C': + rtn = new CharMemberValue(di.readShort()); + break; + case 'D': + rtn = new DoubleMemberValue(di.readShort()); + break; + case 'F': + rtn = new FloatMemberValue(di.readShort()); + break; + case 'I': + rtn = new IntegerMemberValue(di.readShort()); + break; + case 'J': + rtn = new LongMemberValue(di.readShort()); + break; + case 'S': + rtn = new ShortMemberValue(di.readShort()); + break; + case 'Z': + rtn = new BooleanMemberValue(di.readShort()); + break; + case 's': + rtn = new StringMemberValue(di.readShort()); + break; + case 'e': + rtn = new EnumMemberValue(di.readShort(), di.readShort()); + break; + case 'c': + rtn = new ClassMemberValue(di.readShort()); + break; + case '@': + rtn = new AnnotationMemberValue(AnnotationInfo.readAnnotationInfo(cp, di)); + break; + case '[': + rtn = ArrayMemberValue.readArray(cp, di); + break; + } + rtn.cp = cp; + rtn.tag = tag; + return rtn; + } +} + + diff --git a/src/main/javassist/bytecode/annotation/ShortMemberValue.java b/src/main/javassist/bytecode/annotation/ShortMemberValue.java new file mode 100644 index 00000000..82aa17ed --- /dev/null +++ b/src/main/javassist/bytecode/annotation/ShortMemberValue.java @@ -0,0 +1,47 @@ +/* + * JBoss, the OpenSource J2EE webOS + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package javassist.bytecode.annotation; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Comment + * + * @author <a href="mailto:bill@jboss.org">Bill Burke</a> + * @version $Revision: 1.1 $ + * + **/ +public class ShortMemberValue extends MemberValue +{ + short const_value_index; + + public ShortMemberValue(short cvi) + { + tag = 'S'; + this.const_value_index = cvi; + } + + public short getValue() + { + return (short)cp.getIntegerInfo(const_value_index); + } + public void setValue(short newVal) + { + const_value_index = (short)cp.addIntegerInfo(newVal); + } + + public String toString() + { + return "" + getValue(); + } + public void write(DataOutputStream dos) throws IOException + { + super.write(dos); + dos.writeShort(const_value_index); + } +} diff --git a/src/main/javassist/bytecode/annotation/StringMemberValue.java b/src/main/javassist/bytecode/annotation/StringMemberValue.java new file mode 100644 index 00000000..54cfa438 --- /dev/null +++ b/src/main/javassist/bytecode/annotation/StringMemberValue.java @@ -0,0 +1,47 @@ +/* + * JBoss, the OpenSource J2EE webOS + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package javassist.bytecode.annotation; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Comment + * + * @author <a href="mailto:bill@jboss.org">Bill Burke</a> + * @version $Revision: 1.1 $ + * + **/ +public class StringMemberValue extends MemberValue +{ + short const_value_index; + + public StringMemberValue(short cvi) + { + tag = 's'; + this.const_value_index = cvi; + } + + public String getValue() + { + return cp.getUtf8Info(const_value_index); + } + public void setValue(String newVal) + { + const_value_index = (short)cp.addUtf8Info(newVal); + } + + public String toString() + { + return "\"" + getValue() + "\""; + } + public void write(DataOutputStream dos) throws IOException + { + super.write(dos); + dos.writeShort(const_value_index); + } +} |