@@ -60,56 +60,90 @@ import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisibleParameterAnnot | |||
*/ | |||
/** | |||
* Interface to make use of the Visitor pattern programming style. | |||
* I.e. a class that implements this interface can traverse the contents of | |||
* a Java class just by calling the `accept' method which all classes have. | |||
* | |||
* Implemented by wish of | |||
* <A HREF="http://www.inf.fu-berlin.de/~bokowski">Boris Bokowski</A>. | |||
* | |||
* @version $Id: ClassVisitor.java,v 1.2 2008/05/28 23:53:01 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* Interface to make use of the Visitor pattern programming style. I.e. a class that implements this interface can traverse the | |||
* contents of a Java class just by calling the `accept' method which all classes have. | |||
* | |||
* Implemented by wish of <A HREF="http://www.inf.fu-berlin.de/~bokowski">Boris Bokowski</A>. | |||
* | |||
* @version $Id: ClassVisitor.java,v 1.3 2009/09/10 03:59:33 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
*/ | |||
public interface ClassVisitor { | |||
public void visitCode(Code obj); | |||
public void visitCodeException(CodeException obj); | |||
public void visitConstantClass(ConstantClass obj); | |||
public void visitConstantDouble(ConstantDouble obj); | |||
public void visitConstantFieldref(ConstantFieldref obj); | |||
public void visitConstantFloat(ConstantFloat obj); | |||
public void visitConstantInteger(ConstantInteger obj); | |||
public void visitConstantInterfaceMethodref(ConstantInterfaceMethodref obj); | |||
public void visitConstantLong(ConstantLong obj); | |||
public void visitConstantMethodref(ConstantMethodref obj); | |||
public void visitConstantNameAndType(ConstantNameAndType obj); | |||
public void visitConstantPool(ConstantPool obj); | |||
public void visitConstantString(ConstantString obj); | |||
public void visitConstantUtf8(ConstantUtf8 obj); | |||
public void visitConstantValue(ConstantValue obj); | |||
public void visitDeprecated(Deprecated obj); | |||
public void visitExceptionTable(ExceptionTable obj); | |||
public void visitField(Field obj); | |||
public void visitInnerClass(InnerClass obj); | |||
public void visitInnerClasses(InnerClasses obj); | |||
public void visitJavaClass(JavaClass obj); | |||
public void visitLineNumber(LineNumber obj); | |||
public void visitLineNumberTable(LineNumberTable obj); | |||
public void visitLocalVariable(LocalVariable obj); | |||
public void visitLocalVariableTable(LocalVariableTable obj); | |||
public void visitMethod(Method obj); | |||
public void visitSignature(Signature obj); | |||
public void visitSourceFile(SourceFile obj); | |||
public void visitSynthetic(Synthetic obj); | |||
public void visitUnknown(Unknown obj); | |||
public void visitStackMap(StackMap obj); | |||
public void visitStackMapEntry(StackMapEntry obj); | |||
// Java5 | |||
public void visitEnclosingMethod(EnclosingMethod obj); | |||
public void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations obj); | |||
public void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations obj); | |||
public void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations obj); | |||
public void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations obj); | |||
public void visitAnnotationDefault(AnnotationDefault obj); | |||
public void visitLocalVariableTypeTable(LocalVariableTypeTable obj); | |||
public void visitCode(Code obj); | |||
public void visitCodeException(CodeException obj); | |||
public void visitConstantClass(ConstantClass obj); | |||
public void visitConstantDouble(ConstantDouble obj); | |||
public void visitConstantFieldref(ConstantFieldref obj); | |||
public void visitConstantFloat(ConstantFloat obj); | |||
public void visitConstantInteger(ConstantInteger obj); | |||
public void visitConstantInterfaceMethodref(ConstantInterfaceMethodref obj); | |||
public void visitConstantLong(ConstantLong obj); | |||
public void visitConstantMethodref(ConstantMethodref obj); | |||
public void visitConstantNameAndType(ConstantNameAndType obj); | |||
public void visitConstantPool(ConstantPool obj); | |||
public void visitConstantString(ConstantString obj); | |||
public void visitConstantUtf8(ConstantUtf8 obj); | |||
public void visitConstantValue(ConstantValue obj); | |||
public void visitDeprecated(Deprecated obj); | |||
public void visitExceptionTable(ExceptionTable obj); | |||
public void visitField(Field obj); | |||
public void visitInnerClass(InnerClass obj); | |||
public void visitInnerClasses(InnerClasses obj); | |||
public void visitJavaClass(JavaClass obj); | |||
public void visitLineNumber(LineNumber obj); | |||
public void visitLineNumberTable(LineNumberTable obj); | |||
public void visitLocalVariable(LocalVariable obj); | |||
public void visitLocalVariableTable(LocalVariableTable obj); | |||
public void visitMethod(Method obj); | |||
public void visitSignature(Signature obj); | |||
public void visitSourceFile(SourceFile obj); | |||
public void visitSynthetic(Synthetic obj); | |||
public void visitUnknown(Unknown obj); | |||
public void visitStackMap(StackMap obj); | |||
public void visitStackMapEntry(StackMapEntry obj); | |||
public void visitEnclosingMethod(EnclosingMethod obj); | |||
public void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations obj); | |||
public void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations obj); | |||
public void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations obj); | |||
public void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations obj); | |||
public void visitAnnotationDefault(AnnotationDefault obj); | |||
public void visitLocalVariableTypeTable(LocalVariableTypeTable obj); | |||
} |
@@ -54,85 +54,91 @@ package org.aspectj.apache.bcel.classfile; | |||
* <http://www.apache.org/>. | |||
*/ | |||
import org.aspectj.apache.bcel.Constants; | |||
import java.io.*; | |||
import java.io.DataInputStream; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import java.io.Serializable; | |||
import org.aspectj.apache.bcel.Constants; | |||
/** | |||
* Abstract superclass for classes to represent the different constant types | |||
* in the constant pool of a class file. The classes keep closely to | |||
* the JVM specification. | |||
* | |||
* @version $Id: Constant.java,v 1.3 2008/05/28 23:53:01 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* Abstract superclass for classes to represent the different constant types in the constant pool of a class file. The classes keep | |||
* closely to the JVM specification. | |||
* | |||
* @version $Id: Constant.java,v 1.4 2009/09/10 03:59:33 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
*/ | |||
public abstract class Constant implements Cloneable, Node, Serializable { | |||
/* In fact this tag is redundant since we can distinguish different | |||
* `Constant' objects by their type, i.e., via `instanceof'. In some | |||
* places we will use the tag for switch()es anyway. | |||
* | |||
* First, we want match the specification as closely as possible. Second we | |||
* need the tag as an index to select the corresponding class name from the | |||
* `CONSTANT_NAMES' array. | |||
*/ | |||
protected byte tag; | |||
Constant(byte tag) { this.tag = tag; } | |||
protected byte tag; | |||
Constant(byte tag) { | |||
this.tag = tag; | |||
} | |||
/** | |||
* Called by objects that are traversing the nodes of the tree implicitely | |||
* defined by the contents of a Java class. I.e., the hierarchy of methods, | |||
* fields, attributes, etc. spawns a tree of objects. | |||
* | |||
* @param v Visitor object | |||
*/ | |||
public abstract void accept(ClassVisitor v); | |||
/** | |||
* Visitor pattern | |||
*/ | |||
public abstract void accept(ClassVisitor v); | |||
public abstract void dump(DataOutputStream file) throws IOException; | |||
/** | |||
* Serialize the constant to an output stream | |||
*/ | |||
public abstract void dump(DataOutputStream dataOutputStream) throws IOException; | |||
/** | |||
* @return Tag of constant, i.e., its type. No setTag() method to avoid | |||
* confusion. | |||
*/ | |||
public final byte getTag() { return tag; } | |||
public final byte getTag() { | |||
return tag; | |||
} | |||
/** | |||
* @return String representation. | |||
*/ | |||
public String toString() { | |||
return Constants.CONSTANT_NAMES[tag] + "[" + tag + "]"; | |||
} | |||
@Override | |||
public String toString() { | |||
return Constants.CONSTANT_NAMES[tag] + "[" + tag + "]"; | |||
} | |||
/** | |||
* @return deep copy of this constant | |||
*/ | |||
public Constant copy() { | |||
try { | |||
return (Constant)super.clone(); | |||
} catch(CloneNotSupportedException e) {} | |||
/** | |||
* @return deep copy of this constant | |||
*/ | |||
public Constant copy() { | |||
try { | |||
return (Constant) super.clone(); | |||
} catch (CloneNotSupportedException e) { | |||
} | |||
return null; | |||
} | |||
return null; | |||
} | |||
public Object clone() throws CloneNotSupportedException { | |||
return super.clone(); | |||
} | |||
@Override | |||
public Object clone() throws CloneNotSupportedException { | |||
return super.clone(); | |||
} | |||
static final Constant readConstant(DataInputStream file) throws IOException, ClassFormatException { | |||
byte b = file.readByte(); | |||
switch(b) { | |||
case Constants.CONSTANT_Class: return new ConstantClass(file); | |||
case Constants.CONSTANT_NameAndType: return new ConstantNameAndType(file); | |||
case Constants.CONSTANT_Utf8: return new ConstantUtf8(file); | |||
case Constants.CONSTANT_Fieldref: return new ConstantFieldref(file); | |||
case Constants.CONSTANT_Methodref: return new ConstantMethodref(file); | |||
case Constants.CONSTANT_InterfaceMethodref: return new ConstantInterfaceMethodref(file); | |||
case Constants.CONSTANT_String: return new ConstantString(file); | |||
case Constants.CONSTANT_Integer: return new ConstantInteger(file); | |||
case Constants.CONSTANT_Float: return new ConstantFloat(file); | |||
case Constants.CONSTANT_Long: return new ConstantLong(file); | |||
case Constants.CONSTANT_Double: return new ConstantDouble(file); | |||
default: | |||
throw new ClassFormatException("Invalid byte tag in constant pool: " + b); | |||
} | |||
} | |||
static final Constant readConstant(DataInputStream file) throws IOException, ClassFormatException { | |||
byte b = file.readByte(); | |||
switch (b) { | |||
case Constants.CONSTANT_Class: | |||
return new ConstantClass(file); | |||
case Constants.CONSTANT_NameAndType: | |||
return new ConstantNameAndType(file); | |||
case Constants.CONSTANT_Utf8: | |||
return new ConstantUtf8(file); | |||
case Constants.CONSTANT_Fieldref: | |||
return new ConstantFieldref(file); | |||
case Constants.CONSTANT_Methodref: | |||
return new ConstantMethodref(file); | |||
case Constants.CONSTANT_InterfaceMethodref: | |||
return new ConstantInterfaceMethodref(file); | |||
case Constants.CONSTANT_String: | |||
return new ConstantString(file); | |||
case Constants.CONSTANT_Integer: | |||
return new ConstantInteger(file); | |||
case Constants.CONSTANT_Float: | |||
return new ConstantFloat(file); | |||
case Constants.CONSTANT_Long: | |||
return new ConstantLong(file); | |||
case Constants.CONSTANT_Double: | |||
return new ConstantDouble(file); | |||
default: | |||
throw new ClassFormatException("Invalid byte tag in constant pool: " + b); | |||
} | |||
} | |||
} |
@@ -54,103 +54,64 @@ package org.aspectj.apache.bcel.classfile; | |||
* <http://www.apache.org/>. | |||
*/ | |||
import org.aspectj.apache.bcel.Constants; | |||
import java.io.*; | |||
import java.io.DataInputStream; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
/** | |||
* This class is derived from the abstract | |||
* <A HREF="org.aspectj.apache.bcel.classfile.Constant.html">Constant</A> class | |||
* and represents a reference to a (external) class. | |||
* | |||
* @version $Id: ConstantClass.java,v 1.3 2008/05/28 23:53:01 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* @see Constant | |||
import org.aspectj.apache.bcel.Constants; | |||
/** | |||
* This class is derived from the abstract <A HREF="org.aspectj.apache.bcel.classfile.Constant.html">Constant</A> class and | |||
* represents a reference to a (external) class. | |||
* | |||
* @version $Id: ConstantClass.java,v 1.4 2009/09/10 03:59:33 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* @author Andy Clement | |||
*/ | |||
public final class ConstantClass extends Constant implements ConstantObject { | |||
private int name_index; // Identical to ConstantString except for the name | |||
/** | |||
* Initialize from another object. | |||
*/ | |||
public ConstantClass(ConstantClass c) { | |||
this(c.getNameIndex()); | |||
} | |||
/** | |||
* Initialize instance from file data. | |||
* | |||
* @param file Input stream | |||
* @throws IOException | |||
*/ | |||
ConstantClass(DataInputStream file) throws IOException | |||
{ | |||
super(Constants.CONSTANT_Class); | |||
this.name_index = file.readUnsignedShort(); | |||
// this(file.readUnsignedShort()); | |||
} | |||
private int nameIndex; | |||
/** | |||
* @param name_index Name index in constant pool. Should refer to a | |||
* ConstantUtf8. | |||
*/ | |||
public ConstantClass(int name_index) { | |||
super(Constants.CONSTANT_Class); | |||
this.name_index = name_index; | |||
} | |||
public ConstantClass(ConstantClass c) { | |||
this(c.getNameIndex()); | |||
} | |||
/** | |||
* Called by objects that are traversing the nodes of the tree implicitely | |||
* defined by the contents of a Java class. I.e., the hierarchy of methods, | |||
* fields, attributes, etc. spawns a tree of objects. | |||
* | |||
* @param v Visitor object | |||
*/ | |||
public void accept(ClassVisitor v) { | |||
v.visitConstantClass(this); | |||
} | |||
ConstantClass(DataInputStream file) throws IOException { | |||
super(Constants.CONSTANT_Class); | |||
this.nameIndex = file.readUnsignedShort(); | |||
} | |||
/** | |||
* Dump constant class to file stream in binary format. | |||
* | |||
* @param file Output file stream | |||
* @throws IOException | |||
*/ | |||
public final void dump(DataOutputStream file) throws IOException | |||
{ | |||
file.writeByte(tag); | |||
file.writeShort(name_index); | |||
} | |||
public ConstantClass(int nameIndex) { | |||
super(Constants.CONSTANT_Class); | |||
this.nameIndex = nameIndex; | |||
} | |||
/** | |||
* @return Name index in constant pool of class name. | |||
*/ | |||
public final int getNameIndex() { return name_index; } | |||
@Override | |||
public void accept(ClassVisitor v) { | |||
v.visitConstantClass(this); | |||
} | |||
/** | |||
* @param name_index. | |||
*/ | |||
public final void setNameIndex(int name_index) { | |||
this.name_index = name_index; | |||
} | |||
@Override | |||
public final void dump(DataOutputStream file) throws IOException { | |||
file.writeByte(tag); | |||
file.writeShort(nameIndex); | |||
} | |||
public final int getNameIndex() { | |||
return nameIndex; | |||
} | |||
/** @return String object | |||
*/ | |||
public Object getConstantValue(ConstantPool cp) { | |||
Constant c = cp.getConstant(name_index, Constants.CONSTANT_Utf8); | |||
return ((ConstantUtf8)c).getBytes(); | |||
} | |||
public final void setNameIndex(int nameIndex) { | |||
this.nameIndex = nameIndex; | |||
} | |||
/** @return dereferenced string | |||
*/ | |||
public String getBytes(ConstantPool cp) { | |||
return (String)getConstantValue(cp); | |||
} | |||
public String getConstantValue(ConstantPool cp) { | |||
return cp.getConstantUtf8(nameIndex).getBytes(); | |||
// Constant c = cp.getConstant(nameIndex, Constants.CONSTANT_Utf8); | |||
// return ((ConstantUtf8) c).getBytes(); | |||
} | |||
/** | |||
* @return String representation. | |||
*/ | |||
public final String toString() { | |||
return super.toString() + "(name_index = " + name_index + ")"; | |||
} | |||
@Override | |||
public final String toString() { | |||
return super.toString() + "(name_index = " + nameIndex + ")"; | |||
} | |||
} |
@@ -54,89 +54,57 @@ package org.aspectj.apache.bcel.classfile; | |||
* <http://www.apache.org/>. | |||
*/ | |||
import org.aspectj.apache.bcel.Constants; | |||
import java.io.*; | |||
import java.io.DataInputStream; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
/** | |||
* This class is derived from the abstract | |||
* <A HREF="org.aspectj.apache.bcel.classfile.Constant.html">Constant</A> class | |||
* and represents a reference to a Double object. | |||
* | |||
* @version $Id: ConstantDouble.java,v 1.3 2008/05/28 23:53:01 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* @see Constant | |||
import org.aspectj.apache.bcel.Constants; | |||
/** | |||
* This class is derived from the abstract <A HREF="org.aspectj.apache.bcel.classfile.Constant.html">Constant</A> class and | |||
* represents a reference to a Double object. | |||
* | |||
* @version $Id: ConstantDouble.java,v 1.4 2009/09/10 03:59:33 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* @author Andy Clement | |||
*/ | |||
public final class ConstantDouble extends Constant implements ConstantObject { | |||
private double bytes; | |||
private double value; | |||
public ConstantDouble(double value) { | |||
super(Constants.CONSTANT_Double); | |||
this.value = value; | |||
} | |||
public ConstantDouble(ConstantDouble c) { | |||
this(c.getBytes()); | |||
} | |||
ConstantDouble(DataInputStream file) throws IOException { | |||
this(file.readDouble()); | |||
} | |||
/** | |||
* @param bytes Data | |||
*/ | |||
public ConstantDouble(double bytes) { | |||
super(Constants.CONSTANT_Double); | |||
this.bytes = bytes; | |||
} | |||
@Override | |||
public void accept(ClassVisitor v) { | |||
v.visitConstantDouble(this); | |||
} | |||
/** | |||
* Initialize from another object. | |||
*/ | |||
public ConstantDouble(ConstantDouble c) { | |||
this(c.getBytes()); | |||
} | |||
@Override | |||
public final void dump(DataOutputStream file) throws IOException { | |||
file.writeByte(tag); | |||
file.writeDouble(value); | |||
} | |||
/** | |||
* Initialize instance from file data. | |||
* | |||
* @param file Input stream | |||
* @throws IOException | |||
*/ | |||
ConstantDouble(DataInputStream file) throws IOException | |||
{ | |||
this(file.readDouble()); | |||
} | |||
public final double getBytes() { | |||
return value; | |||
} | |||
/** | |||
* Called by objects that are traversing the nodes of the tree implicitely | |||
* defined by the contents of a Java class. I.e., the hierarchy of methods, | |||
* fields, attributes, etc. spawns a tree of objects. | |||
* | |||
* @param v Visitor object | |||
*/ | |||
public void accept(ClassVisitor v) { | |||
v.visitConstantDouble(this); | |||
} | |||
/** | |||
* Dump constant double to file stream in binary format. | |||
* | |||
* @param file Output file stream | |||
* @throws IOException | |||
*/ | |||
public final void dump(DataOutputStream file) throws IOException | |||
{ | |||
file.writeByte(tag); | |||
file.writeDouble(bytes); | |||
} | |||
/** | |||
* @return data, i.e., 8 bytes. | |||
*/ | |||
public final double getBytes() { return bytes; } | |||
/** | |||
* @param bytes. | |||
*/ | |||
public final void setBytes(double bytes) { | |||
this.bytes = bytes; | |||
} | |||
/** | |||
* @return String representation. | |||
*/ | |||
public final String toString() | |||
{ | |||
return super.toString() + "(bytes = " + bytes + ")"; | |||
} | |||
@Override | |||
public final String toString() { | |||
return super.toString() + "(bytes = " + value + ")"; | |||
} | |||
/** @return Double object | |||
*/ | |||
public Object getConstantValue(ConstantPool cp) { | |||
return new Double(bytes); | |||
} | |||
public Double getConstantValue(ConstantPool cp) { | |||
return new Double(value); | |||
} | |||
} |
@@ -54,16 +54,13 @@ package org.aspectj.apache.bcel.classfile; | |||
* <http://www.apache.org/>. | |||
*/ | |||
/** | |||
* This interface denotes those constants that have a "natural" value, | |||
* such as ConstantLong, ConstantString, etc.. | |||
* | |||
* @version $Id: ConstantObject.java,v 1.3 2008/05/28 23:53:02 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* @see Constant | |||
/** | |||
* This interface denotes those constants that have a "natural" value, such as ConstantLong, ConstantString, etc.. | |||
* | |||
* @version $Id: ConstantObject.java,v 1.4 2009/09/10 03:59:33 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* @see Constant | |||
*/ | |||
public interface ConstantObject { | |||
/** @return object representing the constant, e.g., Long for ConstantLong | |||
*/ | |||
public abstract Object getConstantValue(ConstantPool cp); | |||
public abstract Object getConstantValue(ConstantPool cp); | |||
} |
@@ -80,12 +80,17 @@ import org.aspectj.apache.bcel.util.SyntheticRepository; | |||
* The intent of this class is to represent a parsed or otherwise existing class file. Those interested in programatically | |||
* generating classes should see the <a href="../generic/ClassGen.html">ClassGen</a> class. | |||
* | |||
* @version $Id: JavaClass.java,v 1.17 2009/09/09 22:18:20 aclement Exp $ | |||
* @version $Id: JavaClass.java,v 1.18 2009/09/10 03:59:33 aclement Exp $ | |||
* @see org.aspectj.apache.bcel.generic.ClassGen | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
*/ | |||
public class JavaClass extends Modifiers implements Cloneable, Node { | |||
private static final String[] NO_INTERFACE_NAMES = new String[0]; | |||
private static final String[] NoInterfaceNames = new String[0]; | |||
private static final Field[] NoFields = new Field[0]; | |||
private static final Method[] NoMethod = new Method[0]; | |||
private static final int[] NoInterfaceIndices = new int[0]; | |||
private static final Attribute[] NoAttributes = new Attribute[0]; | |||
private String fileName; | |||
private String packageName; | |||
@@ -121,48 +126,23 @@ public class JavaClass extends Modifiers implements Cloneable, Node { | |||
*/ | |||
private transient org.aspectj.apache.bcel.util.Repository repository = null; | |||
/** | |||
* Constructor gets all contents as arguments. | |||
* | |||
* @param class_name_index Index into constant pool referencing a ConstantClass that represents this class. | |||
* @param superclass_name_index Index into constant pool referencing a ConstantClass that represents this class's superclass. | |||
* @param file_name File name | |||
* @param major Major compiler version | |||
* @param minor Minor compiler version | |||
* @param access_flags Access rights defined by bit flags | |||
* @param constant_pool Array of constants | |||
* @param interfaces Implemented interfaces | |||
* @param fields Class fields | |||
* @param methods Class methods | |||
* @param attributes Class attributes | |||
* @param source Read from file or generated in memory? | |||
*/ | |||
public JavaClass(int class_name_index, int superclass_name_index, String file_name, int major, int minor, int access_flags, | |||
ConstantPool constant_pool, int[] interfaces, Field[] fields, Method[] methods, Attribute[] attributes) { | |||
public JavaClass(int classnameIndex, int superclassnameIndex, String filename, int major, int minor, int access_flags, | |||
ConstantPool cpool, int[] interfaces, Field[] fields, Method[] methods, Attribute[] attributes) { | |||
if (interfaces == null) { | |||
interfaces = new int[0]; | |||
} | |||
if (attributes == null) { | |||
this.attributes = Attribute.NoAttributes; | |||
} | |||
if (fields == null) { | |||
fields = new Field[0]; // TODO create a constant for no fields | |||
} | |||
if (methods == null) { | |||
methods = new Method[0]; // TODO create a constant for no methods | |||
interfaces = NoInterfaceIndices; | |||
} | |||
this.classnameIdx = class_name_index; | |||
this.superclassnameIdx = superclass_name_index; | |||
this.fileName = file_name; | |||
this.classnameIdx = classnameIndex; | |||
this.superclassnameIdx = superclassnameIndex; | |||
this.fileName = filename; | |||
this.major = major; | |||
this.minor = minor; | |||
this.modifiers = access_flags; | |||
this.cpool = constant_pool; | |||
this.cpool = cpool; | |||
this.interfaces = interfaces; | |||
this.fields = fields; | |||
this.methods = methods; | |||
this.attributes = attributes; | |||
this.fields = (fields == null ? NoFields : fields); | |||
this.methods = (methods == null ? NoMethod : methods); | |||
this.attributes = (attributes == null ? NoAttributes : attributes); | |||
annotationsOutOfDate = true; | |||
// Get source file name if available | |||
@@ -173,7 +153,7 @@ public class JavaClass extends Modifiers implements Cloneable, Node { | |||
* According to the specification the following entries must be of type `ConstantClass' but we check that anyway via the | |||
* `ConstPool.getConstant' method. | |||
*/ | |||
classname = constant_pool.getConstantString(class_name_index, Constants.CONSTANT_Class); | |||
classname = cpool.getConstantString(classnameIndex, Constants.CONSTANT_Class); | |||
classname = Utility.compactClassName(classname, false); | |||
int index = classname.lastIndexOf('.'); | |||
@@ -183,19 +163,19 @@ public class JavaClass extends Modifiers implements Cloneable, Node { | |||
packageName = classname.substring(0, index); | |||
} | |||
if (superclass_name_index > 0) { // May be zero -> class is java.lang.Object | |||
superclassname = constant_pool.getConstantString(superclass_name_index, Constants.CONSTANT_Class); | |||
if (superclassnameIndex > 0) { // May be zero -> class is java.lang.Object | |||
superclassname = cpool.getConstantString(superclassnameIndex, Constants.CONSTANT_Class); | |||
superclassname = Utility.compactClassName(superclassname, false); | |||
} else { | |||
superclassname = "java.lang.Object"; | |||
} | |||
if (interfaces.length == 0) { | |||
interfacenames = NO_INTERFACE_NAMES; | |||
interfacenames = NoInterfaceNames; | |||
} else { | |||
interfacenames = new String[interfaces.length]; | |||
for (int i = 0; i < interfaces.length; i++) { | |||
String str = constant_pool.getConstantString(interfaces[i], Constants.CONSTANT_Class); | |||
String str = cpool.getConstantString(interfaces[i], Constants.CONSTANT_Class); | |||
interfacenames[i] = Utility.compactClassName(str, false); | |||
} | |||
} | |||
@@ -343,16 +323,10 @@ public class JavaClass extends Modifiers implements Cloneable, Node { | |||
return packageName; | |||
} | |||
/** | |||
* @return Class name index. | |||
*/ | |||
public int getClassNameIndex() { | |||
return classnameIdx; | |||
} | |||
/** | |||
* @return Constant pool. | |||
*/ | |||
public ConstantPool getConstantPool() { | |||
return cpool; | |||
} | |||
@@ -386,9 +360,6 @@ public class JavaClass extends Modifiers implements Cloneable, Node { | |||
return interfaces; | |||
} | |||
/** | |||
* @return Major number of class file version. | |||
*/ | |||
public int getMajor() { | |||
return major; | |||
} | |||
@@ -419,7 +390,6 @@ public class JavaClass extends Modifiers implements Cloneable, Node { | |||
public Method getMethod(java.lang.reflect.Constructor c) { | |||
for (int i = 0; i < methods.length; i++) { | |||
Method method = methods[i]; | |||
if (method.getName().equals("<init>") && c.getModifiers() == method.getModifiers() | |||
&& Type.getSignature(c).equals(method.getSignature())) { | |||
return method; | |||
@@ -430,9 +400,10 @@ public class JavaClass extends Modifiers implements Cloneable, Node { | |||
} | |||
public Field getField(java.lang.reflect.Field field) { | |||
for (int i = 0; i < fields.length; i++) { | |||
if (fields[i].getName().equals(field.getName())) { | |||
return fields[i]; | |||
String fieldName = field.getName(); | |||
for (Field f : fields) { | |||
if (f.getName().equals(fieldName)) { | |||
return f; | |||
} | |||
} | |||
return null; | |||
@@ -523,23 +494,14 @@ public class JavaClass extends Modifiers implements Cloneable, Node { | |||
this.interfaces = interfaces; | |||
} | |||
/** | |||
* @param major . | |||
*/ | |||
public void setMajor(int major) { | |||
this.major = major; | |||
} | |||
/** | |||
* @param methods . | |||
*/ | |||
public void setMethods(Method[] methods) { | |||
this.methods = methods; | |||
} | |||
/** | |||
* @param minor . | |||
*/ | |||
public void setMinor(int minor) { | |||
this.minor = minor; | |||
} |
@@ -70,12 +70,13 @@ import org.aspectj.apache.bcel.classfile.annotation.RuntimeInvisibleParameterAnn | |||
import org.aspectj.apache.bcel.classfile.annotation.RuntimeParameterAnnotations; | |||
import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisibleAnnotations; | |||
import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisibleParameterAnnotations; | |||
import org.aspectj.apache.bcel.generic.Type; | |||
import org.aspectj.apache.bcel.util.ByteSequence; | |||
/** | |||
* Utility functions that do not really belong to any class in particular. | |||
* | |||
* @version $Id: Utility.java,v 1.9 2009/09/09 22:18:20 aclement Exp $ | |||
* @version $Id: Utility.java,v 1.10 2009/09/10 03:59:33 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* | |||
* modified: Andy Clement 2-mar-05 Removed unnecessary static and optimized | |||
@@ -200,7 +201,7 @@ public abstract class Utility { | |||
public static final String compactClassName(String str, String prefix, boolean chopit) { | |||
int len = prefix.length(); | |||
str = str.replace('/', '.'); // Is '/' on all systems, even DOS | |||
str = str.replace('/', '.'); | |||
if (chopit) { | |||
// If string starts with 'prefix' and contains no further dots | |||
@@ -237,37 +238,9 @@ public abstract class Utility { | |||
/** | |||
* This method converts such a string into a Java type declaration like 'void main(String[])' and throws a | |||
* 'ClassFormatException' when the parsed type is invalid. | |||
* | |||
* @param signature Method signature | |||
* @param name Method name | |||
* @param access Method access rights | |||
* @return Java type declaration | |||
* @throws ClassFormatException | |||
*/ | |||
public static final String methodSignatureToString(String signature, String name, String access, boolean chopit, | |||
LocalVariableTable vars) throws ClassFormatException { | |||
// | |||
// | |||
// if (signature.charAt(0)!='(') | |||
// throw new ClassFormatException("Invalid method signature: " + signature); | |||
// | |||
// // Break the signature into two pieces: ([PARAMS])[RETURNTYPE] | |||
// int lastBracketPos = signature.lastIndexOf(")"); | |||
// String parameters = signature.substring(1,lastBracketPos); | |||
// String returnType = signature.substring(lastBracketPos+1); | |||
// | |||
// // e.g. parameters="Ljava/util/List<Ljava/lang/String;>;" | |||
// // returnType="V" | |||
// | |||
// // Break signature into its parts | |||
// // dont want lots of substringing so lets use an index | |||
// int posn=0; | |||
// StringBuffer piece; | |||
// while (posn<parameters.length()) { | |||
// piece = new StringBuffer(); | |||
// posn+=getSignatureFrom(parameters,piece); | |||
// } | |||
// | |||
StringBuffer buf = new StringBuffer("("); | |||
String type; | |||
int index; | |||
@@ -371,10 +344,6 @@ public abstract class Utility { | |||
/** | |||
* This method converts this string into a Java type declaration such as 'String[]' and throws a `ClassFormatException' when the | |||
* parsed type is invalid. | |||
* | |||
* @param signature Class signature | |||
* @param chopit Flag that determines whether chopping is executed or not | |||
* @return Java type declaration | |||
*/ | |||
public static final ResultHolder signatureToStringInternal(String signature, boolean chopit) { | |||
int processedChars = 1; // This is the default, read just one char | |||
@@ -392,12 +361,12 @@ public abstract class Utility { | |||
return ResultHolder.INT; | |||
case 'J': | |||
return ResultHolder.LONG; | |||
case 'L': { // Full class name | |||
int index = signature.indexOf(';'); // Look for closing `;' | |||
// Jump to the correct ';' | |||
if (index != -1 && signature.length() > index + 1 && signature.charAt(index + 1) == '>') | |||
int index = signature.indexOf(';'); // Look for closing ';' | |||
if (index != -1 && signature.length() > index + 1 && signature.charAt(index + 1) == '>') { | |||
index = index + 2; | |||
} | |||
if (index < 0) | |||
throw new ClassFormatException("Invalid signature: " + signature); | |||
@@ -460,10 +429,10 @@ public abstract class Utility { | |||
*/ | |||
public static final byte typeOfMethodSignature(String signature) throws ClassFormatException { | |||
int index; | |||
try { | |||
if (signature.charAt(0) != '(') | |||
if (signature.charAt(0) != '(') { | |||
throw new ClassFormatException("Invalid method signature: " + signature); | |||
} | |||
index = signature.lastIndexOf(')') + 1; | |||
return typeOfSignature(signature.substring(index)); | |||
} catch (StringIndexOutOfBoundsException e) { | |||
@@ -575,11 +544,11 @@ public abstract class Utility { | |||
* Converts a list of AnnotationGen objects into a set of attributes that can be attached to the class file. | |||
* | |||
* @param cp The constant pool gen where we can create the necessary name refs | |||
* @param vec A list of AnnotationGen objects | |||
* @param annotations A list of AnnotationGen objects | |||
*/ | |||
public static Collection<RuntimeAnnotations> getAnnotationAttributes(ConstantPool cp, List<AnnotationGen> vec) { | |||
public static Collection<RuntimeAnnotations> getAnnotationAttributes(ConstantPool cp, List<AnnotationGen> annotations) { | |||
if (vec.size() == 0) | |||
if (annotations.size() == 0) | |||
return null; | |||
try { | |||
@@ -587,12 +556,12 @@ public abstract class Utility { | |||
int countInvisible = 0; | |||
// put the annotations in the right output stream | |||
for (int i = 0; i < vec.size(); i++) { | |||
AnnotationGen a = vec.get(i); | |||
if (a.isRuntimeVisible()) | |||
for (AnnotationGen a : annotations) { | |||
if (a.isRuntimeVisible()) { | |||
countVisible++; | |||
else | |||
} else { | |||
countInvisible++; | |||
} | |||
} | |||
ByteArrayOutputStream rvaBytes = new ByteArrayOutputStream(); | |||
@@ -604,8 +573,7 @@ public abstract class Utility { | |||
riaDos.writeShort(countInvisible); | |||
// put the annotations in the right output stream | |||
for (int i = 0; i < vec.size(); i++) { | |||
AnnotationGen a = vec.get(i); | |||
for (AnnotationGen a : annotations) { | |||
if (a.isRuntimeVisible()) | |||
a.dump(rvaDos); | |||
else | |||
@@ -1089,4 +1057,22 @@ public abstract class Utility { | |||
private static final int pow2(int n) { | |||
return 1 << n; | |||
} | |||
/** | |||
* Convert type to Java method signature, e.g. int[] f(java.lang.String x) becomes (Ljava/lang/String;)[I | |||
* | |||
* @param returnType what the method returns | |||
* @param argTypes what are the argument types | |||
* @return method signature for given type(s). | |||
*/ | |||
public static String toMethodSignature(Type returnType, Type[] argTypes) { | |||
StringBuffer buf = new StringBuffer("("); | |||
int length = (argTypes == null) ? 0 : argTypes.length; | |||
for (int i = 0; i < length; i++) { | |||
buf.append(argTypes[i].getSignature()); | |||
} | |||
buf.append(')'); | |||
buf.append(returnType.getSignature()); | |||
return buf.toString(); | |||
} | |||
} |
@@ -16,177 +16,163 @@ import java.io.DataInputStream; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.Iterator; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import org.aspectj.apache.bcel.classfile.ConstantUtf8; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
import org.aspectj.apache.bcel.generic.ObjectType; | |||
import org.aspectj.apache.bcel.classfile.ConstantUtf8; | |||
import org.aspectj.apache.bcel.classfile.Utility; | |||
import org.aspectj.apache.bcel.generic.ObjectType; | |||
public class AnnotationGen { | |||
public static final AnnotationGen[] NO_ANNOTATIONS = new AnnotationGen[0]; | |||
private int typeIndex; | |||
private List /* ElementNameValuePairGen */<ElementNameValuePairGen> evs; | |||
private List<ElementNameValuePairGen> pairs = Collections.emptyList(); | |||
private ConstantPool cpool; | |||
private boolean isRuntimeVisible = false; | |||
/** | |||
* Here we are taking a fixed annotation of type Annotation and building a | |||
* modifiable AnnotationGen object. If the pool passed in is for a different | |||
* class file, then copyPoolEntries should have been passed as true as that | |||
* will force us to do a deep copy of the annotation and move the cpool entries | |||
* across. | |||
* We need to copy the type and the element name value pairs and the visibility. | |||
* Here we are taking a fixed annotation of type Annotation and building a modifiable AnnotationGen object. If the pool passed | |||
* in is for a different class file, then copyPoolEntries should have been passed as true as that will force us to do a deep | |||
* copy of the annotation and move the cpool entries across. We need to copy the type and the element name value pairs and the | |||
* visibility. | |||
*/ | |||
public AnnotationGen(AnnotationGen a,ConstantPool cpool,boolean copyPoolEntries) { | |||
public AnnotationGen(AnnotationGen a, ConstantPool cpool, boolean copyPoolEntries) { | |||
this.cpool = cpool; | |||
if (copyPoolEntries) { | |||
typeIndex = cpool.addUtf8(a.getTypeSignature()); | |||
typeIndex = cpool.addUtf8(a.getTypeSignature()); | |||
} else { | |||
typeIndex = a.getTypeIndex(); | |||
} | |||
isRuntimeVisible = a.isRuntimeVisible(); | |||
evs = copyValues(a.getValues(),cpool,copyPoolEntries); | |||
isRuntimeVisible = a.isRuntimeVisible(); | |||
pairs = copyValues(a.getValues(), cpool, copyPoolEntries); | |||
} | |||
private List<ElementNameValuePairGen> copyValues(List<ElementNameValuePairGen> in,ConstantPool cpool,boolean copyPoolEntries) { | |||
private List<ElementNameValuePairGen> copyValues(List<ElementNameValuePairGen> in, ConstantPool cpool, boolean copyPoolEntries) { | |||
List<ElementNameValuePairGen> out = new ArrayList<ElementNameValuePairGen>(); | |||
for (Iterator<ElementNameValuePairGen> iter = in.iterator(); iter.hasNext();) { | |||
ElementNameValuePairGen nvp = iter.next(); | |||
out.add(new ElementNameValuePairGen(nvp,cpool,copyPoolEntries)); | |||
for (ElementNameValuePairGen nvp : in) { | |||
out.add(new ElementNameValuePairGen(nvp, cpool, copyPoolEntries)); | |||
} | |||
return out; | |||
} | |||
private AnnotationGen(ConstantPool cpool) { | |||
this.cpool = cpool; | |||
this.evs=new ArrayList<ElementNameValuePairGen>(); | |||
} | |||
/** | |||
* Retrieve an immutable version of this AnnotationGen | |||
*/ | |||
// public AnnotationGen getAnnotation() { | |||
// return this; | |||
//// AnnotationGen a = new AnnotationGen(typeIndex,cpool,isRuntimeVisible); | |||
//// for (Iterator iter = evs.iterator(); iter.hasNext();) { | |||
//// ElementNameValuePairGen element = (ElementNameValuePairGen) iter.next(); | |||
//// a.addElementNameValuePair(element.getElementNameValuePair()); | |||
//// } | |||
//// return a; | |||
// } | |||
public AnnotationGen(ObjectType type,List /*ElementNameValuePairGen*/<ElementNameValuePairGen> elements,boolean vis,ConstantPool cpool) { | |||
public AnnotationGen(ObjectType type, List<ElementNameValuePairGen> pairs, boolean runtimeVisible, ConstantPool cpool) { | |||
this.cpool = cpool; | |||
if (type!=null) this.typeIndex = cpool.addUtf8(type.getSignature()); // Only null for funky *temporary* FakeAnnotation objects | |||
evs = elements; | |||
isRuntimeVisible = vis; | |||
if (type != null) { | |||
this.typeIndex = cpool.addUtf8(type.getSignature()); // Only null for funky *temporary* FakeAnnotation objects | |||
} | |||
this.pairs = pairs; | |||
isRuntimeVisible = runtimeVisible; | |||
} | |||
public static AnnotationGen read(DataInputStream dis,ConstantPool cpool,boolean b) throws IOException { | |||
public static AnnotationGen read(DataInputStream dis, ConstantPool cpool, boolean b) throws IOException { | |||
AnnotationGen a = new AnnotationGen(cpool); | |||
a.typeIndex = dis.readUnsignedShort(); | |||
int elemValuePairCount = dis.readUnsignedShort(); | |||
for (int i=0;i<elemValuePairCount;i++) { | |||
int nidx = dis.readUnsignedShort(); | |||
a.addElementNameValuePair( | |||
new ElementNameValuePairGen(nidx,ElementValueGen.readElementValue(dis,cpool),cpool)); | |||
for (int i = 0; i < elemValuePairCount; i++) { | |||
int nidx = dis.readUnsignedShort(); | |||
a.addElementNameValuePair(new ElementNameValuePairGen(nidx, ElementValueGen.readElementValue(dis, cpool), cpool)); | |||
} | |||
a.isRuntimeVisible(b); | |||
return a; | |||
} | |||
public void dump(DataOutputStream dos) throws IOException { | |||
dos.writeShort(typeIndex); // u2 index of type name in cpool | |||
dos.writeShort(evs.size()); // u2 element_value pair count | |||
for (int i = 0 ; i<evs.size();i++) { | |||
ElementNameValuePairGen envp = evs.get(i); | |||
dos.writeShort(typeIndex); // u2 index of type name in cpool | |||
dos.writeShort(pairs.size()); // u2 element_value pair count | |||
for (int i = 0; i < pairs.size(); i++) { | |||
ElementNameValuePairGen envp = pairs.get(i); | |||
envp.dump(dos); | |||
} | |||
} | |||
public void addElementNameValuePair(ElementNameValuePairGen evp) { | |||
if (evs == null) evs = new ArrayList<ElementNameValuePairGen>(); | |||
evs.add(evp); | |||
if (pairs == Collections.EMPTY_LIST) { | |||
pairs = new ArrayList<ElementNameValuePairGen>(); | |||
} | |||
pairs.add(evp); | |||
} | |||
public int getTypeIndex() { | |||
return typeIndex; | |||
} | |||
public String getTypeSignature() { | |||
// ConstantClass c = (ConstantClass)cpool.getConstant(typeIndex); | |||
ConstantUtf8 utf8 = (ConstantUtf8)cpool.getConstant(typeIndex/*c.getNameIndex()*/); | |||
return utf8.getBytes(); | |||
ConstantUtf8 utf8 = (ConstantUtf8) cpool.getConstant(typeIndex); | |||
return utf8.getBytes(); | |||
} | |||
public String getTypeName() { | |||
return Utility.signatureToString(getTypeSignature()); | |||
} | |||
/** | |||
* Returns list of ElementNameValuePair objects | |||
*/ | |||
public List<ElementNameValuePairGen> getValues() { | |||
return evs; | |||
return pairs; | |||
} | |||
@Override | |||
public String toString() { | |||
StringBuffer s = new StringBuffer(); | |||
s.append("AnnotationGen:["+getTypeName()+" #"+evs.size()+" {"); | |||
for (int i = 0; i<evs.size();i++) { | |||
s.append(evs.get(i)); | |||
if (i+1<evs.size()) s.append(","); | |||
s.append("AnnotationGen:[" + getTypeName() + " #" + pairs.size() + " {"); | |||
for (int i = 0; i < pairs.size(); i++) { | |||
s.append(pairs.get(i)); | |||
if (i + 1 < pairs.size()) | |||
s.append(","); | |||
} | |||
s.append("}]"); | |||
return s.toString(); | |||
} | |||
public String toShortString() { | |||
StringBuffer s = new StringBuffer(); | |||
s.append("@"+getTypeName()+"("); | |||
for (int i = 0; i<evs.size();i++) { | |||
s.append(evs.get(i)); | |||
if (i+1<evs.size()) s.append(","); | |||
s.append("@" + getTypeName() + "("); | |||
for (int i = 0; i < pairs.size(); i++) { | |||
s.append(pairs.get(i)); | |||
if (i + 1 < pairs.size()) | |||
s.append(","); | |||
} | |||
s.append(")"); | |||
return s.toString(); | |||
} | |||
private void isRuntimeVisible(boolean b) { | |||
isRuntimeVisible = b; | |||
isRuntimeVisible = b; | |||
} | |||
public boolean isRuntimeVisible() { | |||
return isRuntimeVisible; | |||
} | |||
/** | |||
* Return true if the annotation has a value with the specified name (n) and value (v) | |||
*/ | |||
public boolean hasNameValuePair(String n, String v) { | |||
for (int i=0;i<evs.size();i++) { | |||
ElementNameValuePairGen pair = evs.get(i); | |||
if (pair.getNameString().equals(n)) { | |||
if (pair.getValue().stringifyValue().equals(v)) return true; | |||
* @return true if the annotation has a value with the specified name and (toString'd) value | |||
*/ | |||
public boolean hasNameValuePair(String name, String value) { | |||
for (ElementNameValuePairGen pair : pairs) { | |||
if (pair.getNameString().equals(name)) { | |||
if (pair.getValue().stringifyValue().equals(value)) { | |||
return true; | |||
} | |||
} | |||
} | |||
return false; | |||
} | |||
/** | |||
* Return true if the annotation has a value with the specified name (n) | |||
*/ | |||
public boolean hasNamedValue(String n) { | |||
for (int i=0;i<evs.size();i++) { | |||
ElementNameValuePairGen pair = evs.get(i); | |||
if (pair.getNameString().equals(n)) return true; | |||
/** | |||
* @return true if the annotation has a value with the specified name | |||
*/ | |||
public boolean hasNamedValue(String name) { | |||
for (ElementNameValuePairGen pair : pairs) { | |||
if (pair.getNameString().equals(name)) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} |
@@ -15,72 +15,61 @@ package org.aspectj.apache.bcel.classfile.annotation; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import org.aspectj.apache.bcel.classfile.ConstantUtf8; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
public class ElementNameValuePairGen { | |||
private int nameIdx; | |||
private ElementValueGen value; | |||
private ConstantPool cpool; | |||
public ElementNameValuePairGen(ElementNameValuePairGen nvp, ConstantPool cpool, boolean copyPoolEntries) { | |||
public ElementNameValuePairGen(ElementNameValuePairGen pair, ConstantPool cpool, boolean copyPoolEntries) { | |||
this.cpool = cpool; | |||
// J5ASSERT: | |||
// Could assert nvp.getNameString() points to the same thing as cpool.getConstant(nvp.getNameIndex()) | |||
// if (!nvp.getNameString().equals(((ConstantUtf8)cpool.getConstant(nvp.getNameIndex())).getBytes())) { | |||
// throw new RuntimeException("envp buggered"); | |||
// } | |||
if (copyPoolEntries) { | |||
nameIdx = cpool.addUtf8(nvp.getNameString()); | |||
// if (!nvp.getNameString().equals(((ConstantUtf8)cpool.getConstant(nvp.getNameIndex())).getBytes())) { | |||
// throw new RuntimeException("envp buggered"); | |||
// } | |||
if (copyPoolEntries) { | |||
nameIdx = cpool.addUtf8(pair.getNameString()); | |||
} else { | |||
nameIdx = nvp.getNameIndex(); | |||
nameIdx = pair.getNameIndex(); | |||
} | |||
value = ElementValueGen.copy(nvp.getValue(),cpool,copyPoolEntries); | |||
value = ElementValueGen.copy(pair.getValue(), cpool, copyPoolEntries); | |||
} | |||
/** | |||
* Retrieve an immutable version of this ElementNameValuePairGen | |||
*/ | |||
// public ElementNameValuePairGen getElementNameValuePair() { | |||
// ElementValueGen immutableValue = value.getElementValue(); | |||
// return new ElementNameValuePairGen(nameIdx,immutableValue,cpool); | |||
// } | |||
protected ElementNameValuePairGen(int idx,ElementValueGen value,ConstantPool cpool) { | |||
protected ElementNameValuePairGen(int idx, ElementValueGen value, ConstantPool cpool) { | |||
this.nameIdx = idx; | |||
this.value = value; | |||
this.cpool = cpool; | |||
this.value = value; | |||
this.cpool = cpool; | |||
} | |||
public ElementNameValuePairGen(String name,ElementValueGen value,ConstantPool cpool) { | |||
public ElementNameValuePairGen(String name, ElementValueGen value, ConstantPool cpool) { | |||
this.nameIdx = cpool.addUtf8(name); | |||
this.value = value; | |||
this.cpool = cpool; | |||
this.value = value; | |||
this.cpool = cpool; | |||
} | |||
protected void dump(DataOutputStream dos) throws IOException { | |||
dos.writeShort(nameIdx); // u2 name of the element | |||
value.dump(dos); | |||
} | |||
public int getNameIndex() { | |||
return nameIdx; | |||
} | |||
public final String getNameString() { | |||
// ConstantString cu8 = (ConstantString)cpool.getConstant(nameIdx); | |||
return ((ConstantUtf8)cpool.getConstant(nameIdx)).getBytes(); | |||
return cpool.getConstantUtf8(nameIdx).getBytes(); | |||
} | |||
public final ElementValueGen getValue() { | |||
return value; | |||
} | |||
@Override | |||
public String toString() { | |||
StringBuffer sb = new StringBuffer(); | |||
sb.append(getNameString()+"="+value.stringifyValue()); | |||
sb.append(getNameString()).append("=").append(value.stringifyValue()); | |||
return sb.toString(); | |||
} | |||
} |
@@ -15,240 +15,261 @@ package org.aspectj.apache.bcel.classfile.annotation; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import org.aspectj.apache.bcel.Constants; | |||
import org.aspectj.apache.bcel.classfile.ConstantDouble; | |||
import org.aspectj.apache.bcel.classfile.ConstantFloat; | |||
import org.aspectj.apache.bcel.classfile.ConstantInteger; | |||
import org.aspectj.apache.bcel.classfile.ConstantLong; | |||
import org.aspectj.apache.bcel.classfile.ConstantUtf8; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
import org.aspectj.apache.bcel.Constants; | |||
import org.aspectj.apache.bcel.classfile.ConstantUtf8; | |||
public class SimpleElementValueGen extends ElementValueGen { | |||
public class SimpleElementValueGen extends ElementValueGen { | |||
// For primitive types and string type, this points to the value entry in the cpGen | |||
// For 'class' this points to the class entry in the cpGen | |||
private int idx; | |||
// ctors for each supported type... type could be inferred but for now lets | |||
// ctors for each supported type... type could be inferred but for now lets | |||
// force it to be passed | |||
/** | |||
* Protected ctor used for deserialization, doesn't *put* an entry in the constant pool, | |||
* assumes the one at the supplied index is correct. | |||
* Protected ctor used for deserialization, doesn't *put* an entry in the constant pool, assumes the one at the supplied index | |||
* is correct. | |||
*/ | |||
protected SimpleElementValueGen(int type,int idx,ConstantPool cpGen) { | |||
super(type,cpGen); | |||
this.idx = idx; | |||
} | |||
public SimpleElementValueGen(int type,ConstantPool cpGen,int value) { | |||
super(type,cpGen); | |||
idx = cpGen.addInteger(value); | |||
} | |||
public SimpleElementValueGen(int type,ConstantPool cpGen,long value) { | |||
super(type,cpGen); | |||
idx = cpGen.addLong(value); | |||
} | |||
public SimpleElementValueGen(int type,ConstantPool cpGen,double value) { | |||
super(type,cpGen); | |||
idx = cpGen.addDouble(value); | |||
} | |||
public SimpleElementValueGen(int type,ConstantPool cpGen,float value) { | |||
super(type,cpGen); | |||
idx = cpGen.addFloat(value); | |||
} | |||
public SimpleElementValueGen(int type,ConstantPool cpGen,short value) { | |||
super(type,cpGen); | |||
idx = cpGen.addInteger(value); | |||
} | |||
public SimpleElementValueGen(int type,ConstantPool cpGen,byte value) { | |||
super(type,cpGen); | |||
idx = cpGen.addInteger(value); | |||
} | |||
public SimpleElementValueGen(int type,ConstantPool cpGen,char value) { | |||
super(type,cpGen); | |||
idx = cpGen.addInteger(value); | |||
} | |||
public SimpleElementValueGen(int type,ConstantPool cpGen,boolean value) { | |||
super(type,cpGen); | |||
if (value) idx = cpGen.addInteger(1); | |||
else idx = cpGen.addInteger(0); | |||
} | |||
public SimpleElementValueGen(int type,ConstantPool cpGen,String value) { | |||
super(type,cpGen); | |||
idx = cpGen.addUtf8(value); | |||
} | |||
public byte getValueByte() { | |||
if (type != PRIMITIVE_BYTE) | |||
throw new RuntimeException("Dont call getValueByte() on a non BYTE ElementValue"); | |||
ConstantInteger c = (ConstantInteger)cpGen.getConstant(idx,Constants.CONSTANT_Integer); | |||
return (byte)c.getBytes(); | |||
} | |||
public char getValueChar() { | |||
if (type != PRIMITIVE_CHAR) | |||
throw new RuntimeException("Dont call getValueChar() on a non CHAR ElementValue"); | |||
ConstantInteger c = (ConstantInteger)cpGen.getConstant(idx,Constants.CONSTANT_Integer); | |||
return (char)c.getBytes(); | |||
} | |||
public long getValueLong() { | |||
if (type != PRIMITIVE_LONG) | |||
throw new RuntimeException("Dont call getValueLong() on a non LONG ElementValue"); | |||
ConstantLong j = (ConstantLong)cpGen.getConstant(idx); | |||
return j.getBytes(); | |||
} | |||
public float getValueFloat() { | |||
if (type != PRIMITIVE_FLOAT) | |||
throw new RuntimeException("Dont call getValueFloat() on a non FLOAT ElementValue"); | |||
ConstantFloat f = (ConstantFloat)cpGen.getConstant(idx); | |||
return f.getBytes(); | |||
} | |||
public double getValueDouble() { | |||
if (type != PRIMITIVE_DOUBLE) | |||
throw new RuntimeException("Dont call getValueDouble() on a non DOUBLE ElementValue"); | |||
ConstantDouble d = (ConstantDouble)cpGen.getConstant(idx); | |||
return d.getBytes(); | |||
} | |||
public boolean getValueBoolean() { | |||
if (type != PRIMITIVE_BOOLEAN) | |||
throw new RuntimeException("Dont call getValueBoolean() on a non BOOLEAN ElementValue"); | |||
ConstantInteger bo = (ConstantInteger)cpGen.getConstant(idx); | |||
return (bo.getBytes()!=0); | |||
} | |||
public short getValueShort() { | |||
if (type != PRIMITIVE_SHORT) | |||
throw new RuntimeException("Dont call getValueShort() on a non SHORT ElementValue"); | |||
ConstantInteger s = (ConstantInteger)cpGen.getConstant(idx); | |||
return (short)s.getBytes(); | |||
} | |||
/** | |||
* The boolean controls whether we copy info from the 'old' constant pool | |||
* to the 'new'. You need to use this ctor if the annotation is | |||
* being copied from one file to another. | |||
*/ | |||
public SimpleElementValueGen(SimpleElementValueGen value,ConstantPool cpool,boolean copyPoolEntries) { | |||
super(value.getElementValueType(),cpool); | |||
protected SimpleElementValueGen(int type, int idx, ConstantPool cpGen) { | |||
super(type, cpGen); | |||
this.idx = idx; | |||
} | |||
public SimpleElementValueGen(int type, ConstantPool cpGen, int value) { | |||
super(type, cpGen); | |||
idx = cpGen.addInteger(value); | |||
} | |||
public SimpleElementValueGen(int type, ConstantPool cpGen, long value) { | |||
super(type, cpGen); | |||
idx = cpGen.addLong(value); | |||
} | |||
public SimpleElementValueGen(int type, ConstantPool cpGen, double value) { | |||
super(type, cpGen); | |||
idx = cpGen.addDouble(value); | |||
} | |||
public SimpleElementValueGen(int type, ConstantPool cpGen, float value) { | |||
super(type, cpGen); | |||
idx = cpGen.addFloat(value); | |||
} | |||
public SimpleElementValueGen(int type, ConstantPool cpGen, short value) { | |||
super(type, cpGen); | |||
idx = cpGen.addInteger(value); | |||
} | |||
public SimpleElementValueGen(int type, ConstantPool cpGen, byte value) { | |||
super(type, cpGen); | |||
idx = cpGen.addInteger(value); | |||
} | |||
public SimpleElementValueGen(int type, ConstantPool cpGen, char value) { | |||
super(type, cpGen); | |||
idx = cpGen.addInteger(value); | |||
} | |||
public SimpleElementValueGen(int type, ConstantPool cpGen, boolean value) { | |||
super(type, cpGen); | |||
if (value) | |||
idx = cpGen.addInteger(1); | |||
else | |||
idx = cpGen.addInteger(0); | |||
} | |||
public SimpleElementValueGen(int type, ConstantPool cpGen, String value) { | |||
super(type, cpGen); | |||
idx = cpGen.addUtf8(value); | |||
} | |||
public byte getValueByte() { | |||
if (type != PRIMITIVE_BYTE) | |||
throw new RuntimeException("Dont call getValueByte() on a non BYTE ElementValue"); | |||
ConstantInteger c = (ConstantInteger) cpGen.getConstant(idx, Constants.CONSTANT_Integer); | |||
return (byte) c.getBytes(); | |||
} | |||
public char getValueChar() { | |||
if (type != PRIMITIVE_CHAR) | |||
throw new RuntimeException("Dont call getValueChar() on a non CHAR ElementValue"); | |||
ConstantInteger c = (ConstantInteger) cpGen.getConstant(idx, Constants.CONSTANT_Integer); | |||
return (char) c.getBytes(); | |||
} | |||
public long getValueLong() { | |||
if (type != PRIMITIVE_LONG) | |||
throw new RuntimeException("Dont call getValueLong() on a non LONG ElementValue"); | |||
ConstantLong j = (ConstantLong) cpGen.getConstant(idx); | |||
return j.getBytes(); | |||
} | |||
public float getValueFloat() { | |||
if (type != PRIMITIVE_FLOAT) | |||
throw new RuntimeException("Dont call getValueFloat() on a non FLOAT ElementValue"); | |||
ConstantFloat f = (ConstantFloat) cpGen.getConstant(idx); | |||
return f.getBytes(); | |||
} | |||
public double getValueDouble() { | |||
if (type != PRIMITIVE_DOUBLE) | |||
throw new RuntimeException("Dont call getValueDouble() on a non DOUBLE ElementValue"); | |||
ConstantDouble d = (ConstantDouble) cpGen.getConstant(idx); | |||
return d.getBytes(); | |||
} | |||
public boolean getValueBoolean() { | |||
if (type != PRIMITIVE_BOOLEAN) | |||
throw new RuntimeException("Dont call getValueBoolean() on a non BOOLEAN ElementValue"); | |||
ConstantInteger bo = (ConstantInteger) cpGen.getConstant(idx); | |||
return (bo.getBytes() != 0); | |||
} | |||
public short getValueShort() { | |||
if (type != PRIMITIVE_SHORT) | |||
throw new RuntimeException("Dont call getValueShort() on a non SHORT ElementValue"); | |||
ConstantInteger s = (ConstantInteger) cpGen.getConstant(idx); | |||
return (short) s.getBytes(); | |||
} | |||
/** | |||
* The boolean controls whether we copy info from the 'old' constant pool to the 'new'. You need to use this ctor if the | |||
* annotation is being copied from one file to another. | |||
*/ | |||
public SimpleElementValueGen(SimpleElementValueGen value, ConstantPool cpool, boolean copyPoolEntries) { | |||
super(value.getElementValueType(), cpool); | |||
if (!copyPoolEntries) { | |||
// J5ASSERT: Could assert value.stringifyValue() is the same as | |||
// cpool.getConstant(SimpleElementValuevalue.getIndex()) | |||
idx = value.getIndex(); | |||
} else { | |||
switch (value.getElementValueType()) { | |||
case STRING: idx = cpool.addUtf8(value.getValueString()); break; | |||
case PRIMITIVE_INT: idx = cpool.addInteger(value.getValueInt()); break; | |||
case PRIMITIVE_BYTE: idx = cpool.addInteger(value.getValueByte()); break; | |||
case PRIMITIVE_CHAR: idx = cpool.addInteger(value.getValueChar()); break; | |||
case PRIMITIVE_LONG: idx = cpool.addLong(value.getValueLong()); break; | |||
case PRIMITIVE_FLOAT: idx = cpool.addFloat(value.getValueFloat());break; | |||
case PRIMITIVE_DOUBLE:idx = cpool.addDouble(value.getValueDouble());break; | |||
case PRIMITIVE_BOOLEAN: | |||
if (value.getValueBoolean()) { idx = cpool.addInteger(1); | |||
} else { idx = cpool.addInteger(0);} | |||
break; | |||
case PRIMITIVE_SHORT: idx = cpool.addInteger(value.getValueShort());break; | |||
default: | |||
throw new RuntimeException("SimpleElementValueGen class does not know how "+ | |||
"to copy this type "+type); | |||
case STRING: | |||
idx = cpool.addUtf8(value.getValueString()); | |||
break; | |||
case PRIMITIVE_INT: | |||
idx = cpool.addInteger(value.getValueInt()); | |||
break; | |||
case PRIMITIVE_BYTE: | |||
idx = cpool.addInteger(value.getValueByte()); | |||
break; | |||
case PRIMITIVE_CHAR: | |||
idx = cpool.addInteger(value.getValueChar()); | |||
break; | |||
case PRIMITIVE_LONG: | |||
idx = cpool.addLong(value.getValueLong()); | |||
break; | |||
case PRIMITIVE_FLOAT: | |||
idx = cpool.addFloat(value.getValueFloat()); | |||
break; | |||
case PRIMITIVE_DOUBLE: | |||
idx = cpool.addDouble(value.getValueDouble()); | |||
break; | |||
case PRIMITIVE_BOOLEAN: | |||
if (value.getValueBoolean()) { | |||
idx = cpool.addInteger(1); | |||
} else { | |||
idx = cpool.addInteger(0); | |||
} | |||
break; | |||
case PRIMITIVE_SHORT: | |||
idx = cpool.addInteger(value.getValueShort()); | |||
break; | |||
default: | |||
throw new RuntimeException("SimpleElementValueGen class does not know how " + "to copy this type " + type); | |||
} | |||
} | |||
} | |||
/** | |||
* Return immutable variant | |||
*/ | |||
* Return immutable variant | |||
*/ | |||
public ElementValueGen getElementValue() { | |||
return new SimpleElementValueGen(type,idx,cpGen); | |||
return new SimpleElementValueGen(type, idx, cpGen); | |||
} | |||
public int getIndex() { | |||
return idx; | |||
} | |||
return idx; | |||
} | |||
public String getValueString() { | |||
if (type != STRING) | |||
throw new RuntimeException("Dont call getValueString() on a non STRING ElementValue"); | |||
ConstantUtf8 c = (ConstantUtf8)cpGen.getConstant(idx); | |||
public String getValueString() { | |||
if (type != STRING) | |||
throw new RuntimeException("Dont call getValueString() on a non STRING ElementValue"); | |||
ConstantUtf8 c = (ConstantUtf8) cpGen.getConstant(idx); | |||
return c.getBytes(); | |||
} | |||
public int getValueInt() { | |||
if (type != PRIMITIVE_INT) | |||
throw new RuntimeException("Dont call getValueString() on a non STRING ElementValue"); | |||
ConstantInteger c = (ConstantInteger)cpGen.getConstant(idx); | |||
} | |||
public int getValueInt() { | |||
if (type != PRIMITIVE_INT) | |||
throw new RuntimeException("Dont call getValueString() on a non STRING ElementValue"); | |||
ConstantInteger c = (ConstantInteger) cpGen.getConstant(idx); | |||
return c.getBytes(); | |||
} | |||
// Whatever kind of value it is, return it as a string | |||
public String stringifyValue() { | |||
switch (type) { | |||
case PRIMITIVE_INT: | |||
ConstantInteger c = (ConstantInteger)cpGen.getConstant(idx); | |||
return Integer.toString(c.getBytes()); | |||
case PRIMITIVE_LONG: | |||
ConstantLong j = (ConstantLong)cpGen.getConstant(idx); | |||
return Long.toString(j.getBytes()); | |||
case PRIMITIVE_DOUBLE: | |||
ConstantDouble d = (ConstantDouble)cpGen.getConstant(idx); | |||
return Double.toString(d.getBytes()); | |||
case PRIMITIVE_FLOAT: | |||
ConstantFloat f = (ConstantFloat)cpGen.getConstant(idx); | |||
return Float.toString(f.getBytes()); | |||
case PRIMITIVE_SHORT: | |||
ConstantInteger s = (ConstantInteger)cpGen.getConstant(idx); | |||
return Integer.toString(s.getBytes()); | |||
case PRIMITIVE_BYTE: | |||
ConstantInteger b = (ConstantInteger)cpGen.getConstant(idx); | |||
return Integer.toString(b.getBytes()); | |||
case PRIMITIVE_CHAR: | |||
ConstantInteger ch = (ConstantInteger)cpGen.getConstant(idx); | |||
return new Character((char)ch.getBytes()).toString(); | |||
case PRIMITIVE_BOOLEAN: | |||
ConstantInteger bo = (ConstantInteger)cpGen.getConstant(idx); | |||
if (bo.getBytes() == 0) return "false"; | |||
else return "true"; | |||
case STRING: | |||
ConstantUtf8 cu8 = (ConstantUtf8)cpGen.getConstant(idx); | |||
return cu8.getBytes(); | |||
default: | |||
throw new RuntimeException("SimpleElementValueGen class does not know how to stringify type "+type); | |||
} | |||
} | |||
public void dump(DataOutputStream dos) throws IOException { | |||
dos.writeByte(type); // u1 kind of value | |||
switch (type) { | |||
case PRIMITIVE_INT: | |||
case PRIMITIVE_BYTE: | |||
case PRIMITIVE_CHAR: | |||
case PRIMITIVE_FLOAT: | |||
case PRIMITIVE_LONG: | |||
case PRIMITIVE_BOOLEAN: | |||
case PRIMITIVE_SHORT: | |||
case PRIMITIVE_DOUBLE: | |||
case STRING: | |||
dos.writeShort(idx); | |||
break; | |||
default: | |||
throw new RuntimeException("SimpleElementValueGen doesnt know how to write out type "+type); | |||
} | |||
} | |||
} | |||
// Whatever kind of value it is, return it as a string | |||
@Override | |||
public String stringifyValue() { | |||
switch (type) { | |||
case PRIMITIVE_INT: | |||
ConstantInteger c = (ConstantInteger) cpGen.getConstant(idx); | |||
return Integer.toString(c.getBytes()); | |||
case PRIMITIVE_LONG: | |||
ConstantLong j = (ConstantLong) cpGen.getConstant(idx); | |||
return Long.toString(j.getBytes()); | |||
case PRIMITIVE_DOUBLE: | |||
ConstantDouble d = (ConstantDouble) cpGen.getConstant(idx); | |||
return Double.toString(d.getBytes()); | |||
case PRIMITIVE_FLOAT: | |||
ConstantFloat f = (ConstantFloat) cpGen.getConstant(idx); | |||
return Float.toString(f.getBytes()); | |||
case PRIMITIVE_SHORT: | |||
ConstantInteger s = (ConstantInteger) cpGen.getConstant(idx); | |||
return Integer.toString(s.getBytes()); | |||
case PRIMITIVE_BYTE: | |||
ConstantInteger b = (ConstantInteger) cpGen.getConstant(idx); | |||
return Integer.toString(b.getBytes()); | |||
case PRIMITIVE_CHAR: | |||
ConstantInteger ch = (ConstantInteger) cpGen.getConstant(idx); | |||
return new Character((char) ch.getBytes()).toString(); | |||
case PRIMITIVE_BOOLEAN: | |||
ConstantInteger bo = (ConstantInteger) cpGen.getConstant(idx); | |||
if (bo.getBytes() == 0) | |||
return "false"; | |||
else | |||
return "true"; | |||
case STRING: | |||
ConstantUtf8 cu8 = (ConstantUtf8) cpGen.getConstant(idx); | |||
return cu8.getBytes(); | |||
default: | |||
throw new RuntimeException("SimpleElementValueGen class does not know how to stringify type " + type); | |||
} | |||
} | |||
@Override | |||
public void dump(DataOutputStream dos) throws IOException { | |||
dos.writeByte(type); // u1 kind of value | |||
switch (type) { | |||
case PRIMITIVE_INT: | |||
case PRIMITIVE_BYTE: | |||
case PRIMITIVE_CHAR: | |||
case PRIMITIVE_FLOAT: | |||
case PRIMITIVE_LONG: | |||
case PRIMITIVE_BOOLEAN: | |||
case PRIMITIVE_SHORT: | |||
case PRIMITIVE_DOUBLE: | |||
case STRING: | |||
dos.writeShort(idx); | |||
break; | |||
default: | |||
throw new RuntimeException("SimpleElementValueGen doesnt know how to write out type " + type); | |||
} | |||
} | |||
} |
@@ -63,14 +63,12 @@ import java.util.Arrays; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.Comparator; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import org.aspectj.apache.bcel.Constants; | |||
import org.aspectj.apache.bcel.classfile.Attribute; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
import org.aspectj.apache.bcel.classfile.Field; | |||
import org.aspectj.apache.bcel.classfile.FieldOrMethod; | |||
import org.aspectj.apache.bcel.classfile.JavaClass; | |||
import org.aspectj.apache.bcel.classfile.Method; | |||
import org.aspectj.apache.bcel.classfile.Modifiers; | |||
@@ -81,149 +79,103 @@ import org.aspectj.apache.bcel.classfile.annotation.RuntimeInvisibleAnnotations; | |||
import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisibleAnnotations; | |||
/** | |||
* Template class for building up a java class. May be initialized with an existing java class (file). | |||
* Template class for building up a java class. May be initialized with an existing java class. | |||
* | |||
* @see JavaClass | |||
* @version $Id: ClassGen.java,v 1.13 2009/09/09 23:13:20 aclement Exp $ | |||
* @version $Id: ClassGen.java,v 1.14 2009/09/10 03:59:34 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* | |||
* Upgraded, Andy Clement 9th Mar 06 - calculates SUID | |||
*/ | |||
public class ClassGen extends Modifiers implements Cloneable { | |||
private String class_name, super_class_name, file_name; | |||
private int class_name_index = -1, superclass_name_index = -1; | |||
private int major = Constants.MAJOR_1_1, minor = Constants.MINOR_1_1; | |||
private ConstantPool cp; | |||
private List<Field> field_vec = new ArrayList<Field>(); | |||
private List<Method> method_vec = new ArrayList<Method>(); | |||
private String classname; | |||
private String superclassname; | |||
private String filename; | |||
private int classnameIndex = -1; | |||
private int superclassnameIndex = -1; | |||
private int major = Constants.MAJOR_1_1; | |||
private int minor = Constants.MINOR_1_1; | |||
private ConstantPool cpool; | |||
private List<Field> fieldsList = new ArrayList<Field>(); | |||
private List<Method> methodsList = new ArrayList<Method>(); | |||
private List<Attribute> attributesList = new ArrayList<Attribute>(); | |||
private List<String> interface_vec = new ArrayList<String>(); | |||
private List<String> interfaceList = new ArrayList<String>(); | |||
private List<AnnotationGen> annotationsList = new ArrayList<AnnotationGen>(); | |||
/** | |||
* Convenience constructor to set up some important values initially. | |||
* | |||
* @param class_name fully qualified class name | |||
* @param super_class_name fully qualified superclass name | |||
* @param file_name source file name | |||
* @param access_flags access qualifiers | |||
* @param interfaces implemented interfaces | |||
* @param cp constant pool to use | |||
*/ | |||
public ClassGen(String class_name, String super_class_name, String file_name, int access_flags, String[] interfaces, | |||
ConstantPool cp) { | |||
this.class_name = class_name; | |||
this.super_class_name = super_class_name; | |||
this.file_name = file_name; | |||
this.modifiers = access_flags; | |||
this.cp = cp; | |||
// Put everything needed by default into the constant pool and the vectors | |||
if (file_name != null) { | |||
addAttribute(new SourceFile(cp.addUtf8("SourceFile"), 2, cp.addUtf8(file_name), cp)); | |||
public ClassGen(String classname, String superclassname, String filename, int modifiers, String[] interfacenames, | |||
ConstantPool cpool) { | |||
this.classname = classname; | |||
this.superclassname = superclassname; | |||
this.filename = filename; | |||
this.modifiers = modifiers; | |||
this.cpool = cpool; | |||
if (filename != null) { | |||
addAttribute(new SourceFile(cpool.addUtf8("SourceFile"), 2, cpool.addUtf8(filename), cpool)); | |||
} | |||
class_name_index = cp.addClass(class_name); | |||
superclass_name_index = cp.addClass(super_class_name); | |||
if (interfaces != null) { | |||
for (int i = 0; i < interfaces.length; i++) | |||
addInterface(interfaces[i]); | |||
this.classnameIndex = cpool.addClass(classname); | |||
this.superclassnameIndex = cpool.addClass(superclassname); | |||
if (interfacenames != null) { | |||
for (String interfacename : interfacenames) { | |||
addInterface(interfacename); | |||
} | |||
} | |||
} | |||
/** | |||
* Convenience constructor to set up some important values initially. | |||
* | |||
* @param class_name fully qualified class name | |||
* @param super_class_name fully qualified superclass name | |||
* @param file_name source file name | |||
* @param access_flags access qualifiers | |||
* @param interfaces implemented interfaces | |||
*/ | |||
public ClassGen(String class_name, String super_class_name, String file_name, int access_flags, String[] interfaces) { | |||
this(class_name, super_class_name, file_name, access_flags, interfaces, new ConstantPool()); | |||
public ClassGen(String classname, String superclassname, String filename, int modifiers, String[] interfacenames) { | |||
this(classname, superclassname, filename, modifiers, interfacenames, new ConstantPool()); | |||
} | |||
/** | |||
* Initialize with existing class. | |||
* | |||
* @param clazz JavaClass object (e.g. read from file) | |||
*/ | |||
public ClassGen(JavaClass clazz) { | |||
class_name_index = clazz.getClassNameIndex(); | |||
superclass_name_index = clazz.getSuperclassNameIndex(); | |||
class_name = clazz.getClassName(); | |||
super_class_name = clazz.getSuperclassName(); | |||
file_name = clazz.getSourceFileName(); | |||
classnameIndex = clazz.getClassNameIndex(); | |||
superclassnameIndex = clazz.getSuperclassNameIndex(); | |||
classname = clazz.getClassName(); | |||
superclassname = clazz.getSuperclassName(); | |||
filename = clazz.getSourceFileName(); | |||
modifiers = clazz.getModifiers(); | |||
cp = clazz.getConstantPool().copy(); | |||
cpool = clazz.getConstantPool().copy(); | |||
major = clazz.getMajor(); | |||
minor = clazz.getMinor(); | |||
Attribute[] attributes = clazz.getAttributes(); | |||
// J5TODO: Could make unpacking lazy, done on first reference | |||
AnnotationGen[] annotations = unpackAnnotations(attributes); | |||
Method[] methods = clazz.getMethods(); | |||
Field[] fields = clazz.getFields(); | |||
String[] interfaces = clazz.getInterfaceNames(); | |||
for (int i = 0; i < interfaces.length; i++) | |||
for (int i = 0; i < interfaces.length; i++) { | |||
addInterface(interfaces[i]); | |||
// Attribute[] attrs = attributes.getAttributes(); | |||
for (int i = 0; i < attributes.length; i++) { | |||
// Dont add attributes for annotations as those will have been unpacked | |||
if (annotations.length == 0) { | |||
addAttribute(attributes[i]); | |||
} else if (!attributes[i].getName().equals("RuntimeVisibleAnnotations") | |||
&& !attributes[i].getName().equals("RuntimeInvisibleAnnotations")) { | |||
addAttribute(attributes[i]); | |||
} | |||
} | |||
for (int i = 0; i < annotations.length; i++) | |||
addAnnotation(annotations[i]); | |||
for (int i = 0; i < methods.length; i++) { | |||
Method m = methods[i]; | |||
addMethod(m); | |||
} | |||
for (int i = 0; i < fields.length; i++) | |||
addField(fields[i]); | |||
} | |||
/** | |||
* Look for attributes representing annotations and unpack them. | |||
*/ | |||
private AnnotationGen[] unpackAnnotations(Attribute[] attrs) { | |||
List<AnnotationGen> annotationGenObjs = new ArrayList<AnnotationGen>(); | |||
for (int i = 0; i < attrs.length; i++) { | |||
Attribute attr = attrs[i]; | |||
// OPTIMIZE Could make unpacking lazy, done on first reference | |||
Attribute[] attributes = clazz.getAttributes(); | |||
for (Attribute attr : attributes) { | |||
if (attr instanceof RuntimeVisibleAnnotations) { | |||
RuntimeVisibleAnnotations rva = (RuntimeVisibleAnnotations) attr; | |||
List<AnnotationGen> annos = rva.getAnnotations(); | |||
for (Iterator<AnnotationGen> iter = annos.iterator(); iter.hasNext();) { | |||
AnnotationGen a = iter.next(); | |||
annotationGenObjs.add(new AnnotationGen(a, getConstantPool(), false)); | |||
for (AnnotationGen a : annos) { | |||
annotationsList.add(new AnnotationGen(a, cpool, false)); | |||
} | |||
} else if (attr instanceof RuntimeInvisibleAnnotations) { | |||
RuntimeInvisibleAnnotations ria = (RuntimeInvisibleAnnotations) attr; | |||
List<AnnotationGen> annos = ria.getAnnotations(); | |||
for (Iterator<AnnotationGen> iter = annos.iterator(); iter.hasNext();) { | |||
AnnotationGen a = iter.next(); | |||
annotationGenObjs.add(new AnnotationGen(a, getConstantPool(), false)); | |||
for (AnnotationGen anno : annos) { | |||
annotationsList.add(new AnnotationGen(anno, cpool, false)); | |||
} | |||
} else { | |||
attributesList.add(attr); | |||
} | |||
} | |||
return annotationGenObjs.toArray(new AnnotationGen[] {}); | |||
for (int i = 0; i < methods.length; i++) { | |||
addMethod(methods[i]); | |||
} | |||
for (int i = 0; i < fields.length; i++) { | |||
addField(fields[i]); | |||
} | |||
} | |||
/** | |||
* @return the (finally) built up Java class object. | |||
* @return build and return a JavaClass | |||
*/ | |||
public JavaClass getJavaClass() { | |||
int[] interfaces = getInterfaces(); | |||
@@ -236,72 +188,41 @@ public class ClassGen extends Modifiers implements Cloneable { | |||
} else { | |||
// TODO: Sometime later, trash any attributes called 'RuntimeVisibleAnnotations' or 'RuntimeInvisibleAnnotations' | |||
attributes = new ArrayList<Attribute>(); | |||
attributes.addAll(Utility.getAnnotationAttributes(cp, annotationsList)); | |||
attributes.addAll(Utility.getAnnotationAttributes(cpool, annotationsList)); | |||
attributes.addAll(attributesList); | |||
} | |||
// Must be last since the above calls may still add something to it | |||
ConstantPool cp = this.cp.getFinalConstantPool(); | |||
ConstantPool cp = this.cpool.getFinalConstantPool(); | |||
return new JavaClass(class_name_index, superclass_name_index, file_name, major, minor, modifiers, cp, interfaces, fields, | |||
return new JavaClass(classnameIndex, superclassnameIndex, filename, major, minor, modifiers, cp, interfaces, fields, | |||
methods, attributes.toArray(new Attribute[attributes.size()]));// OPTIMIZE avoid toArray()? | |||
} | |||
/** | |||
* Add an interface to this class, i.e., this class has to implement it. | |||
* | |||
* @param name interface to implement (fully qualified class name) | |||
*/ | |||
public void addInterface(String name) { | |||
interface_vec.add(name); | |||
interfaceList.add(name); | |||
} | |||
/** | |||
* Remove an interface from this class. | |||
* | |||
* @param name interface to remove (fully qualified name) | |||
*/ | |||
public void removeInterface(String name) { | |||
interface_vec.remove(name); | |||
interfaceList.remove(name); | |||
} | |||
/** | |||
* @return major version number of class file | |||
*/ | |||
public int getMajor() { | |||
return major; | |||
} | |||
/** | |||
* Set major version number of class file, default value is 45 (JDK 1.1) | |||
* | |||
* @param major major version number | |||
*/ | |||
public void setMajor(int major) { | |||
this.major = major; | |||
} | |||
/** | |||
* Set minor version number of class file, default value is 3 (JDK 1.1) | |||
* | |||
* @param minor minor version number | |||
*/ | |||
public void setMinor(int minor) { | |||
this.minor = minor; | |||
} | |||
/** | |||
* @return minor version number of class file | |||
*/ | |||
public int getMinor() { | |||
return minor; | |||
} | |||
/** | |||
* Add an attribute to this class. | |||
* | |||
* @param a attribute to add | |||
*/ | |||
public void addAttribute(Attribute a) { | |||
attributesList.add(a); | |||
} | |||
@@ -310,13 +231,8 @@ public class ClassGen extends Modifiers implements Cloneable { | |||
annotationsList.add(a); | |||
} | |||
/** | |||
* Add a method to this class. | |||
* | |||
* @param m method to add | |||
*/ | |||
public void addMethod(Method m) { | |||
method_vec.add(m); | |||
methodsList.add(m); | |||
} | |||
/** | |||
@@ -329,10 +245,10 @@ public class ClassGen extends Modifiers implements Cloneable { | |||
public void addEmptyConstructor(int access_flags) { | |||
InstructionList il = new InstructionList(); | |||
il.append(InstructionConstants.THIS); // Push `this' | |||
il.append(new InvokeInstruction(Constants.INVOKESPECIAL, cp.addMethodref(super_class_name, "<init>", "()V"))); | |||
il.append(new InvokeInstruction(Constants.INVOKESPECIAL, cpool.addMethodref(superclassname, "<init>", "()V"))); | |||
il.append(InstructionConstants.RETURN); | |||
MethodGen mg = new MethodGen(access_flags, Type.VOID, Type.NO_ARGS, null, "<init>", class_name, il, cp); | |||
MethodGen mg = new MethodGen(access_flags, Type.VOID, Type.NO_ARGS, null, "<init>", classname, il, cpool); | |||
mg.setMaxStack(1); | |||
mg.setMaxLocals(); | |||
addMethod(mg.getMethod()); | |||
@@ -344,44 +260,37 @@ public class ClassGen extends Modifiers implements Cloneable { | |||
* @param f field to add | |||
*/ | |||
public void addField(Field f) { | |||
field_vec.add(f); | |||
fieldsList.add(f); | |||
} | |||
public boolean containsField(Field f) { | |||
return field_vec.contains(f); | |||
return fieldsList.contains(f); | |||
} | |||
/** | |||
* @return field object with given name, or null | |||
* @return field object with given name, or null if not found | |||
*/ | |||
public Field containsField(String name) { | |||
for (Iterator<Field> e = field_vec.iterator(); e.hasNext();) { | |||
Field f = e.next(); | |||
if (f.getName().equals(name)) | |||
return f; | |||
for (Field field : fieldsList) { | |||
if (field.getName().equals(name)) { | |||
return field; | |||
} | |||
} | |||
return null; | |||
} | |||
/** | |||
* @return method object with given name and signature, or null | |||
* @return method object with given name and signature, or null if not found | |||
*/ | |||
public Method containsMethod(String name, String signature) { | |||
for (Iterator<Method> e = method_vec.iterator(); e.hasNext();) { | |||
Method m = e.next(); | |||
if (m.getName().equals(name) && m.getSignature().equals(signature)) | |||
return m; | |||
for (Method method : methodsList) { | |||
if (method.getName().equals(name) && method.getSignature().equals(signature)) { | |||
return method; | |||
} | |||
} | |||
return null; | |||
} | |||
/** | |||
* Remove an attribute from this class. | |||
* | |||
* @param a attribute to remove | |||
*/ | |||
public void removeAttribute(Attribute a) { | |||
attributesList.remove(a); | |||
} | |||
@@ -390,13 +299,8 @@ public class ClassGen extends Modifiers implements Cloneable { | |||
annotationsList.remove(a); | |||
} | |||
/** | |||
* Remove a method from this class. | |||
* | |||
* @param m method to remove | |||
*/ | |||
public void removeMethod(Method m) { | |||
method_vec.remove(m); | |||
methodsList.remove(m); | |||
} | |||
/** | |||
@@ -406,12 +310,12 @@ public class ClassGen extends Modifiers implements Cloneable { | |||
if (new_ == null) | |||
throw new ClassGenException("Replacement method must not be null"); | |||
int i = method_vec.indexOf(old); | |||
int i = methodsList.indexOf(old); | |||
if (i < 0) | |||
method_vec.add(new_); | |||
methodsList.add(new_); | |||
else | |||
method_vec.set(i, new_); | |||
methodsList.set(i, new_); | |||
} | |||
/** | |||
@@ -421,92 +325,87 @@ public class ClassGen extends Modifiers implements Cloneable { | |||
if (new_ == null) | |||
throw new ClassGenException("Replacement method must not be null"); | |||
int i = field_vec.indexOf(old); | |||
int i = fieldsList.indexOf(old); | |||
if (i < 0) | |||
field_vec.add(new_); | |||
fieldsList.add(new_); | |||
else | |||
field_vec.set(i, new_); | |||
fieldsList.set(i, new_); | |||
} | |||
/** | |||
* Remove a field to this class. | |||
* | |||
* @param f field to remove | |||
*/ | |||
public void removeField(Field f) { | |||
field_vec.remove(f); | |||
fieldsList.remove(f); | |||
} | |||
public String getClassName() { | |||
return class_name; | |||
return classname; | |||
} | |||
public String getSuperclassName() { | |||
return super_class_name; | |||
return superclassname; | |||
} | |||
public String getFileName() { | |||
return file_name; | |||
return filename; | |||
} | |||
public void setClassName(String name) { | |||
class_name = name.replace('/', '.'); | |||
class_name_index = cp.addClass(name); | |||
classname = name.replace('/', '.'); | |||
classnameIndex = cpool.addClass(name); | |||
} | |||
public void setSuperclassName(String name) { | |||
super_class_name = name.replace('/', '.'); | |||
superclass_name_index = cp.addClass(name); | |||
superclassname = name.replace('/', '.'); | |||
superclassnameIndex = cpool.addClass(name); | |||
} | |||
public Method[] getMethods() { | |||
Method[] methods = new Method[method_vec.size()]; | |||
method_vec.toArray(methods); | |||
Method[] methods = new Method[methodsList.size()]; | |||
methodsList.toArray(methods); | |||
return methods; | |||
} | |||
public void setMethods(Method[] methods) { | |||
method_vec.clear(); | |||
methodsList.clear(); | |||
for (int m = 0; m < methods.length; m++) | |||
addMethod(methods[m]); | |||
} | |||
public void setFields(Field[] fs) { | |||
field_vec.clear(); | |||
fieldsList.clear(); | |||
for (int m = 0; m < fs.length; m++) | |||
addField(fs[m]); | |||
} | |||
public void setMethodAt(Method method, int pos) { | |||
method_vec.set(pos, method); | |||
methodsList.set(pos, method); | |||
} | |||
public Method getMethodAt(int pos) { | |||
return method_vec.get(pos); | |||
return methodsList.get(pos); | |||
} | |||
public String[] getInterfaceNames() { | |||
int size = interface_vec.size(); | |||
int size = interfaceList.size(); | |||
String[] interfaces = new String[size]; | |||
interface_vec.toArray(interfaces); | |||
interfaceList.toArray(interfaces); | |||
return interfaces; | |||
} | |||
public int[] getInterfaces() { | |||
int size = interface_vec.size(); | |||
int size = interfaceList.size(); | |||
int[] interfaces = new int[size]; | |||
for (int i = 0; i < size; i++) | |||
interfaces[i] = cp.addClass(interface_vec.get(i)); | |||
interfaces[i] = cpool.addClass(interfaceList.get(i)); | |||
return interfaces; | |||
} | |||
public Field[] getFields() { | |||
Field[] fields = new Field[field_vec.size()]; | |||
field_vec.toArray(fields); | |||
Field[] fields = new Field[fieldsList.size()]; | |||
fieldsList.toArray(fields); | |||
return fields; | |||
} | |||
@@ -522,29 +421,29 @@ public class ClassGen extends Modifiers implements Cloneable { | |||
} | |||
public ConstantPool getConstantPool() { | |||
return cp; | |||
return cpool; | |||
} | |||
public void setConstantPool(ConstantPool constant_pool) { | |||
cp = constant_pool; | |||
cpool = constant_pool; | |||
} | |||
public void setClassNameIndex(int class_name_index) { | |||
this.class_name_index = class_name_index; | |||
class_name = cp.getConstantString(class_name_index, Constants.CONSTANT_Class).replace('/', '.'); | |||
this.classnameIndex = class_name_index; | |||
classname = cpool.getConstantString(class_name_index, Constants.CONSTANT_Class).replace('/', '.'); | |||
} | |||
public void setSuperclassNameIndex(int superclass_name_index) { | |||
this.superclass_name_index = superclass_name_index; | |||
super_class_name = cp.getConstantString(superclass_name_index, Constants.CONSTANT_Class).replace('/', '.'); | |||
this.superclassnameIndex = superclass_name_index; | |||
superclassname = cpool.getConstantString(superclass_name_index, Constants.CONSTANT_Class).replace('/', '.'); | |||
} | |||
public int getSuperclassNameIndex() { | |||
return superclass_name_index; | |||
return superclassnameIndex; | |||
} | |||
public int getClassNameIndex() { | |||
return class_name_index; | |||
return classnameIndex; | |||
} | |||
@Override | |||
@@ -557,18 +456,10 @@ public class ClassGen extends Modifiers implements Cloneable { | |||
} | |||
} | |||
// J5SUPPORT: | |||
/** | |||
* Returns true if this class represents an annotation type | |||
*/ | |||
public final boolean isAnnotation() { | |||
return (modifiers & Constants.ACC_ANNOTATION) != 0; | |||
} | |||
/** | |||
* Returns true if this class represents an enum type | |||
*/ | |||
public final boolean isEnum() { | |||
return (modifiers & Constants.ACC_ENUM) != 0; | |||
} | |||
@@ -578,8 +469,6 @@ public class ClassGen extends Modifiers implements Cloneable { | |||
*/ | |||
public long getSUID() { | |||
try { | |||
Field[] fields = getFields(); | |||
Method[] methods = getMethods(); | |||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |||
DataOutputStream dos = new DataOutputStream(baos); | |||
@@ -596,7 +485,7 @@ public class ClassGen extends Modifiers implements Cloneable { | |||
if (isAbstract()) { | |||
// if an interface then abstract is only set if it has methods | |||
if (isInterface()) { | |||
if (methods.length > 0) | |||
if (methodsList.size() > 0) | |||
classmods |= Constants.ACC_ABSTRACT; | |||
} else { | |||
classmods |= Constants.ACC_ABSTRACT; | |||
@@ -606,7 +495,6 @@ public class ClassGen extends Modifiers implements Cloneable { | |||
dos.writeInt(classmods); | |||
// 3. ordered list of interfaces | |||
List<FieldOrMethod> list = new ArrayList<FieldOrMethod>(); | |||
String[] names = getInterfaceNames(); | |||
if (names != null) { | |||
Arrays.sort(names); | |||
@@ -618,41 +506,39 @@ public class ClassGen extends Modifiers implements Cloneable { | |||
// (relevant modifiers are ACC_PUBLIC, ACC_PRIVATE, | |||
// ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_VOLATILE, | |||
// ACC_TRANSIENT) | |||
list.clear(); | |||
for (int i = 0; i < fields.length; i++) { | |||
Field field = fields[i]; | |||
if (!(field.isPrivate() && field.isStatic()) && !(field.isPrivate() && field.isTransient())) | |||
list.add(field); | |||
List<Field> relevantFields = new ArrayList<Field>(); | |||
for (Field field : fieldsList) { | |||
if (!(field.isPrivate() && field.isStatic()) && !(field.isPrivate() && field.isTransient())) { | |||
relevantFields.add(field); | |||
} | |||
} | |||
Collections.sort(list, new FieldComparator()); | |||
Collections.sort(relevantFields, new FieldComparator()); | |||
int relevantFlags = Constants.ACC_PUBLIC | Constants.ACC_PRIVATE | Constants.ACC_PROTECTED | Constants.ACC_STATIC | |||
| Constants.ACC_FINAL | Constants.ACC_VOLATILE | Constants.ACC_TRANSIENT; | |||
for (Iterator<FieldOrMethod> iter = list.iterator(); iter.hasNext();) { | |||
Field f = (Field) iter.next(); | |||
for (Field f : relevantFields) { | |||
dos.writeUTF(f.getName()); | |||
dos.writeInt(relevantFlags & f.getModifiers()); | |||
dos.writeUTF(f.getType().getSignature()); | |||
} | |||
// some up front method processing: discover clinit, init and ordinary methods of interest: | |||
list.clear(); // now used for methods | |||
List<Method> ctors = new ArrayList<Method>(); | |||
List<Method> relevantMethods = new ArrayList<Method>(); | |||
List<Method> relevantCtors = new ArrayList<Method>(); | |||
boolean hasClinit = false; | |||
for (int i = 0; i < methods.length; i++) { | |||
Method m = methods[i]; | |||
for (Method m : methodsList) { | |||
boolean couldBeInitializer = m.getName().charAt(0) == '<'; | |||
if (couldBeInitializer && m.getName().equals("<clinit>")) { | |||
hasClinit = true; | |||
} else if (couldBeInitializer && m.getName().equals("<init>")) { | |||
if (!m.isPrivate()) | |||
ctors.add(m); | |||
relevantCtors.add(m); | |||
} else { | |||
if (!m.isPrivate()) | |||
list.add(m); | |||
relevantMethods.add(m); | |||
} | |||
} | |||
Collections.sort(ctors, new ConstructorComparator()); | |||
Collections.sort(list, new MethodComparator()); | |||
Collections.sort(relevantCtors, new ConstructorComparator()); | |||
Collections.sort(relevantMethods, new MethodComparator()); | |||
// 5. If a class initializer exists, write out the following: | |||
// 1. The name of the method, <clinit>. | |||
@@ -672,16 +558,14 @@ public class ClassGen extends Modifiers implements Cloneable { | |||
| Constants.ACC_STRICT; | |||
// 6. sorted non-private constructors | |||
for (Iterator<Method> iter = ctors.iterator(); iter.hasNext();) { | |||
Method m = iter.next(); | |||
dos.writeUTF(m.getName()); // <init> | |||
dos.writeInt(relevantFlags & m.getModifiers()); | |||
dos.writeUTF(m.getSignature().replace('/', '.')); | |||
for (Method ctor : relevantCtors) { | |||
dos.writeUTF(ctor.getName()); // <init> | |||
dos.writeInt(relevantFlags & ctor.getModifiers()); | |||
dos.writeUTF(ctor.getSignature().replace('/', '.')); | |||
} | |||
// 7. sorted non-private methods | |||
for (Iterator<FieldOrMethod> iter = list.iterator(); iter.hasNext();) { | |||
Method m = (Method) iter.next(); | |||
for (Method m : relevantMethods) { | |||
dos.writeUTF(m.getName()); | |||
dos.writeInt(relevantFlags & m.getModifiers()); | |||
dos.writeUTF(m.getSignature().replace('/', '.')); | |||
@@ -705,33 +589,31 @@ public class ClassGen extends Modifiers implements Cloneable { | |||
// (long)(sha[6]&0xff) << 48 | (long)(sha[7]&0xff) << 56); | |||
return suid; | |||
} catch (Exception e) { | |||
System.err.println("Unable to calculate suid for " + getClassName()); | |||
e.printStackTrace(); | |||
throw new RuntimeException("Unable to calculate suid for " + getClassName() + ": " + e.toString()); | |||
} | |||
} | |||
private static class FieldComparator implements Comparator { | |||
public int compare(Object arg0, Object arg1) { | |||
return ((Field) arg0).getName().compareTo(((Field) arg1).getName()); | |||
private static class FieldComparator implements Comparator<Field> { | |||
public int compare(Field f0, Field f1) { | |||
return f0.getName().compareTo(f1.getName()); | |||
} | |||
} | |||
private static class ConstructorComparator implements Comparator { | |||
public int compare(Object arg0, Object arg1) { | |||
private static class ConstructorComparator implements Comparator<Method> { | |||
public int compare(Method m0, Method m1) { | |||
// can ignore the name... | |||
return ((Method) arg0).getSignature().compareTo(((Method) arg1).getSignature()); | |||
return (m0).getSignature().compareTo(m1.getSignature()); | |||
} | |||
} | |||
private static class MethodComparator implements Comparator { | |||
public int compare(Object arg0, Object arg1) { | |||
Method m1 = (Method) arg0; | |||
Method m2 = (Method) arg1; | |||
int result = m1.getName().compareTo(m2.getName()); | |||
if (result != 0) | |||
return result; | |||
return m1.getSignature().compareTo(m2.getSignature()); | |||
private static class MethodComparator implements Comparator<Method> { | |||
public int compare(Method m0, Method m1) { | |||
int result = m0.getName().compareTo(m1.getName()); | |||
if (result == 0) { | |||
result = m0.getSignature().compareTo(m1.getSignature()); | |||
} | |||
return result; | |||
} | |||
} | |||
@@ -745,10 +627,10 @@ public class ClassGen extends Modifiers implements Cloneable { | |||
} | |||
public Attribute getAttribute(String attributeName) { | |||
for (Iterator<Attribute> iter = attributesList.iterator(); iter.hasNext();) { | |||
Attribute attr = iter.next(); | |||
if (attr.getName().equals(attributeName)) | |||
for (Attribute attr : attributesList) { | |||
if (attr.getName().equals(attributeName)) { | |||
return attr; | |||
} | |||
} | |||
return null; | |||
} |
@@ -55,6 +55,7 @@ package org.aspectj.apache.bcel.generic; | |||
*/ | |||
import org.aspectj.apache.bcel.Constants; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
import org.aspectj.apache.bcel.classfile.Utility; | |||
/** | |||
* Instances of this class may be used, e.g., to generate typed | |||
@@ -62,7 +63,7 @@ import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
* byte code generating backend of a compiler. You can subclass it to | |||
* add your own create methods. | |||
* | |||
* @version $Id: InstructionFactory.java,v 1.5 2008/08/28 00:03:24 aclement Exp $ | |||
* @version $Id: InstructionFactory.java,v 1.6 2009/09/10 03:59:34 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* @see Constants | |||
*/ | |||
@@ -95,7 +96,7 @@ public class InstructionFactory implements InstructionConstants { | |||
public InvokeInstruction createInvoke(String class_name, String name, Type ret_type, | |||
Type[] arg_types, short kind) { | |||
String signature = Type.getMethodSignature(ret_type, arg_types); | |||
String signature = Utility.toMethodSignature(ret_type, arg_types); | |||
int index; | |||
if (kind == Constants.INVOKEINTERFACE) |
@@ -76,7 +76,7 @@ import org.aspectj.apache.bcel.util.ByteSequence; | |||
* | |||
* A list is finally dumped to a byte code array with <a href="#getByteCode()">getByteCode</a>. | |||
* | |||
* @version $Id: InstructionList.java,v 1.8 2009/09/09 19:56:20 aclement Exp $ | |||
* @version $Id: InstructionList.java,v 1.9 2009/09/10 03:59:33 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* @see Instruction | |||
* @see InstructionHandle | |||
@@ -84,27 +84,16 @@ import org.aspectj.apache.bcel.util.ByteSequence; | |||
*/ | |||
public class InstructionList implements Serializable { | |||
private InstructionHandle start = null, end = null; | |||
private int length = 0; // number of elements in list | |||
private int[] byte_positions; // byte code offsets corresponding to instructions | |||
private int length = 0; | |||
private int[] positions; // byte code offsets corresponding to instructions | |||
/** | |||
* Create (empty) instruction list. | |||
*/ | |||
public InstructionList() { | |||
} | |||
/** | |||
* Create instruction list containing one instruction. | |||
* | |||
* @param i initial instruction | |||
*/ | |||
public InstructionList(Instruction i) { | |||
append(i); | |||
} | |||
/** | |||
* Test for empty list. | |||
*/ | |||
public boolean isEmpty() { | |||
return start == null; | |||
} // && end == null | |||
@@ -158,7 +147,7 @@ public class InstructionList implements Serializable { | |||
*/ | |||
public InstructionHandle findHandle(int pos) { | |||
InstructionHandle[] ihs = getInstructionHandles(); | |||
return findHandle(ihs, byte_positions, length, pos); | |||
return findHandle(ihs, positions, length, pos); | |||
} | |||
public InstructionHandle[] getInstructionsAsArray() { | |||
@@ -166,11 +155,11 @@ public class InstructionList implements Serializable { | |||
} | |||
public InstructionHandle findHandle(int pos, InstructionHandle[] instructionArray) { | |||
return findHandle(instructionArray, byte_positions, length, pos); | |||
return findHandle(instructionArray, positions, length, pos); | |||
} | |||
public InstructionHandle findHandle(int pos, InstructionHandle[] instructionArray, boolean useClosestApproximationIfNoExactFound) { | |||
return findHandle(instructionArray, byte_positions, length, pos, useClosestApproximationIfNoExactFound); | |||
return findHandle(instructionArray, positions, length, pos, useClosestApproximationIfNoExactFound); | |||
} | |||
/** | |||
@@ -213,8 +202,8 @@ public class InstructionList implements Serializable { | |||
throw new ClassGenException(e.toString()); | |||
} | |||
byte_positions = new int[count]; // Trim to proper size | |||
System.arraycopy(pos, 0, byte_positions, 0, count); | |||
positions = new int[count]; // Trim to proper size | |||
System.arraycopy(pos, 0, positions, 0, count); | |||
/* | |||
* Pass 2: Look for BranchInstruction and update their targets, i.e., convert offsets to instruction handles. | |||
@@ -945,8 +934,8 @@ public class InstructionList implements Serializable { | |||
index += i.getLength(); | |||
} | |||
byte_positions = new int[count]; // Trim to proper size | |||
System.arraycopy(pos, 0, byte_positions, 0, count); | |||
positions = new int[count]; // Trim to proper size | |||
System.arraycopy(pos, 0, positions, 0, count); | |||
} | |||
/** | |||
@@ -998,6 +987,7 @@ public class InstructionList implements Serializable { | |||
return result; | |||
} | |||
@Override | |||
public String toString() { | |||
return toString(true); | |||
} | |||
@@ -1061,7 +1051,7 @@ public class InstructionList implements Serializable { | |||
* @return array containing all instruction's offset in byte code | |||
*/ | |||
public int[] getInstructionPositions() { | |||
return byte_positions; | |||
return positions; | |||
} | |||
/** |
@@ -84,7 +84,7 @@ import org.aspectj.apache.bcel.classfile.annotation.RuntimeParameterAnnotations; | |||
* While generating code it may be necessary to insert NOP operations. You can use the `removeNOPs' method to get rid off them. The | |||
* resulting method object can be obtained via the `getMethod()' method. | |||
* | |||
* @version $Id: MethodGen.java,v 1.12 2009/09/09 19:56:20 aclement Exp $ | |||
* @version $Id: MethodGen.java,v 1.13 2009/09/10 03:59:34 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* @author <A HREF="http://www.vmeng.com/beard">Patrick C. Beard</A> [setMaxStack()] | |||
* @see InstructionList | |||
@@ -846,7 +846,7 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
} | |||
public String getSignature() { | |||
return Type.getMethodSignature(type, parameterTypes); | |||
return Utility.toMethodSignature(type, parameterTypes); | |||
} | |||
/** | |||
@@ -1016,7 +1016,7 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
*/ | |||
public final String toString() { | |||
String access = Utility.accessToString(modifiers); | |||
String signature = Type.getMethodSignature(type, parameterTypes); | |||
String signature = Utility.toMethodSignature(type, parameterTypes); | |||
signature = Utility.methodSignatureToString(signature, name, access, true, getLocalVariableTable(cp)); | |||
@@ -56,6 +56,7 @@ package org.aspectj.apache.bcel.generic; | |||
import java.util.ArrayList; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.aspectj.apache.bcel.Constants; | |||
@@ -66,14 +67,14 @@ import org.aspectj.apache.bcel.classfile.Utility; | |||
* Abstract super class for all possible java types, namely basic types such as int, object types like String and array types, e.g. | |||
* int[] | |||
* | |||
* @version $Id: Type.java,v 1.11 2009/09/09 19:56:20 aclement Exp $ | |||
* @version $Id: Type.java,v 1.12 2009/09/10 03:59:34 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* | |||
* modified: AndyClement 2-mar-05: Removed unnecessary static and optimized | |||
*/ | |||
public abstract class Type implements java.io.Serializable { | |||
public abstract class Type { | |||
protected byte type; | |||
protected String signature; // signature for the type | |||
protected String signature; | |||
/* Predefined constants */ | |||
public static final BasicType VOID = new BasicType(Constants.T_VOID); | |||
@@ -142,16 +143,10 @@ public abstract class Type implements java.io.Serializable { | |||
signature = s; | |||
} | |||
/** | |||
* @return signature for given type. | |||
*/ | |||
public String getSignature() { | |||
return signature; | |||
} | |||
/** | |||
* @return type as defined in Constants | |||
*/ | |||
public byte getType() { | |||
return type; | |||
} | |||
@@ -180,24 +175,6 @@ public abstract class Type implements java.io.Serializable { | |||
.signatureToString(signature, false); | |||
} | |||
/** | |||
* Convert type to Java method signature, e.g. int[] f(java.lang.String x) becomes (Ljava/lang/String;)[I | |||
* | |||
* @param return_type what the method returns | |||
* @param arg_types what are the argument types | |||
* @return method signature for given type(s). | |||
*/ | |||
public static String getMethodSignature(Type return_type, Type[] arg_types) { | |||
StringBuffer buf = new StringBuffer("("); | |||
int length = (arg_types == null) ? 0 : arg_types.length; | |||
for (int i = 0; i < length; i++) { | |||
buf.append(arg_types[i].getSignature()); | |||
} | |||
buf.append(')'); | |||
buf.append(return_type.getSignature()); | |||
return buf.toString(); | |||
} | |||
public static final Type getType(String signature) { | |||
Type t = commonTypes.get(signature); | |||
if (t != null) | |||
@@ -314,7 +291,7 @@ public abstract class Type implements java.io.Serializable { | |||
*/ | |||
public static Type getReturnType(String signature) { | |||
try { | |||
// Read return type after `)' | |||
// Read return type after ')' | |||
int index = signature.lastIndexOf(')') + 1; | |||
return getType(signature.substring(index)); | |||
} catch (StringIndexOutOfBoundsException e) { // Should never occur | |||
@@ -330,7 +307,7 @@ public abstract class Type implements java.io.Serializable { | |||
*/ | |||
// OPTIMIZE crap impl | |||
public static Type[] getArgumentTypes(String signature) { | |||
ArrayList<Type> vec = new ArrayList<Type>(); | |||
List<Type> argumentTypes = new ArrayList<Type>(); | |||
int index; | |||
Type[] types; | |||
@@ -342,15 +319,15 @@ public abstract class Type implements java.io.Serializable { | |||
while (signature.charAt(index) != ')') { | |||
TypeHolder th = getTypeInternal(signature.substring(index)); | |||
vec.add(th.getType()); | |||
argumentTypes.add(th.getType()); | |||
index += th.getConsumed(); // update position | |||
} | |||
} catch (StringIndexOutOfBoundsException e) { // Should never occur | |||
throw new ClassFormatException("Invalid method signature: " + signature); | |||
} | |||
types = new Type[vec.size()]; | |||
vec.toArray(types); | |||
types = new Type[argumentTypes.size()]; | |||
argumentTypes.toArray(types); | |||
return types; | |||
} | |||
@@ -21,82 +21,76 @@ import org.aspectj.apache.bcel.classfile.EnclosingMethod; | |||
import org.aspectj.apache.bcel.classfile.JavaClass; | |||
import org.aspectj.apache.bcel.util.SyntheticRepository; | |||
public class EnclosingMethodAttributeTest extends BcelTestCase { | |||
@Override | |||
protected void setUp() throws Exception { | |||
super.setUp(); | |||
} | |||
/** | |||
* Verify for an inner class declared inside the 'main' method that the enclosing method | |||
* attribute is set correctly. | |||
* Verify for an inner class declared inside the 'main' method that the enclosing method attribute is set correctly. | |||
*/ | |||
public void testCheckMethodLevelNamedInnerClass() throws ClassNotFoundException { | |||
SyntheticRepository repos = createRepos("testcode.jar"); | |||
JavaClass clazz = repos.loadClass("AttributeTestClassEM01$1S"); | |||
ConstantPool pool = clazz.getConstantPool(); | |||
Attribute[] encMethodAttrs = findAttribute("EnclosingMethod",clazz); | |||
assertTrue("Expected 1 EnclosingMethod attribute but found "+encMethodAttrs.length, | |||
encMethodAttrs.length==1); | |||
EnclosingMethod em = (EnclosingMethod)encMethodAttrs[0]; | |||
String enclosingClassName = em.getEnclosingClass().getBytes(pool); | |||
String enclosingMethodName= em.getEnclosingMethod().getName(pool); | |||
assertTrue("Expected class name to be 'AttributeTestClassEM01' but was "+enclosingClassName, | |||
enclosingClassName.equals("AttributeTestClassEM01")); | |||
assertTrue("Expected method name to be 'main' but was "+enclosingMethodName, | |||
enclosingMethodName.equals("main")); | |||
Attribute[] encMethodAttrs = findAttribute("EnclosingMethod", clazz); | |||
assertTrue("Expected 1 EnclosingMethod attribute but found " + encMethodAttrs.length, encMethodAttrs.length == 1); | |||
EnclosingMethod em = (EnclosingMethod) encMethodAttrs[0]; | |||
String enclosingClassName = em.getEnclosingClass().getConstantValue(pool); | |||
String enclosingMethodName = em.getEnclosingMethod().getName(pool); | |||
assertTrue("Expected class name to be 'AttributeTestClassEM01' but was " + enclosingClassName, enclosingClassName | |||
.equals("AttributeTestClassEM01")); | |||
assertTrue("Expected method name to be 'main' but was " + enclosingMethodName, enclosingMethodName.equals("main")); | |||
} | |||
/** | |||
* Verify for an inner class declared at the type level that the EnclosingMethod attribute | |||
* is set correctly (i.e. to a null value) | |||
* Verify for an inner class declared at the type level that the EnclosingMethod attribute is set correctly (i.e. to a null | |||
* value) | |||
*/ | |||
public void testCheckClassLevelNamedInnerClass() throws ClassNotFoundException { | |||
SyntheticRepository repos = createRepos("testcode.jar"); | |||
JavaClass clazz = repos.loadClass("AttributeTestClassEM02$1"); | |||
ConstantPool pool = clazz.getConstantPool(); | |||
Attribute[] encMethodAttrs = findAttribute("EnclosingMethod",clazz); | |||
assertTrue("Expected 1 EnclosingMethod attribute but found "+encMethodAttrs.length, | |||
encMethodAttrs.length==1); | |||
EnclosingMethod em = (EnclosingMethod)encMethodAttrs[0]; | |||
String enclosingClassName = em.getEnclosingClass().getBytes(pool); | |||
assertTrue("The class is not within a method, so method_index should be null, but it is "+ | |||
em.getEnclosingMethodIndex(),em.getEnclosingMethodIndex() == 0); | |||
assertTrue("Expected class name to be 'AttributeTestClassEM02' but was "+enclosingClassName, | |||
enclosingClassName.equals("AttributeTestClassEM02")); | |||
Attribute[] encMethodAttrs = findAttribute("EnclosingMethod", clazz); | |||
assertTrue("Expected 1 EnclosingMethod attribute but found " + encMethodAttrs.length, encMethodAttrs.length == 1); | |||
EnclosingMethod em = (EnclosingMethod) encMethodAttrs[0]; | |||
String enclosingClassName = em.getEnclosingClass().getConstantValue(pool); | |||
assertTrue("The class is not within a method, so method_index should be null, but it is " + em.getEnclosingMethodIndex(), | |||
em.getEnclosingMethodIndex() == 0); | |||
assertTrue("Expected class name to be 'AttributeTestClassEM02' but was " + enclosingClassName, enclosingClassName | |||
.equals("AttributeTestClassEM02")); | |||
} | |||
/** | |||
* Check that we can save and load the attribute correctly. | |||
*/ | |||
public void testAttributeSerializtion() throws ClassNotFoundException,IOException { | |||
public void testAttributeSerializtion() throws ClassNotFoundException, IOException { | |||
// Read in the class | |||
SyntheticRepository repos = createRepos("testcode.jar"); | |||
JavaClass clazz = repos.loadClass("AttributeTestClassEM02$1"); | |||
ConstantPool pool = clazz.getConstantPool(); | |||
Attribute[] encMethodAttrs = findAttribute("EnclosingMethod",clazz); | |||
assertTrue("Expected 1 EnclosingMethod attribute but found "+encMethodAttrs.length, | |||
encMethodAttrs.length==1); | |||
Attribute[] encMethodAttrs = findAttribute("EnclosingMethod", clazz); | |||
assertTrue("Expected 1 EnclosingMethod attribute but found " + encMethodAttrs.length, encMethodAttrs.length == 1); | |||
// Write it out | |||
File tfile = createTestdataFile("AttributeTestClassEM02$1.class"); | |||
clazz.dump(tfile); | |||
// Read in the new version and check it is OK | |||
SyntheticRepository repos2 = createRepos("."); | |||
JavaClass clazz2 = repos2.loadClass("AttributeTestClassEM02$1"); | |||
EnclosingMethod em = (EnclosingMethod)encMethodAttrs[0]; | |||
String enclosingClassName = em.getEnclosingClass().getBytes(pool); | |||
assertTrue("The class is not within a method, so method_index should be null, but it is "+ | |||
em.getEnclosingMethodIndex(),em.getEnclosingMethodIndex() == 0); | |||
assertTrue("Expected class name to be 'AttributeTestClassEM02' but was "+enclosingClassName, | |||
enclosingClassName.equals("AttributeTestClassEM02")); | |||
EnclosingMethod em = (EnclosingMethod) encMethodAttrs[0]; | |||
String enclosingClassName = em.getEnclosingClass().getConstantValue(pool); | |||
assertTrue("The class is not within a method, so method_index should be null, but it is " + em.getEnclosingMethodIndex(), | |||
em.getEnclosingMethodIndex() == 0); | |||
assertTrue("Expected class name to be 'AttributeTestClassEM02' but was " + enclosingClassName, enclosingClassName | |||
.equals("AttributeTestClassEM02")); | |||
assertTrue(tfile.delete()); | |||
} | |||
@Override | |||
protected void tearDown() throws Exception { | |||
super.tearDown(); | |||
} |
@@ -40,7 +40,7 @@ public class UtilTests extends TestCase { | |||
} | |||
public void testTypeUtilMethods1() { | |||
String s = Type.getMethodSignature(Type.DOUBLE,new Type[]{Type.INT,Type.STRING,Type.SHORT}); | |||
String s = Utility.toMethodSignature(Type.DOUBLE,new Type[]{Type.INT,Type.STRING,Type.SHORT}); | |||
System.err.println(s); | |||
} | |||