diff options
author | aclement <aclement> | 2004-11-19 16:35:15 +0000 |
---|---|---|
committer | aclement <aclement> | 2004-11-19 16:35:15 +0000 |
commit | 8644e07c0dcee8a4e24b0bcdb320c9bfa47d9612 (patch) | |
tree | 73e8702570983a46ba4129d57fa16d6df9950327 /bcel-builder | |
parent | bfd1d4d0b5a553afdbbf93eb1972ff9d802906b3 (diff) | |
download | aspectj-8644e07c0dcee8a4e24b0bcdb320c9bfa47d9612.tar.gz aspectj-8644e07c0dcee8a4e24b0bcdb320c9bfa47d9612.zip |
BCEL Java5 Support
Diffstat (limited to 'bcel-builder')
42 files changed, 4863 insertions, 8 deletions
diff --git a/bcel-builder/.classpath b/bcel-builder/.classpath index 7c0df08e1..955afd2c0 100644 --- a/bcel-builder/.classpath +++ b/bcel-builder/.classpath @@ -1,7 +1,9 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> - <classpathentry kind="src" path="src"/> - <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> - <classpathentry kind="lib" path="/lib/regexp/jakarta-regexp-1.2.jar"/> - <classpathentry kind="output" path="bin"/> + <classpathentry kind="src" path="src"/> + <classpathentry kind="src" path="testsrc"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry kind="lib" path="/lib/regexp/jakarta-regexp-1.2.jar"/> + <classpathentry sourcepath="/lib/junit/junit-src.jar" kind="lib" path="/lib/junit/junit.jar"/> + <classpathentry kind="output" path="bin"/> </classpath> diff --git a/bcel-builder/build.xml b/bcel-builder/build.xml index 296c8713e..1d7809267 100644 --- a/bcel-builder/build.xml +++ b/bcel-builder/build.xml @@ -1,10 +1,12 @@ -<project default="extractAndPatchAndJar" basedir="."> +<project default="packageAndPush" basedir="."> <!-- top-level --> <target name="extractAndPatchAndJar" depends="extractAndPatch,jar,srcjar" /> <target name="extractAndPatch" depends="unzipSource,createPatchedSource" /> - + + <target name="packageAndPush" depends="buildTheJars,push"/> + <target name="jar" depends="pack"> <copy file="../lib/regexp/jakarta-regexp-1.2.jar" tofile="bcel/lib/Regex.jar" /> @@ -20,6 +22,11 @@ <copy file="bcel.jar" todir="../lib/bcel" /> <copy file="bcel-src.zip" todir="../lib/bcel" /> </target> + + <target name="buildTheJars"> + <zip file="bcel.jar" basedir="bin" includes="**/*" excludes="**/tests/*.class"/> + <zip file="bcel-src.zip" basedir="src" includes="**/*"/> + </target> <target name="diff" depends="transformFromAJ,pack"> diff --git a/bcel-builder/notamodule b/bcel-builder/notamodule deleted file mode 100644 index e69de29bb..000000000 --- a/bcel-builder/notamodule +++ /dev/null diff --git a/bcel-builder/readme.html b/bcel-builder/readme.html index 734be723e..9a17e14bc 100644 --- a/bcel-builder/readme.html +++ b/bcel-builder/readme.html @@ -6,15 +6,73 @@ <body> <h1>The BCEL-builder module</h1> +This module includes a modified form of BCEL - with some fixes in *and* support for Java5. + +<hr> + +<h3>Java 5 support</h3> +<p>The best way to see how it works is look in the testcases. The only feature that + is definetly not implemented yet is package level annotations. What is working is:</p> + +<ul> + <li>You can ask a type: are you an annotation type? are you an enum type?</li> + <li>You can ask a method: were you defined with varargs? Are you a bridge method?</li> + <li>All annotation values types are supported (primitive, string, array, enum, annotation, class).</li> + <li>Runtime visible and invisible annotations are supported.</li> + <li>Annotations are accessible on types, methods, fields.</li> + <li>Parameter annotations are accessible on methods.</li> + <li>You can programmatically construct annotations and attach them to types, methods, fields.</li> + <li>You can construct parameter annotations and add them to methods.</li> + <li>The EnclosingMethod attribute is supported (it is used to let you know the containing method for local/anonymous types)</li> + <li>The LocalVariableTypeTable attribute is supported (used for generics to tell you the original variable signature)</li> +</ul> +<p>All this is implemented without using any Java 5 APIs.</p> +<p>There are a number of new TODO type tags in the code that may prove useful:</p> +<ul> + <li>J5SUPPORT: Marks places where BCEL has been changed for 1.5 (might have missed a couple...)</li> + <li>BCELBUG: Marks things that might be BCEL problems that I came across</li> + <li>J5TODO: Marks either a missing bit of implementation (hopefully corner case) or an optimization we could make</li> +</ul> +<hr> <p> The contents of this directory are: </p> <ul> <li>This file</li> - <li>build.xml -- an ant script </li> - <li>patch.txt -- a diff patchfile</li> + <li>src -- contains the source for BCEL, a modified variant of BCEL 5.1 that includes bug fixes and Java 5 support</li> + <li>testsrc -- JUnit test cases for the Java 5 support</li> + <li>testdata -- Java5 testcode that can be built using the build.xml script in the testdata directory (see note on this below)</li> + <li>build.xml -- an ant script for manipulating the src folder, possibly useful if ever merging a base BCEL version</li> </ul> +<hr> +<h3>Development Process</h3> +<p> +We can now follow normal TDD for this. Add a JUnit testcase to the testsrc folder, plus any +associated test materials into the testdata directory. Then change BCEL to get your test passing, +when you are happy with the result (i.e. all the tests in the bcel-builder module are passing), you +should execute the build.xml script whose default target will package up bcel (and bcel src) and +deliver it into the lib module, the rest of AspectJ is driven off the version of bcel in the lib/bcel +folder - it is *not* driven off the bcel-builder code (we could choose to change that sometime later). +<p> +Once you have done this execute all the tests for AspectJ, if they all pass you can check in your +mods for bcel-builder and to the lib project. + +<hr> +<h3>testdata</h3> +The testdata folder includes a load of Java5 code, it needs to be built with a Java5 compiler. There +is an ant script in there (build.xml) that builds all the source code into a testcode.jar which is +then used by the testcases - so if you do change the testdata code then you should run build.xml +to rebuild testcode.jar. + +<hr> +<h3>The old stuff...</h3> +Before the Java 5 support was added we maintained this module as basically a patch to apply against +a particular download of BCEL. Changes to BCEL are occurring more frequently than we integrate +a new version of BCEL so it made sense to make the patching process easier, so we have checked in +the modified source for BCEL. +The original instructions for patching BCEL in the old way are below... + <p> And pretty much nothing else. Well, then, what do you do with this directory? Well, the whole point is to generate bcel/bcel.jar in the lib package. To do so, first stick diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/Annotation.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/Annotation.java new file mode 100644 index 000000000..f5c280018 --- /dev/null +++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/Annotation.java @@ -0,0 +1,125 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM Corporation + * + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement initial implementation + * ******************************************************************/ +package org.aspectj.apache.bcel.classfile.annotation; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.aspectj.apache.bcel.Constants; +import org.aspectj.apache.bcel.classfile.ConstantPool; +import org.aspectj.apache.bcel.classfile.ConstantUtf8; +import org.aspectj.apache.bcel.classfile.Utility; + +/** + * An annotation is an immutable object (AnnotationGen is the mutable variant) - it basically contains a list + * of name-value pairs. + */ +public class Annotation { + private int typeIndex; + private List /* ElementNameValuePair */ evs; + private ConstantPool cpool; + private boolean isRuntimeVisible; + + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append("ANNOTATION ["+getTypeSignature()+"] ["+ + (isRuntimeVisible?"runtimeVisible":"runtimeInvisible")+"] ["); + for (Iterator iter = evs.iterator(); iter.hasNext();) { + ElementNameValuePair element = (ElementNameValuePair) iter.next(); + sb.append(element.toString()); + if (iter.hasNext()) sb.append(","); + } + sb.append("]"); + return sb.toString(); + } + + private Annotation(ConstantPool cpool) { + this.cpool = cpool; + } + + protected static Annotation read(DataInputStream dis,ConstantPool cpool,boolean isRuntimeVisible) throws IOException { + Annotation a = new Annotation(cpool); + a.typeIndex = dis.readUnsignedShort(); + int elemValuePairCount = dis.readUnsignedShort(); + for (int i=0;i<elemValuePairCount;i++) { + int nidx = dis.readUnsignedShort(); + a.addElementNameValuePair( + new ElementNameValuePair(nidx,ElementValue.readElementValue(dis,cpool),cpool)); + } + a.isRuntimeVisible(isRuntimeVisible); + return a; + } + + protected 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++) { + ElementNameValuePair envp = (ElementNameValuePair) evs.get(i); + envp.dump(dos); + } + } + + public void addElementNameValuePair(ElementNameValuePair evp) { + if (evs == null) evs = new ArrayList(); + evs.add(evp); + } + + + public int getTypeIndex() { + return typeIndex; + } + + public final String getTypeSignature() { + ConstantUtf8 c = (ConstantUtf8)cpool.getConstant(typeIndex,Constants.CONSTANT_Utf8); + return c.getBytes(); + } + + public final String getTypeName() { + ConstantUtf8 c = (ConstantUtf8)cpool.getConstant(typeIndex,Constants.CONSTANT_Utf8); + return Utility.signatureToString(c.getBytes()); + } + + /** + * Returns list of ElementNameValuePair objects + */ + public List getValues() { + return evs; + } + + protected void isRuntimeVisible(boolean b) { + isRuntimeVisible = b; + } + + public boolean isRuntimeVisible() { + return isRuntimeVisible; + } + + public String toShortString() { + StringBuffer result = new StringBuffer(); + result.append("@"); + result.append(getTypeName()); + if (getValues().size()>0) { + result.append("("); + for (Iterator iter = getValues().iterator(); iter.hasNext();) { + ElementNameValuePair element = (ElementNameValuePair) iter.next(); + result.append(element.toShortString()); + } + result.append(")"); + } + return result.toString(); + } +} diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/AnnotationElementValue.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/AnnotationElementValue.java new file mode 100644 index 000000000..eba2cb1f3 --- /dev/null +++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/AnnotationElementValue.java @@ -0,0 +1,51 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation {date} + * ******************************************************************/ +package org.aspectj.apache.bcel.classfile.annotation; + +import java.io.DataOutputStream; +import java.io.IOException; + +import org.aspectj.apache.bcel.classfile.ConstantPool; + +/** + * An element value that is an annotation. + */ +public class AnnotationElementValue extends ElementValue { + + // For annotation element values, this is the annotation + private Annotation a; + + public AnnotationElementValue(int type, Annotation annotation, ConstantPool cpool) { + super(type,cpool); + if (type != ANNOTATION) + throw new RuntimeException("Only element values of type annotation can be built with this ctor"); + this.a = annotation; + } + + public void dump(DataOutputStream dos) throws IOException { + dos.writeByte(type); // u1 type of value (ANNOTATION == '@') + a.dump(dos); + } + + public String stringifyValue() { + StringBuffer sb = new StringBuffer(); + sb.append(a.toString()); + return sb.toString(); + } + + public String toString() { + return stringifyValue(); + } + + public Annotation getAnnotation() { return a;} + +} diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/ArrayElementValue.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/ArrayElementValue.java new file mode 100644 index 000000000..de1b0cc70 --- /dev/null +++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/ArrayElementValue.java @@ -0,0 +1,66 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation {date} + * ******************************************************************/ + +package org.aspectj.apache.bcel.classfile.annotation; + +import java.io.DataOutputStream; +import java.io.IOException; + +import org.aspectj.apache.bcel.classfile.ConstantPool; + + +public class ArrayElementValue extends ElementValue { + + // For array types, this is the array + private ElementValue[] evalues; + + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append("{"); + for (int i = 0; i < evalues.length; i++) { + sb.append(evalues[i].toString()); + if ((i+1)<evalues.length) sb.append(","); + } + sb.append("}"); + return sb.toString(); + } + + public ArrayElementValue(int type, ElementValue[] datums, ConstantPool cpool) { + super(type,cpool); + if (type != ARRAY) + throw new RuntimeException("Only element values of type array can be built with this ctor"); + this.evalues = datums; + } + + public void dump(DataOutputStream dos) throws IOException { + dos.writeByte(type); // u1 type of value (ARRAY == '[') + dos.writeShort(evalues.length); + for (int i=0; i<evalues.length; i++) { + evalues[i].dump(dos); + } + } + + public String stringifyValue() { + StringBuffer sb = new StringBuffer(); + sb.append("["); + for(int i=0; i<evalues.length; i++) { + sb.append(evalues[i].stringifyValue()); + if ((i+1)<evalues.length) sb.append(","); + } + sb.append("]"); + return sb.toString(); + } + + public ElementValue[] getElementValuesArray() { return evalues;} + public int getElementValuesArraySize() { return evalues.length;} + +} diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/ClassElementValue.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/ClassElementValue.java new file mode 100644 index 000000000..9143b1bbb --- /dev/null +++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/ClassElementValue.java @@ -0,0 +1,53 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation {date} + * ******************************************************************/ + +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.ConstantPool; +import org.aspectj.apache.bcel.classfile.ConstantUtf8; + + +public class ClassElementValue extends ElementValue { + + // For primitive types and string type, this points to the value entry in the cpool + // For 'class' this points to the class entry in the cpool + private int idx; + + protected ClassElementValue(int type,int idx,ConstantPool cpool) { + super(type,cpool); + this.idx = idx; + } + + public int getIndex() { + return idx; + } + + public String getClassString() { + ConstantUtf8 c = (ConstantUtf8)cpool.getConstant(idx,Constants.CONSTANT_Utf8); + return c.getBytes(); + } + + public String stringifyValue() { + ConstantUtf8 cu8 = (ConstantUtf8)cpool.getConstant(idx,Constants.CONSTANT_Utf8); + return cu8.getBytes(); + } + + public void dump(DataOutputStream dos) throws IOException { + dos.writeByte(type); // u1 kind of value + dos.writeShort(idx); + } + +} diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/ElementNameValuePair.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/ElementNameValuePair.java new file mode 100644 index 000000000..50ac79f38 --- /dev/null +++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/ElementNameValuePair.java @@ -0,0 +1,62 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation {date} + * ******************************************************************/ + +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.ConstantPool; +import org.aspectj.apache.bcel.classfile.ConstantUtf8; + + +public class ElementNameValuePair { + private int nameIdx; + private ElementValue value; + private ConstantPool cpool; + + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append(getNameString()+"="+value.toString()); + return sb.toString(); + } + public ElementNameValuePair(int idx,ElementValue value,ConstantPool cpool) { + this.nameIdx = idx; + 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() { + ConstantUtf8 c = (ConstantUtf8)cpool.getConstant(nameIdx,Constants.CONSTANT_Utf8); + return c.getBytes(); + } + + public final ElementValue getValue() { + return value; + } + + public String toShortString() { + StringBuffer result = new StringBuffer(); + result.append(getNameString()).append("=").append(getValue().toShortString()); + return result.toString(); + } +} diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/ElementValue.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/ElementValue.java new file mode 100644 index 000000000..c40494975 --- /dev/null +++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/ElementValue.java @@ -0,0 +1,112 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation {date} + * ******************************************************************/ + +package org.aspectj.apache.bcel.classfile.annotation; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.aspectj.apache.bcel.classfile.ConstantPool; + +public abstract class ElementValue { + + protected int type; + protected ConstantPool cpool; + + public String toString() { + return stringifyValue(); + } + + protected ElementValue(int type,ConstantPool cpool) { + this.type = type; + this.cpool = cpool; + } + + public int getElementValueType() { + return type; + } + + public abstract String stringifyValue(); + public abstract void dump(DataOutputStream dos) throws IOException; + + public static final int STRING = 's'; + public static final int ENUM_CONSTANT = 'e'; + public static final int CLASS = 'c'; + public static final int ANNOTATION = '@'; + public static final int ARRAY = '['; + + public static final int PRIMITIVE_INT = 'I'; + public static final int PRIMITIVE_BYTE = 'B'; + public static final int PRIMITIVE_CHAR = 'C'; + public static final int PRIMITIVE_DOUBLE = 'D'; + public static final int PRIMITIVE_FLOAT = 'F'; + public static final int PRIMITIVE_LONG = 'J'; + public static final int PRIMITIVE_SHORT = 'S'; + public static final int PRIMITIVE_BOOLEAN= 'Z'; + + public static ElementValue readElementValue(DataInputStream dis,ConstantPool cpool) throws IOException { + int type= dis.readUnsignedByte(); + switch (type) { + case 'B': // byte + return new SimpleElementValue(PRIMITIVE_BYTE,dis.readUnsignedShort(),cpool); + case 'C': // char + return new SimpleElementValue(PRIMITIVE_CHAR,dis.readUnsignedShort(),cpool); + case 'D': // double + return new SimpleElementValue(PRIMITIVE_DOUBLE,dis.readUnsignedShort(),cpool); + case 'F': // float + return new SimpleElementValue(PRIMITIVE_FLOAT,dis.readUnsignedShort(),cpool); + case 'I': // int + return new SimpleElementValue(PRIMITIVE_INT,dis.readUnsignedShort(),cpool); + case 'J': // long + return new SimpleElementValue(PRIMITIVE_LONG,dis.readUnsignedShort(),cpool); + case 'S': // short + return new SimpleElementValue(PRIMITIVE_SHORT,dis.readUnsignedShort(),cpool); + case 'Z': // boolean + return new SimpleElementValue(PRIMITIVE_BOOLEAN,dis.readUnsignedShort(),cpool); + case 's': // String + return new SimpleElementValue(STRING,dis.readUnsignedShort(),cpool); + + case 'e': // Enum constant + return new EnumElementValue(ENUM_CONSTANT,dis.readUnsignedShort(),dis.readUnsignedShort(),cpool); + + case 'c': // Class + return new ClassElementValue(CLASS,dis.readUnsignedShort(),cpool); + + //J5TODO: Should it be 'true' in the next statement? What difference does it make? Should it be + // the same as the 'super annotation' in which we are contained? + case '@': // Annotation + return new AnnotationElementValue(ANNOTATION,Annotation.read(dis,cpool,true),cpool); + + case '[': // Array + int numArrayVals = dis.readUnsignedShort(); + List arrayVals = new ArrayList(); + ElementValue[] evalues = new ElementValue[numArrayVals]; + for (int j=0;j<numArrayVals;j++) { + evalues[j] = ElementValue.readElementValue(dis,cpool); + } + return new ArrayElementValue(ARRAY,evalues,cpool); + + default: + throw new RuntimeException("Unexpected element value kind in annotation: "+type); + } + } + + + public String toShortString() { + StringBuffer result = new StringBuffer(); + result.append(stringifyValue()); + return result.toString(); + } +} diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/EnumElementValue.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/EnumElementValue.java new file mode 100644 index 000000000..c7fabd866 --- /dev/null +++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/EnumElementValue.java @@ -0,0 +1,63 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation {date} + * ******************************************************************/ + +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.ConstantPool; +import org.aspectj.apache.bcel.classfile.ConstantUtf8; +import org.aspectj.apache.bcel.classfile.Utility; + + +public class EnumElementValue extends ElementValue { + + // For enum types, these two indices point to the type and value + private int typeIdx; + private int valueIdx; + + public EnumElementValue(int type,int typeIdx,int valueIdx,ConstantPool cpool) { + super(type,cpool); + if (type != ENUM_CONSTANT) + throw new RuntimeException("Only element values of type enum can be built with this ctor"); + this.typeIdx = typeIdx; + this.valueIdx= valueIdx; + } + + public void dump(DataOutputStream dos) throws IOException { + dos.writeByte(type); // u1 type of value (ENUM_CONSTANT == 'e') + dos.writeShort(typeIdx); // u2 + dos.writeShort(valueIdx); // u2 + } + + public String stringifyValue() { + ConstantUtf8 cu8 = (ConstantUtf8)cpool.getConstant(valueIdx,Constants.CONSTANT_Utf8); + return cu8.getBytes(); + } + + public String getEnumTypeString() { + ConstantUtf8 cu8 = (ConstantUtf8)cpool.getConstant(typeIdx,Constants.CONSTANT_Utf8); + return Utility.signatureToString(cu8.getBytes()); + } + + public String getEnumValueString() { + ConstantUtf8 cu8 = (ConstantUtf8)cpool.getConstant(valueIdx,Constants.CONSTANT_Utf8); + return cu8.getBytes(); + } + + public int getValueIndex() { return valueIdx;} + public int getTypeIndex() { return typeIdx; } + + +} diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeAnnotations.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeAnnotations.java new file mode 100644 index 000000000..c0d06aa82 --- /dev/null +++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeAnnotations.java @@ -0,0 +1,83 @@ +package org.aspectj.apache.bcel.classfile.annotation; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.aspectj.apache.bcel.classfile.Attribute; +import org.aspectj.apache.bcel.classfile.ConstantPool; + +public abstract class RuntimeAnnotations extends Attribute { + + private List /*Annotation*/ annotations; + private boolean visible; + + // Keep just a byte stream of the data until someone actually asks for it + private boolean inflated = false; + private byte[] annotation_data; + + public RuntimeAnnotations(byte attrid, boolean visible, + int nameIdx, int len, + ConstantPool cpool) { + super(attrid,nameIdx,len,cpool); + this.visible = visible; + annotations = new ArrayList(); + } + + public RuntimeAnnotations(byte attrid,boolean visible,int nameIdx,int len,byte[] data,ConstantPool cpool) { + super(attrid,nameIdx,len,cpool); + this.visible = visible; + annotations = new ArrayList(); + annotation_data = data; + } + + public List getAnnotations() { + if (!inflated) inflate(); + return annotations; + } + + public boolean areVisible() { + return visible; + } + + protected void readAnnotations(DataInputStream dis,ConstantPool cpool) throws IOException { + annotation_data = new byte[length]; + dis.read(annotation_data,0,length); + } + + private void inflate() { + try { + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(annotation_data)); + int numberOfAnnotations = dis.readUnsignedShort(); + for (int i = 0 ;i<numberOfAnnotations;i++) { + annotations.add(Annotation.read(dis,getConstantPool(),visible)); + } + dis.close(); + inflated = true; + } catch (IOException ioe) { + throw new RuntimeException("Unabled to inflate annotation data, badly formed? "); + } + } + + protected void writeAnnotations(DataOutputStream dos) throws IOException { + if (!inflated) { + dos.write(annotation_data,0,length); + } else { + dos.writeShort(annotations.size()); + for (Iterator i = annotations.iterator(); i.hasNext();) { + Annotation ann = (Annotation) i.next(); + ann.dump(dos); + } + } + } + + /** FOR TESTING ONLY: Tells you if the annotations have been inflated to an object graph */ + public boolean isInflated() { + return inflated; + } + +} diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeInvisibleAnnotations.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeInvisibleAnnotations.java new file mode 100644 index 000000000..626b48c65 --- /dev/null +++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeInvisibleAnnotations.java @@ -0,0 +1,40 @@ +package org.aspectj.apache.bcel.classfile.annotation; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +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.Visitor; + +public class RuntimeInvisibleAnnotations extends RuntimeAnnotations { + + public RuntimeInvisibleAnnotations(int nameIdx, int len, ConstantPool cpool) { + super(Constants.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS, false, nameIdx, len, cpool); + } + + public RuntimeInvisibleAnnotations(int nameIdx, int len, + DataInputStream dis,ConstantPool cpool) throws IOException { + this(nameIdx, len, cpool); + readAnnotations(dis,cpool); + } + + public RuntimeInvisibleAnnotations(int nameIndex, int len, byte[] rvaData,ConstantPool cpool) { + super(Constants.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS,true,nameIndex,len,rvaData,cpool); + } + + public void accept(Visitor v) { + v.visitRuntimeInvisibleAnnotations(this); + } + + public final void dump(DataOutputStream dos) throws IOException { + super.dump(dos); + writeAnnotations(dos); + } + + public Attribute copy(ConstantPool constant_pool) { + throw new RuntimeException("Not implemented yet!"); + } +}
\ No newline at end of file diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeInvisibleParameterAnnotations.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeInvisibleParameterAnnotations.java new file mode 100644 index 000000000..9665dd6a2 --- /dev/null +++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeInvisibleParameterAnnotations.java @@ -0,0 +1,34 @@ +package org.aspectj.apache.bcel.classfile.annotation; + +import java.io.DataInputStream; +import java.io.IOException; + +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.Visitor; + +public class RuntimeInvisibleParameterAnnotations extends RuntimeParameterAnnotations { + + public RuntimeInvisibleParameterAnnotations(int nameIdx, int len, ConstantPool cpool) { + super(Constants.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, false, nameIdx, len, cpool); + } + + public RuntimeInvisibleParameterAnnotations(int nameIdx, int len, + DataInputStream dis,ConstantPool cpool) throws IOException { + this(nameIdx, len, cpool); + readParameterAnnotations(dis,cpool); + } + + public RuntimeInvisibleParameterAnnotations(int nameIndex, int len, byte[] rvaData,ConstantPool cpool) { + super(Constants.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS,true,nameIndex,len,rvaData,cpool); + } + + public void accept(Visitor v) { + v.visitRuntimeInvisibleParameterAnnotations(this); + } + + public Attribute copy(ConstantPool constant_pool) { + throw new RuntimeException("Not implemented yet!"); + } +}
\ No newline at end of file diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeParameterAnnotations.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeParameterAnnotations.java new file mode 100644 index 000000000..5a90fe07c --- /dev/null +++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeParameterAnnotations.java @@ -0,0 +1,110 @@ +package org.aspectj.apache.bcel.classfile.annotation; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.aspectj.apache.bcel.classfile.Attribute; +import org.aspectj.apache.bcel.classfile.ConstantPool; + +public abstract class RuntimeParameterAnnotations extends Attribute { + + private List /*Annotation[]*/ parameterAnnotations; + private boolean visible; + + + // Keep just a byte stream of the data until someone actually asks for it + private boolean inflated = false; + private byte[] annotation_data; + + + public RuntimeParameterAnnotations(byte attrid, boolean visible, + int nameIdx, int len, ConstantPool cpool) { + super(attrid,nameIdx,len,cpool); + this.visible = visible; + parameterAnnotations = new ArrayList(); + } + + public RuntimeParameterAnnotations(byte attrid,boolean visible,int nameIdx,int len,byte[] data,ConstantPool cpool) { + super(attrid,nameIdx,len,cpool); + this.visible = visible; + parameterAnnotations = new ArrayList(); + annotation_data = data; + } + + public final void dump(DataOutputStream dos) throws IOException { + super.dump(dos); + writeAnnotations(dos); + } + + public Attribute copy(ConstantPool constant_pool) { + throw new RuntimeException("Not implemented yet!"); + } + + /** Return a list of Annotation[] - each list entry contains the annotations for one parameter */ + public List /*Annotation[]*/ getParameterAnnotations() { + if (!inflated) inflate(); + return parameterAnnotations; + } + + public Annotation[] getAnnotationsOnParameter(int parameterIndex) { + if (!inflated) inflate(); + return (Annotation[])parameterAnnotations.get(parameterIndex); + } + + public boolean areVisible() { + return visible; + } + + protected void readParameterAnnotations(DataInputStream dis,ConstantPool cpool) throws IOException { + annotation_data = new byte[length]; + dis.read(annotation_data,0,length); + } + + private void inflate() { + try { + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(annotation_data)); + int numParameters = dis.readUnsignedByte(); + for (int i=0; i<numParameters; i++) { + int numAnnotations = dis.readUnsignedShort(); + Annotation[] annotations = new Annotation[numAnnotations]; + for (int j=0; j<numAnnotations; j++) { + annotations[j] = Annotation.read(dis,getConstantPool(),visible); + } + parameterAnnotations.add(annotations); + } + inflated = true; + } catch (IOException ioe) { + throw new RuntimeException("Unabled to inflate annotation data, badly formed?"); + } + } + + + protected void writeAnnotations(DataOutputStream dos) throws IOException { + if (!inflated) { + dos.write(annotation_data,0,length); + } else { + dos.writeByte(parameterAnnotations.size()); + for (int i=0; i<parameterAnnotations.size(); i++) { + Annotation[] annotations = (Annotation[])parameterAnnotations.get(i); + dos.writeShort(annotations.length); + for (int j=0; j<annotations.length;j++) { + annotations[j].dump(dos); + } + } + } + } + + /** FOR TESTING ONLY: Tells you if the annotations have been inflated to an object graph */ + public boolean isInflated() { + return inflated; + } + + public String toString() { + return "Runtime"+(visible?"Visible":"Invisible")+"ParameterAnnotations ["+(inflated?"inflated":"not yet inflated")+"]"; + } + +} diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeVisibleAnnotations.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeVisibleAnnotations.java new file mode 100644 index 000000000..e43c55b92 --- /dev/null +++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeVisibleAnnotations.java @@ -0,0 +1,40 @@ +package org.aspectj.apache.bcel.classfile.annotation; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +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.Visitor; + +public class RuntimeVisibleAnnotations extends RuntimeAnnotations { + + public RuntimeVisibleAnnotations(int nameIdx, int len, ConstantPool cpool) { + super(Constants.ATTR_RUNTIME_VISIBLE_ANNOTATIONS, true, nameIdx, len, cpool); + } + + public RuntimeVisibleAnnotations(int nameIdx, int len, + DataInputStream dis,ConstantPool cpool) throws IOException { + this(nameIdx, len, cpool); + readAnnotations(dis,cpool); + } + + public RuntimeVisibleAnnotations(int nameIndex, int len, byte[] rvaData,ConstantPool cpool) { + super(Constants.ATTR_RUNTIME_VISIBLE_ANNOTATIONS,true,nameIndex,len,rvaData,cpool); + } + + public void accept(Visitor v) { + v.visitRuntimeVisibleAnnotations(this); + } + + public final void dump(DataOutputStream dos) throws IOException { + super.dump(dos); + writeAnnotations(dos); + } + + public Attribute copy(ConstantPool constant_pool) { + throw new RuntimeException("Not implemented yet!"); + } +}
\ No newline at end of file diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeVisibleParameterAnnotations.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeVisibleParameterAnnotations.java new file mode 100644 index 000000000..b57068bc1 --- /dev/null +++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeVisibleParameterAnnotations.java @@ -0,0 +1,34 @@ +package org.aspectj.apache.bcel.classfile.annotation; + +import java.io.DataInputStream; +import java.io.IOException; + +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.Visitor; + +public class RuntimeVisibleParameterAnnotations extends RuntimeParameterAnnotations { + + public RuntimeVisibleParameterAnnotations(int nameIdx, int len, ConstantPool cpool) { + super(Constants.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, true, nameIdx, len, cpool); + } + + public RuntimeVisibleParameterAnnotations(int nameIndex, int len, byte[] rvaData,ConstantPool cpool) { + super(Constants.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS,true,nameIndex,len,rvaData,cpool); + } + + public RuntimeVisibleParameterAnnotations(int nameIdx, int len, + DataInputStream dis,ConstantPool cpool) throws IOException { + this(nameIdx, len, cpool); + readParameterAnnotations(dis,cpool); + } + + public void accept(Visitor v) { + v.visitRuntimeVisibleParameterAnnotations(this); + } + + public Attribute copy(ConstantPool constant_pool) { + throw new RuntimeException("Not implemented yet!"); + } +}
\ No newline at end of file diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/SimpleElementValue.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/SimpleElementValue.java new file mode 100644 index 000000000..339365e54 --- /dev/null +++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/SimpleElementValue.java @@ -0,0 +1,119 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation {date} + * ******************************************************************/ + +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.ConstantPool; +import org.aspectj.apache.bcel.classfile.ConstantUtf8; + +/** + * An element value representing a primitive or string value. + */ +public class SimpleElementValue extends ElementValue { + + // For primitive types and string type, this points to the value entry in the cpool + // For 'class' this points to the class entry in the cpool + private int idx; + + protected SimpleElementValue(int type,int idx,ConstantPool cpool) { + super(type,cpool); + this.idx = idx; + } + + public int getIndex() { + return idx; + } + + + public String getValueString() { + if (type != STRING) + throw new RuntimeException("Dont call getValueString() on a non STRING ElementValue"); + ConstantUtf8 c = (ConstantUtf8)cpool.getConstant(idx,Constants.CONSTANT_Utf8); + return c.getBytes(); + } + + public int getValueInt() { + if (type != PRIMITIVE_INT) + throw new RuntimeException("Dont call getValueString() on a non STRING ElementValue"); + ConstantInteger c = (ConstantInteger)cpool.getConstant(idx,Constants.CONSTANT_Integer); + return c.getBytes(); + } + + public String toString() { + return stringifyValue(); + } + + // Whatever kind of value it is, return it as a string + public String stringifyValue() { + switch (type) { + case PRIMITIVE_INT: + ConstantInteger c = (ConstantInteger)cpool.getConstant(idx,Constants.CONSTANT_Integer); + return Integer.toString(c.getBytes()); + case PRIMITIVE_LONG: + ConstantLong j = (ConstantLong)cpool.getConstant(idx,Constants.CONSTANT_Long); + return Long.toString(j.getBytes()); + case PRIMITIVE_DOUBLE: + ConstantDouble d = (ConstantDouble)cpool.getConstant(idx,Constants.CONSTANT_Double); + return Double.toString(d.getBytes()); + case PRIMITIVE_FLOAT: + ConstantFloat f = (ConstantFloat)cpool.getConstant(idx,Constants.CONSTANT_Float); + return Float.toString(f.getBytes()); + case PRIMITIVE_SHORT: + ConstantInteger s = (ConstantInteger)cpool.getConstant(idx,Constants.CONSTANT_Integer); + return Integer.toString(s.getBytes()); + case PRIMITIVE_BYTE: + ConstantInteger b = (ConstantInteger)cpool.getConstant(idx,Constants.CONSTANT_Integer); + return Integer.toString(b.getBytes()); + case PRIMITIVE_CHAR: + ConstantInteger ch = (ConstantInteger)cpool.getConstant(idx,Constants.CONSTANT_Integer); + return Integer.toString(ch.getBytes()); + case PRIMITIVE_BOOLEAN: + ConstantInteger bo = (ConstantInteger)cpool.getConstant(idx,Constants.CONSTANT_Integer); + if (bo.getBytes() == 0) return "false"; + if (bo.getBytes() != 0) return "true"; + case STRING: + ConstantUtf8 cu8 = (ConstantUtf8)cpool.getConstant(idx,Constants.CONSTANT_Utf8); + return cu8.getBytes(); + + default: + throw new RuntimeException("SimpleElementValue 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("SimpleElementValue doesnt know how to write out type "+type); + } + } + +} diff --git a/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/AnnotationElementValueGen.java b/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/AnnotationElementValueGen.java new file mode 100644 index 000000000..0ddee226f --- /dev/null +++ b/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/AnnotationElementValueGen.java @@ -0,0 +1,55 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation {date} + * ******************************************************************/ + +package org.aspectj.apache.bcel.generic.annotation; + +import java.io.DataOutputStream; +import java.io.IOException; + +import org.aspectj.apache.bcel.classfile.annotation.AnnotationElementValue; +import org.aspectj.apache.bcel.generic.ConstantPoolGen; + + +public class AnnotationElementValueGen extends ElementValueGen { + + // For annotation element values, this is the annotation + private AnnotationGen a; + + public AnnotationElementValueGen(AnnotationGen a,ConstantPoolGen cpool) { + super(ANNOTATION,cpool); + this.a = a; + } + + public AnnotationElementValueGen(int type, AnnotationGen annotation, ConstantPoolGen cpool) { + super(type,cpool); + if (type != ANNOTATION) + throw new RuntimeException("Only element values of type annotation can be built with this ctor"); + this.a = annotation; + } + + public AnnotationElementValueGen(AnnotationElementValue value, ConstantPoolGen cpool) { + super(ANNOTATION,cpool); + a = new AnnotationGen(value.getAnnotation(),cpool); + } + + public void dump(DataOutputStream dos) throws IOException { + dos.writeByte(type); // u1 type of value (ANNOTATION == '@') + a.dump(dos); + } + + public String stringifyValue() { + throw new RuntimeException("Not implemented yet"); + } + + public AnnotationGen getAnnotation() { return a;} + +} diff --git a/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/AnnotationGen.java b/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/AnnotationGen.java new file mode 100644 index 000000000..94236bc36 --- /dev/null +++ b/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/AnnotationGen.java @@ -0,0 +1,148 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM Corporation + * + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement initial implementation + * ******************************************************************/ +package org.aspectj.apache.bcel.generic.annotation; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.aspectj.apache.bcel.classfile.ConstantUtf8; +import org.aspectj.apache.bcel.classfile.annotation.Annotation; +import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePair; +import org.aspectj.apache.bcel.generic.ConstantPoolGen; +import org.aspectj.apache.bcel.generic.ObjectType; + +public class AnnotationGen { + private int typeIndex; + private List /* ElementNameValuePairGen */ evs; + private ConstantPoolGen cpool; + private boolean isRuntimeVisible = false; + + /** + * Here we are taking a fixed annotation of type Annotation and building a + * modifiable AnnotationGen object. The ConstantPool entries should already + * be correct, we could assert that ... + * We need to copy the type and the element name value pairs and the visibility. + */ + public AnnotationGen(Annotation a,ConstantPoolGen cpool) { + this.cpool = cpool; + // Could assert a.getTypeSignature() == (ConstantUtf8)cpool.getConstant(a.getTypeIndex())).getBytes() + typeIndex = a.getTypeIndex(); + + isRuntimeVisible = a.isRuntimeVisible(); + + evs = copyValues(a.getValues(),cpool); + } + + private List copyValues(List in,ConstantPoolGen cpool) { + List out = new ArrayList(); + for (Iterator iter = in.iterator(); iter.hasNext();) { + ElementNameValuePair nvp = (ElementNameValuePair) iter.next(); + out.add(new ElementNameValuePairGen(nvp,cpool)); + } + return out; + } + + private AnnotationGen(ConstantPoolGen cpool) { + this.cpool = cpool; + } + + public AnnotationGen(ObjectType type,List /*ElementNameValuePairGen*/ elements,boolean vis,ConstantPoolGen cpool) { + this.cpool = cpool; + this.typeIndex = cpool.addUtf8(type.getSignature()); + evs = elements; + isRuntimeVisible = vis; + } + + public static AnnotationGen read(DataInputStream dis,ConstantPoolGen 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)); + } + 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 = (ElementNameValuePairGen) evs.get(i); + envp.dump(dos); + } + } + + public void addElementNameValuePair(ElementNameValuePairGen evp) { + if (evs == null) evs = new ArrayList(); + evs.add(evp); + } + + + public int getTypeIndex() { + return typeIndex; + } + + public final String getTypeSignature() { +// ConstantClass c = (ConstantClass)cpool.getConstant(typeIndex); + ConstantUtf8 utf8 = (ConstantUtf8)cpool.getConstant(typeIndex/*c.getNameIndex()*/); + return utf8.getBytes(); + } + + public final String getTypeName() { + return getTypeSignature();// BCELBUG: Should I use this instead? Utility.signatureToString(getTypeSignature()); + } + + /** + * Returns list of ElementNameValuePair objects + */ + public List getValues() { + return evs; + } + + 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("}]"); + 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(")"); + return s.toString(); + } + + private void isRuntimeVisible(boolean b) { + isRuntimeVisible = b; + } + + public boolean isRuntimeVisible() { + return isRuntimeVisible; + } +} diff --git a/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/ArrayElementValueGen.java b/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/ArrayElementValueGen.java new file mode 100644 index 000000000..f5b176437 --- /dev/null +++ b/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/ArrayElementValueGen.java @@ -0,0 +1,87 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation {date} + * ******************************************************************/ + +package org.aspectj.apache.bcel.generic.annotation; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.aspectj.apache.bcel.classfile.annotation.ArrayElementValue; +import org.aspectj.apache.bcel.classfile.annotation.ElementValue; +import org.aspectj.apache.bcel.generic.ConstantPoolGen; + + +public class ArrayElementValueGen extends ElementValueGen { + + // J5TODO: Should we make this an array or a list? A list would be easier to modify ... + private List /*ElementValueGen*/ evalues; + + public ArrayElementValueGen(ConstantPoolGen cp) { + super(ARRAY,cp); + evalues = new ArrayList(); + } + + public ArrayElementValueGen(int type, ElementValueGen[] datums, ConstantPoolGen cpool) { + super(type,cpool); + if (type != ARRAY) + throw new RuntimeException("Only element values of type array can be built with this ctor"); + this.evalues = new ArrayList(); + for (int i = 0; i < datums.length; i++) { + evalues.add(datums[i]); + } + } + + /** + * @param value + * @param cpool + */ + public ArrayElementValueGen(ArrayElementValue value, ConstantPoolGen cpool) { + super(ARRAY,cpool); + evalues = new ArrayList(); + ElementValue[] in = value.getElementValuesArray(); + for (int i = 0; i < in.length; i++) { + evalues.add(ElementValueGen.copy(in[i],cpool)); + } + } + + public void dump(DataOutputStream dos) throws IOException { + dos.writeByte(type); // u1 type of value (ARRAY == '[') + dos.writeShort(evalues.size()); + for (Iterator iter = evalues.iterator(); iter.hasNext();) { + ElementValueGen element = (ElementValueGen) iter.next(); + element.dump(dos); + } + } + + public String stringifyValue() { + StringBuffer sb = new StringBuffer(); + sb.append("["); + for (Iterator iter = evalues.iterator(); iter.hasNext();) { + ElementValueGen element = (ElementValueGen) iter.next(); + sb.append(element.stringifyValue()); + if (iter.hasNext()) sb.append(","); + } + sb.append("]"); + return sb.toString(); + } + + public List getElementValues() { return evalues;} + public int getElementValuesSize() { return evalues.size();} + + public void addElement(ElementValueGen gen) { + evalues.add(gen); + } + +} diff --git a/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/ClassElementValueGen.java b/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/ClassElementValueGen.java new file mode 100644 index 000000000..4639e6b8b --- /dev/null +++ b/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/ClassElementValueGen.java @@ -0,0 +1,59 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation {date} + * ******************************************************************/ + +package org.aspectj.apache.bcel.generic.annotation; + +import java.io.DataOutputStream; +import java.io.IOException; + +import org.aspectj.apache.bcel.classfile.ConstantClass; +import org.aspectj.apache.bcel.classfile.ConstantUtf8; +import org.aspectj.apache.bcel.generic.ConstantPoolGen; +import org.aspectj.apache.bcel.generic.ObjectType; + + +public class ClassElementValueGen extends ElementValueGen { + + // For primitive types and string type, this points to the value entry in the cpool + // For 'class' this points to the class entry in the cpool + private int idx; + + protected ClassElementValueGen(int typeIdx,ConstantPoolGen cpool) { + super(ElementValueGen.CLASS,cpool); + this.idx = typeIdx; + } + + public ClassElementValueGen(ObjectType t,ConstantPoolGen cpool) { + super(ElementValueGen.CLASS,cpool); + this.idx = cpool.addClass(t); + } + + public int getIndex() { + return idx; + } + + public String getClassString() { + ConstantClass c = (ConstantClass)getConstantPool().getConstant(idx); + ConstantUtf8 utf8 = (ConstantUtf8)getConstantPool().getConstant(c.getNameIndex()); + return utf8.getBytes(); + } + + public String stringifyValue() { + return getClassString(); + } + + public void dump(DataOutputStream dos) throws IOException { + dos.writeByte(type); // u1 kind of value + dos.writeShort(idx); + } + +} diff --git a/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/ElementNameValuePairGen.java b/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/ElementNameValuePairGen.java new file mode 100644 index 000000000..23b84e6b7 --- /dev/null +++ b/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/ElementNameValuePairGen.java @@ -0,0 +1,70 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation + * ******************************************************************/ + +package org.aspectj.apache.bcel.generic.annotation; + +import java.io.DataOutputStream; +import java.io.IOException; + +import org.aspectj.apache.bcel.classfile.ConstantUtf8; +import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePair; +import org.aspectj.apache.bcel.generic.ConstantPoolGen; + + +public class ElementNameValuePairGen { + private int nameIdx; + private ElementValueGen value; + private ConstantPoolGen cpool; + + public ElementNameValuePairGen(ElementNameValuePair nvp, ConstantPoolGen cpool) { + this.cpool = cpool; + // J5ASSERT: + // Could assert nvp.getNameString() points to the same thing as cpool.getConstant(nvp.getNameIndex()) + nameIdx = nvp.getNameIndex(); + value = ElementValueGen.copy(nvp.getValue(),cpool); + } + + + protected ElementNameValuePairGen(int idx,ElementValueGen value,ConstantPoolGen cpool) { + this.nameIdx = idx; + this.value = value; + this.cpool = cpool; + } + + public ElementNameValuePairGen(String name,ElementValueGen value,ConstantPoolGen cpool) { + this.nameIdx = cpool.addUtf8(name); + 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(); + } + + public final ElementValueGen getValue() { + return value; + } + + public String toString() { + return "ElementNameValuePair:["+getNameString()+"="+value.stringifyValue()+"]"; + } +} diff --git a/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/ElementValueGen.java b/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/ElementValueGen.java new file mode 100644 index 000000000..b97afc8e3 --- /dev/null +++ b/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/ElementValueGen.java @@ -0,0 +1,137 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation {date} + * ******************************************************************/ + +package org.aspectj.apache.bcel.generic.annotation; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.aspectj.apache.bcel.classfile.annotation.AnnotationElementValue; +import org.aspectj.apache.bcel.classfile.annotation.ArrayElementValue; +import org.aspectj.apache.bcel.classfile.annotation.ElementValue; +import org.aspectj.apache.bcel.classfile.annotation.EnumElementValue; +import org.aspectj.apache.bcel.classfile.annotation.SimpleElementValue; +import org.aspectj.apache.bcel.generic.ConstantPoolGen; + +public abstract class ElementValueGen { + + protected int type; + protected ConstantPoolGen cpGen; + + + protected ElementValueGen(int type,ConstantPoolGen cpGen) { + this.type = type; + this.cpGen = cpGen; + } + + public int getElementValueType() { + return type; + } + + public abstract String stringifyValue(); + public abstract void dump(DataOutputStream dos) throws IOException; + + public static final int STRING = 's'; + public static final int ENUM_CONSTANT = 'e'; + public static final int CLASS = 'c'; + public static final int ANNOTATION = '@'; + public static final int ARRAY = '['; + + public static final int PRIMITIVE_INT = 'I'; + public static final int PRIMITIVE_BYTE = 'B'; + public static final int PRIMITIVE_CHAR = 'C'; + public static final int PRIMITIVE_DOUBLE = 'D'; + public static final int PRIMITIVE_FLOAT = 'F'; + public static final int PRIMITIVE_LONG = 'J'; + public static final int PRIMITIVE_SHORT = 'S'; + public static final int PRIMITIVE_BOOLEAN= 'Z'; + + public static ElementValueGen readElementValue(DataInputStream dis,ConstantPoolGen cpGen) throws IOException { + int type= dis.readUnsignedByte(); + switch (type) { + case 'B': // byte + return new SimpleElementValueGen(PRIMITIVE_BYTE,dis.readUnsignedShort(),cpGen); + case 'C': // char + return new SimpleElementValueGen(PRIMITIVE_CHAR,dis.readUnsignedShort(),cpGen); + case 'D': // double + return new SimpleElementValueGen(PRIMITIVE_DOUBLE,dis.readUnsignedShort(),cpGen); + case 'F': // float + return new SimpleElementValueGen(PRIMITIVE_FLOAT,dis.readUnsignedShort(),cpGen); + case 'I': // int + return new SimpleElementValueGen(PRIMITIVE_INT,dis.readUnsignedShort(),cpGen); + case 'J': // long + return new SimpleElementValueGen(PRIMITIVE_LONG,dis.readUnsignedShort(),cpGen); + case 'S': // short + return new SimpleElementValueGen(PRIMITIVE_SHORT,dis.readUnsignedShort(),cpGen); + case 'Z': // boolean + return new SimpleElementValueGen(PRIMITIVE_BOOLEAN,dis.readUnsignedShort(),cpGen); + case 's': // String + return new SimpleElementValueGen(STRING,dis.readUnsignedShort(),cpGen); + + case 'e': // Enum constant + return new EnumElementValueGen(dis.readUnsignedShort(),dis.readUnsignedShort(),cpGen); + + case 'c': // Class + return new ClassElementValueGen(dis.readUnsignedShort(),cpGen); +// +// case '@': // Annotation +// return new AnnotationElementValueGen(ANNOTATION,Annotation.read(dis,cpGen),cpGen); +// +// case '[': // Array +// int numArrayVals = dis.readUnsignedShort(); +// List arrayVals = new ArrayList(); +// ElementValue[] evalues = new ElementValue[numArrayVals]; +// for (int j=0;j<numArrayVals;j++) { +// evalues[j] = ElementValue.readElementValue(dis,cpGen); +// } +// return new ArrayElementValue(ARRAY,evalues,cpGen); + + default: + throw new RuntimeException("Unexpected element value kind in annotation: "+type); + } + } + + protected ConstantPoolGen getConstantPool() { + return cpGen; + } + + /** + * Creates an (modifiable) ElementValueGen copy of an (immutable) ElementValue - constant pool is assumed correct. + */ + public static ElementValueGen copy(ElementValue value,ConstantPoolGen cpool) { + switch (value.getElementValueType()) { + case 'B': // byte + case 'C': // char + case 'D': // double + case 'F': // float + case 'I': // int + case 'J': // long + case 'S': // short + case 'Z': // boolean + case 's': // String + return new SimpleElementValueGen((SimpleElementValue)value,cpool); + + case 'e': // Enum constant + return new EnumElementValueGen((EnumElementValue)value,cpool); + + case '@': // Annotation + return new AnnotationElementValueGen((AnnotationElementValue)value,cpool); + + case '[': // Array + return new ArrayElementValueGen((ArrayElementValue)value,cpool); + + default: + throw new RuntimeException("Not implemented yet! ("+value.getElementValueType()+")"); + } + } +} diff --git a/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/EnumElementValueGen.java b/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/EnumElementValueGen.java new file mode 100644 index 000000000..f30283601 --- /dev/null +++ b/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/EnumElementValueGen.java @@ -0,0 +1,84 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation {date} + * ******************************************************************/ + +package org.aspectj.apache.bcel.generic.annotation; + +import java.io.DataOutputStream; +import java.io.IOException; + +import org.aspectj.apache.bcel.classfile.ConstantClass; +import org.aspectj.apache.bcel.classfile.ConstantString; +import org.aspectj.apache.bcel.classfile.ConstantUtf8; +import org.aspectj.apache.bcel.classfile.annotation.EnumElementValue; +import org.aspectj.apache.bcel.generic.ConstantPoolGen; +import org.aspectj.apache.bcel.generic.ObjectType; + + +public class EnumElementValueGen extends ElementValueGen { + + // For enum types, these two indices point to the type and value + private int typeIdx; + private int valueIdx; + + /** + * This ctor assumes the constant pool already contains the right type and value - + * as indicated by typeIdx and valueIdx. This ctor is used for deserialization + */ + protected EnumElementValueGen(int typeIdx,int valueIdx,ConstantPoolGen cpool) { + super(ElementValueGen.ENUM_CONSTANT,cpool); + if (type != ENUM_CONSTANT) + throw new RuntimeException("Only element values of type enum can be built with this ctor"); + this.typeIdx = typeIdx; + this.valueIdx= valueIdx; + } + + public EnumElementValueGen(ObjectType t,String value,ConstantPoolGen cpool) { + super(ElementValueGen.ENUM_CONSTANT,cpool); + typeIdx = cpool.addClass(t); + valueIdx= cpool.addString(value); + } + + public EnumElementValueGen(EnumElementValue value, ConstantPoolGen cpool) { + super(ENUM_CONSTANT,cpool); + typeIdx = value.getTypeIndex(); + valueIdx = value.getValueIndex(); + } + + public void dump(DataOutputStream dos) throws IOException { + dos.writeByte(type); // u1 type of value (ENUM_CONSTANT == 'e') + dos.writeShort(typeIdx); // u2 + dos.writeShort(valueIdx); // u2 + } + + public String stringifyValue() { + ConstantString cu8 = (ConstantString)getConstantPool().getConstant(valueIdx); + return ((ConstantUtf8)getConstantPool().getConstant(cu8.getStringIndex())).getBytes(); + } + + + // BCELBUG: Should we need to call utility.signatureToString() on the output here? + public String getEnumTypeString() { + ConstantClass cu8 = (ConstantClass)getConstantPool().getConstant(typeIdx); + return ((ConstantUtf8)getConstantPool().getConstant(cu8.getNameIndex())).getBytes(); + // return Utility.signatureToString(cu8.getBytes()); + } + + public String getEnumValueString() { + ConstantString cu8 = (ConstantString)getConstantPool().getConstant(valueIdx); + return ((ConstantUtf8)getConstantPool().getConstant(cu8.getStringIndex())).getBytes(); + } + + public int getValueIndex() { return valueIdx;} + public int getTypeIndex() { return typeIdx; } + + +} diff --git a/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/SimpleElementValueGen.java b/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/SimpleElementValueGen.java new file mode 100644 index 000000000..49e5c57d2 --- /dev/null +++ b/bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/SimpleElementValueGen.java @@ -0,0 +1,173 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation {date} + * ******************************************************************/ + +package org.aspectj.apache.bcel.generic.annotation; + +import java.io.DataOutputStream; +import java.io.IOException; + +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.annotation.SimpleElementValue; +import org.aspectj.apache.bcel.generic.ConstantPoolGen; + + +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 + // 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 SimpleElementValueGen(int type,int idx,ConstantPoolGen cpGen) { + super(type,cpGen); + this.idx = idx; + } + + public SimpleElementValueGen(int type,ConstantPoolGen cpGen,int value) { + super(type,cpGen); + idx = cpGen.addInteger(value); + } + + public SimpleElementValueGen(int type,ConstantPoolGen cpGen,long value) { + super(type,cpGen); + idx = cpGen.addLong(value); + } + + public SimpleElementValueGen(int type,ConstantPoolGen cpGen,double value) { + super(type,cpGen); + idx = cpGen.addDouble(value); + } + + public SimpleElementValueGen(int type,ConstantPoolGen cpGen,float value) { + super(type,cpGen); + idx = cpGen.addFloat(value); + } + + public SimpleElementValueGen(int type,ConstantPoolGen cpGen,short value) { + super(type,cpGen); + idx = cpGen.addInteger(value); + } + + public SimpleElementValueGen(int type,ConstantPoolGen cpGen,byte value) { + super(type,cpGen); + idx = cpGen.addInteger(value); + } + + public SimpleElementValueGen(int type,ConstantPoolGen cpGen,char value) { + super(type,cpGen); + idx = cpGen.addInteger(value); + } + + public SimpleElementValueGen(int type,ConstantPoolGen cpGen,boolean value) { + super(type,cpGen); + if (value) idx = cpGen.addInteger(1); + else idx = cpGen.addInteger(0); + } + + public SimpleElementValueGen(int type,ConstantPoolGen cpGen,String value) { + super(type,cpGen); + idx = cpGen.addUtf8(value); + } + + public SimpleElementValueGen(SimpleElementValue value,ConstantPoolGen cpool) { + super(value.getElementValueType(),cpool); + // J5ASSERT: Could assert value.stringifyValue() is the same as + // cpool.getConstant(SimpleElementValuevalue.getIndex()) + idx = value.getIndex(); + } + + public int getIndex() { + 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); + 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); + 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 Integer.toString(ch.getBytes()); + case PRIMITIVE_BOOLEAN: + ConstantInteger bo = (ConstantInteger)cpGen.getConstant(idx); + if (bo.getBytes() == 0) return "false"; + if (bo.getBytes() != 0) 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); + } + } + +} diff --git a/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/AllTests.java b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/AllTests.java new file mode 100644 index 000000000..69d41d6b8 --- /dev/null +++ b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/AllTests.java @@ -0,0 +1,54 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation {date} + * ******************************************************************/ + +package org.aspectj.apache.bcel.classfile.tests; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.aspectj.apache.bcel.classfile.tests.AnnotationAccessFlagTest; +import org.aspectj.apache.bcel.classfile.tests.AnnotationDefaultAttributeTest; +import org.aspectj.apache.bcel.classfile.tests.ElementValueGenTest; +import org.aspectj.apache.bcel.classfile.tests.EnclosingMethodAttributeTest; +import org.aspectj.apache.bcel.classfile.tests.EnumAccessFlagTest; +import org.aspectj.apache.bcel.classfile.tests.FieldAnnotationsTest; +import org.aspectj.apache.bcel.classfile.tests.GeneratingAnnotatedClassesTest; +import org.aspectj.apache.bcel.classfile.tests.LocalVariableTypeTableTest; +import org.aspectj.apache.bcel.classfile.tests.MethodAnnotationsTest; +import org.aspectj.apache.bcel.classfile.tests.RuntimeVisibleAnnotationAttributeTest; +import org.aspectj.apache.bcel.classfile.tests.RuntimeVisibleParameterAnnotationAttributeTest; +import org.aspectj.apache.bcel.classfile.tests.VarargsTest; + +public class AllTests { + + public static Test suite() { + TestSuite suite = new TestSuite("Tests for BCEL Java5 support"); + //$JUnit-BEGIN$ + suite + .addTestSuite(RuntimeVisibleParameterAnnotationAttributeTest.class); + suite.addTestSuite(AnnotationDefaultAttributeTest.class); + suite.addTestSuite(EnclosingMethodAttributeTest.class); + suite.addTestSuite(MethodAnnotationsTest.class); + suite.addTestSuite(RuntimeVisibleAnnotationAttributeTest.class); + suite.addTestSuite(EnumAccessFlagTest.class); + suite.addTestSuite(LocalVariableTypeTableTest.class); + suite.addTestSuite(VarargsTest.class); + suite.addTestSuite(AnnotationAccessFlagTest.class); + suite.addTestSuite(ElementValueGenTest.class); + suite.addTestSuite(FieldAnnotationsTest.class); + suite.addTestSuite(AnnotationGenTest.class); + suite.addTestSuite(ParameterAnnotationsTest.class); + suite.addTestSuite(GeneratingAnnotatedClassesTest.class); + //$JUnit-END$ + return suite; + } +}
\ No newline at end of file diff --git a/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/AnnotationAccessFlagTest.java b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/AnnotationAccessFlagTest.java new file mode 100644 index 000000000..5b661e771 --- /dev/null +++ b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/AnnotationAccessFlagTest.java @@ -0,0 +1,55 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation + * ******************************************************************/ + +package org.aspectj.apache.bcel.classfile.tests; + +import java.io.File; + +import junit.framework.TestCase; + +import org.aspectj.apache.bcel.classfile.ConstantPool; +import org.aspectj.apache.bcel.classfile.JavaClass; +import org.aspectj.apache.bcel.util.ClassPath; +import org.aspectj.apache.bcel.util.SyntheticRepository; + +public class AnnotationAccessFlagTest extends TestCase { + + private boolean verbose = false; + + protected void setUp() throws Exception { + super.setUp(); + } + + /** + * If you write an annotation and compile it, the class file generated should be + * marked as an annotation type - which is detectable through BCEL. + */ + public void testAnnotationClassSaysItIs() throws ClassNotFoundException { + ClassPath cp = + new ClassPath("testdata"+File.separator+"testcode.jar"+File.pathSeparator+System.getProperty("java.class.path")); + SyntheticRepository repos = SyntheticRepository.getInstance(cp); + JavaClass clazz = repos.loadClass("SimpleAnnotation"); + ConstantPool pool = clazz.getConstantPool(); + assertTrue("Expected SimpleAnnotation class to say it was an annotation - but it didn't !", + clazz.isAnnotation()); + clazz = repos.loadClass("SimpleClass"); + assertTrue("Expected SimpleClass class to say it was not an annotation - but it didn't !", + !clazz.isAnnotation()); + } + + + protected void tearDown() throws Exception { + super.tearDown(); + } + + +} diff --git a/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/AnnotationDefaultAttributeTest.java b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/AnnotationDefaultAttributeTest.java new file mode 100644 index 000000000..7db628cb0 --- /dev/null +++ b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/AnnotationDefaultAttributeTest.java @@ -0,0 +1,49 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation + * ******************************************************************/ + +package org.aspectj.apache.bcel.classfile.tests; + +import org.aspectj.apache.bcel.classfile.AnnotationDefault; +import org.aspectj.apache.bcel.classfile.JavaClass; +import org.aspectj.apache.bcel.classfile.Method; +import org.aspectj.apache.bcel.classfile.annotation.ElementValue; +import org.aspectj.apache.bcel.classfile.annotation.SimpleElementValue; + +public class AnnotationDefaultAttributeTest extends BcelTestCase { + + protected void setUp() throws Exception { + super.setUp(); + } + + + /** + * For values in an annotation that have default values, we should be able to + * query the AnnotationDefault attribute against the method to discover the + * default value that was originally declared. + */ + public void testMethodAnnotations() throws ClassNotFoundException { + JavaClass clazz = getClassFromJar("SimpleAnnotation"); + + Method m = getMethod(clazz,"fruit"); + AnnotationDefault a = (AnnotationDefault) findAttribute("AnnotationDefault",m.getAttributes()); + SimpleElementValue val = (SimpleElementValue) a.getElementValue(); + assertTrue("Should be STRING but is "+val.getElementValueType(), + val.getElementValueType()==ElementValue.STRING); + assertTrue("Should have default of bananas but default is "+val.getValueString(), + val.getValueString().equals("bananas")); + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + +} diff --git a/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/AnnotationGenTest.java b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/AnnotationGenTest.java new file mode 100644 index 000000000..a98fcecff --- /dev/null +++ b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/AnnotationGenTest.java @@ -0,0 +1,122 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM All rights reserved. This program and the accompanying + * materials are made available under the terms of the Common Public License + * v1.0 which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: Andy Clement - initial implementation + ******************************************************************************/ + +package org.aspectj.apache.bcel.classfile.tests; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.aspectj.apache.bcel.Constants; +import org.aspectj.apache.bcel.generic.ClassGen; +import org.aspectj.apache.bcel.generic.ConstantPoolGen; +import org.aspectj.apache.bcel.generic.ObjectType; +import org.aspectj.apache.bcel.generic.annotation.AnnotationGen; +import org.aspectj.apache.bcel.generic.annotation.ElementNameValuePairGen; +import org.aspectj.apache.bcel.generic.annotation.ElementValueGen; +import org.aspectj.apache.bcel.generic.annotation.SimpleElementValueGen; + +public class AnnotationGenTest extends BcelTestCase { + + protected void setUp() throws Exception { + super.setUp(); + } + + private ClassGen createClassGen(String classname) { + return new ClassGen(classname, "java.lang.Object", + "<generated>", Constants.ACC_PUBLIC | Constants.ACC_SUPER, null); + } + + /** + * Programmatically construct an mutable annotation (AnnotationGen) object. + */ + public void testConstructMutableAnnotation() { + + // Create the containing class + ClassGen cg = createClassGen("HelloWorld"); + ConstantPoolGen cp = cg.getConstantPool(); + + // Create the simple primitive value '4' of type 'int' + SimpleElementValueGen evg = + new SimpleElementValueGen(ElementValueGen.PRIMITIVE_INT,cp,4); + + // Give it a name, call it 'id' + ElementNameValuePairGen nvGen = new ElementNameValuePairGen("id",evg,cp); + + // Check it looks right + assertTrue("Should include string 'id=4' but says: "+nvGen.toString(), + nvGen.toString().indexOf("id=4")!=-1); + + + ObjectType t = new ObjectType("SimpleAnnotation"); + + List elements = new ArrayList(); + elements.add(nvGen); + + // Build an annotation of type 'SimpleAnnotation' with 'id=4' as the only value :) + AnnotationGen a = new AnnotationGen(t,elements,true,cp); + + // Check we can save and load it ok + checkSerialize(a,cp); + } + + //// + // Helper methods + + private void checkSerialize(AnnotationGen a,ConstantPoolGen cpg) { + try { + String beforeName = a.getTypeName(); + List beforeValues = a.getValues(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + a.dump(dos); + dos.flush(); + dos.close(); + + byte[] bs = baos.toByteArray(); + + ByteArrayInputStream bais = new ByteArrayInputStream(bs); + DataInputStream dis = new DataInputStream(bais); + AnnotationGen annAfter = AnnotationGen.read(dis,cpg,a.isRuntimeVisible()); + + dis.close(); + + String afterName = annAfter.getTypeName(); + List afterValues = annAfter.getValues(); + + if (!beforeName.equals(afterName)) { + fail("Deserialization failed: before type='"+beforeName+"' after type='"+afterName+"'"); + } + if (a.getValues().size()!=annAfter.getValues().size()) { + fail("Different numbers of element name value pairs?? "+a.getValues().size()+"!="+annAfter.getValues().size()); + } + for (int i=0;i<a.getValues().size();i++) { + ElementNameValuePairGen beforeElement = (ElementNameValuePairGen) a.getValues().get(i); + ElementNameValuePairGen afterElement = (ElementNameValuePairGen) annAfter.getValues().get(i); + if (!beforeElement.getNameString().equals(afterElement.getNameString())) { + fail("Different names?? "+beforeElement.getNameString()+"!="+afterElement.getNameString()); + } + } + + + } catch (IOException ioe) { + fail("Unexpected exception whilst checking serialization: "+ioe); + } + } + + + protected void tearDown() throws Exception { + super.tearDown(); + } + +}
\ No newline at end of file diff --git a/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/BcelTestCase.java b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/BcelTestCase.java new file mode 100644 index 000000000..87c6dc21e --- /dev/null +++ b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/BcelTestCase.java @@ -0,0 +1,150 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation {date} + * ******************************************************************/ + +package org.aspectj.apache.bcel.classfile.tests; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.aspectj.apache.bcel.classfile.Attribute; +import org.aspectj.apache.bcel.classfile.JavaClass; +import org.aspectj.apache.bcel.classfile.Method; +import org.aspectj.apache.bcel.classfile.annotation.Annotation; +import org.aspectj.apache.bcel.generic.ConstantPoolGen; +import org.aspectj.apache.bcel.generic.ObjectType; +import org.aspectj.apache.bcel.generic.annotation.AnnotationGen; +import org.aspectj.apache.bcel.generic.annotation.ElementNameValuePairGen; +import org.aspectj.apache.bcel.generic.annotation.ElementValueGen; +import org.aspectj.apache.bcel.generic.annotation.SimpleElementValueGen; +import org.aspectj.apache.bcel.util.ClassPath; +import org.aspectj.apache.bcel.util.SyntheticRepository; + +import junit.framework.TestCase; + +/** + * Super class for the Java5 tests, includes various helper methods. + */ + +public class BcelTestCase extends TestCase { + + private boolean verbose = false; + + protected File createTestdataFile(String name) { + return new File("testdata"+File.separator+name); + } + + protected JavaClass getClassFromJar(String clazzname) throws ClassNotFoundException { + SyntheticRepository repos = createRepos("testcode.jar"); + return repos.loadClass(clazzname); + } + + protected Method getMethod(JavaClass cl,String methodname) { + Method[] methods = cl.getMethods(); + for (int i = 0; i < methods.length; i++) { + Method m = methods[i]; + if (m.getName().equals(methodname)) { + return m; + } + } + return null; + } + + protected boolean wipe(String name) { + return new File("testdata"+File.separator+name).delete(); + } + + protected boolean wipe(String dir, String name) { + boolean b = wipe(dir+File.separator+name); + String[] files = new File(dir).list(); + if (files==null || files.length==0) { + new File(dir).delete(); // Why does this not succeed? stupid thing + } + return b; + } + + + public SyntheticRepository createRepos(String cpentry) { + ClassPath cp = new ClassPath( + "testdata"+File.separator+cpentry+File.pathSeparator+ + System.getProperty("java.class.path")); + return SyntheticRepository.getInstance(cp); + } + + protected Attribute[] findAttribute(String name, JavaClass clazz) { + Attribute[] all = clazz.getAttributes(); + List chosenAttrsList = new ArrayList(); + for (int i = 0; i < all.length; i++) { + if (verbose) System.err.println("Attribute: "+all[i].getName()); + if (all[i].getName().equals(name)) chosenAttrsList.add(all[i]); + } + return (Attribute[])chosenAttrsList.toArray(new Attribute[]{}); + } + + protected Attribute findAttribute(String name, Attribute[] all) { + List chosenAttrsList = new ArrayList(); + for (int i = 0; i < all.length; i++) { + if (verbose) System.err.println("Attribute: "+all[i].getName()); + if (all[i].getName().equals(name)) chosenAttrsList.add(all[i]); + } + assertTrue("Should be one match: "+chosenAttrsList.size(),chosenAttrsList.size()==1); + return (Attribute)chosenAttrsList.get(0); + } + + protected String dumpAnnotations(Annotation[] as) { + StringBuffer result = new StringBuffer(); + result.append("["); + for (int i = 0; i < as.length; i++) { + Annotation annotation = as[i]; + result.append(annotation.toShortString()); + if (i+1<as.length) result.append(","); + } + result.append("]"); + return result.toString(); + } + + protected String dumpAnnotations(AnnotationGen[] as) { + StringBuffer result = new StringBuffer(); + result.append("["); + for (int i = 0; i < as.length; i++) { + AnnotationGen annotation = as[i]; + result.append(annotation.toShortString()); + if (i+1<as.length) result.append(","); + } + result.append("]"); + return result.toString(); + } + + protected String dumpAttributes(Attribute[] as) { + StringBuffer result = new StringBuffer(); + result.append("AttributeArray:["); + for (int i = 0; i < as.length; i++) { + Attribute attr = as[i]; + result.append(attr.toString()); + if (i+1<as.length) result.append(","); + } + result.append("]"); + return result.toString(); + } + + public AnnotationGen createFruitAnnotation(ConstantPoolGen cp, String aFruit, boolean visibility) { + SimpleElementValueGen evg = new SimpleElementValueGen(ElementValueGen.STRING,cp,aFruit); + ElementNameValuePairGen nvGen = new ElementNameValuePairGen("fruit",evg,cp); + ObjectType t = new ObjectType("SimpleStringAnnotation"); + List elements = new ArrayList(); + elements.add(nvGen); + return new AnnotationGen(t,elements,visibility,cp); + } + + + +} diff --git a/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/ElementValueGenTest.java b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/ElementValueGenTest.java new file mode 100644 index 000000000..884270c9f --- /dev/null +++ b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/ElementValueGenTest.java @@ -0,0 +1,227 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM All rights reserved. This program and the accompanying + * materials are made available under the terms of the Common Public License + * v1.0 which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: Andy Clement - initial implementation + ******************************************************************************/ + +package org.aspectj.apache.bcel.classfile.tests; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.aspectj.apache.bcel.Constants; +import org.aspectj.apache.bcel.generic.ClassGen; +import org.aspectj.apache.bcel.generic.ConstantPoolGen; +import org.aspectj.apache.bcel.generic.ObjectType; +import org.aspectj.apache.bcel.generic.annotation.ClassElementValueGen; +import org.aspectj.apache.bcel.generic.annotation.ElementValueGen; +import org.aspectj.apache.bcel.generic.annotation.EnumElementValueGen; +import org.aspectj.apache.bcel.generic.annotation.SimpleElementValueGen; + +public class ElementValueGenTest extends BcelTestCase { + + protected void setUp() throws Exception { + super.setUp(); + } + + private ClassGen createClassGen(String classname) { + return new ClassGen(classname, "java.lang.Object", + "<generated>", Constants.ACC_PUBLIC | Constants.ACC_SUPER, null); + } + + //// + // Create primitive element values + + public void testCreateIntegerElementValue() { + ClassGen cg = createClassGen("HelloWorld"); + ConstantPoolGen cp = cg.getConstantPool(); + + SimpleElementValueGen evg = new SimpleElementValueGen(ElementValueGen.PRIMITIVE_INT,cp,555); + // Creation of an element like that should leave a new entry in the cpool + assertTrue("Should have the same index in the constantpool but "+evg.getIndex()+"!="+cp.lookupInteger(555), + evg.getIndex()==cp.lookupInteger(555)); + checkSerialize(evg,cp); + } + + public void testCreateFloatElementValue() { + ClassGen cg = createClassGen("HelloWorld"); + ConstantPoolGen cp = cg.getConstantPool(); + + SimpleElementValueGen evg = new SimpleElementValueGen(ElementValueGen.PRIMITIVE_FLOAT,cp,111.222f); + // Creation of an element like that should leave a new entry in the cpool + assertTrue("Should have the same index in the constantpool but "+evg.getIndex()+"!="+cp.lookupFloat(111.222f), + evg.getIndex()==cp.lookupFloat(111.222f)); + checkSerialize(evg,cp); + } + + public void testCreateDoubleElementValue() { + ClassGen cg = createClassGen("HelloWorld"); + ConstantPoolGen cp = cg.getConstantPool(); + + SimpleElementValueGen evg = new SimpleElementValueGen(ElementValueGen.PRIMITIVE_DOUBLE,cp,333.44); + // Creation of an element like that should leave a new entry in the cpool + int idx = cp.lookupDouble(333.44); + assertTrue("Should have the same index in the constantpool but "+evg.getIndex()+"!="+idx, + evg.getIndex()==idx); + checkSerialize(evg,cp); + } + + public void testCreateLongElementValue() { + ClassGen cg = createClassGen("HelloWorld"); + ConstantPoolGen cp = cg.getConstantPool(); + + SimpleElementValueGen evg = new SimpleElementValueGen(ElementValueGen.PRIMITIVE_LONG,cp,3334455L); + // Creation of an element like that should leave a new entry in the cpool + int idx = cp.lookupLong(3334455L); + assertTrue("Should have the same index in the constantpool but "+evg.getIndex()+"!="+idx, + evg.getIndex()==idx); + checkSerialize(evg,cp); + } + + public void testCreateCharElementValue() { + ClassGen cg = createClassGen("HelloWorld"); + ConstantPoolGen cp = cg.getConstantPool(); + + SimpleElementValueGen evg = new SimpleElementValueGen(ElementValueGen.PRIMITIVE_CHAR,cp,(char)'t'); + // Creation of an element like that should leave a new entry in the cpool + int idx = cp.lookupInteger((char)'t'); + assertTrue("Should have the same index in the constantpool but "+evg.getIndex()+"!="+idx, + evg.getIndex()==idx); + checkSerialize(evg,cp); + } + + public void testCreateByteElementValue() { + ClassGen cg = createClassGen("HelloWorld"); + ConstantPoolGen cp = cg.getConstantPool(); + + SimpleElementValueGen evg = new SimpleElementValueGen(ElementValueGen.PRIMITIVE_CHAR,cp,(byte)'z'); + // Creation of an element like that should leave a new entry in the cpool + int idx = cp.lookupInteger((byte)'z'); + assertTrue("Should have the same index in the constantpool but "+evg.getIndex()+"!="+idx, + evg.getIndex()==idx); + checkSerialize(evg,cp); + } + + public void testCreateBooleanElementValue() { + ClassGen cg = createClassGen("HelloWorld"); + ConstantPoolGen cp = cg.getConstantPool(); + + SimpleElementValueGen evg = new SimpleElementValueGen(ElementValueGen.PRIMITIVE_BOOLEAN,cp,true); + // Creation of an element like that should leave a new entry in the cpool + int idx = cp.lookupInteger(1); // 1 == true + assertTrue("Should have the same index in the constantpool but "+evg.getIndex()+"!="+idx, + evg.getIndex()==idx); + checkSerialize(evg,cp); + } + + public void testCreateShortElementValue() { + ClassGen cg = createClassGen("HelloWorld"); + ConstantPoolGen cp = cg.getConstantPool(); + + SimpleElementValueGen evg = new SimpleElementValueGen(ElementValueGen.PRIMITIVE_SHORT,cp,(short)42); + // Creation of an element like that should leave a new entry in the cpool + int idx = cp.lookupInteger(42); + assertTrue("Should have the same index in the constantpool but "+evg.getIndex()+"!="+idx, + evg.getIndex()==idx); + checkSerialize(evg,cp); + } + + //// + // Create string element values + + public void testCreateStringElementValue() { + + // Create HelloWorld + ClassGen cg = createClassGen("HelloWorld"); + ConstantPoolGen cp = cg.getConstantPool(); + + SimpleElementValueGen evg = new SimpleElementValueGen(ElementValueGen.STRING,cp,"hello"); + // Creation of an element like that should leave a new entry in the cpool + assertTrue("Should have the same index in the constantpool but "+evg.getIndex()+"!="+cp.lookupUtf8("hello"), + evg.getIndex()==cp.lookupUtf8("hello")); + checkSerialize(evg,cp); + } + + //// + // Create enum element value + + public void testCreateEnumElementValue() { + ClassGen cg = createClassGen("HelloWorld"); + ConstantPoolGen cp = cg.getConstantPool(); + + + ObjectType enumType = new ObjectType("SimpleEnum"); // Supports rainbow :) + + EnumElementValueGen evg = new EnumElementValueGen(enumType,"Red",cp); + // Creation of an element like that should leave a new entry in the cpool + assertTrue("The new ElementValue value index should match the contents of the constantpool but "+ + evg.getValueIndex()+"!="+cp.lookupString("Red"), + evg.getValueIndex()==cp.lookupString("Red")); + //BCELBUG: Should the class signature or class name be in the constant pool? (see note in ConstantPool) +// assertTrue("The new ElementValue type index should match the contents of the constantpool but "+ +// evg.getTypeIndex()+"!="+cp.lookupClass(enumType.getSignature()), +// evg.getTypeIndex()==cp.lookupClass(enumType.getSignature())); + + checkSerialize(evg,cp); + } + + //// + // Create class element value + + public void testCreateClassElementValue() { + ClassGen cg = createClassGen("HelloWorld"); + ConstantPoolGen cp = cg.getConstantPool(); + + ObjectType classType = new ObjectType("java.lang.Integer"); + + ClassElementValueGen evg = new ClassElementValueGen(classType,cp); + + assertTrue("Unexpected value for contained class: '"+evg.getClassString()+"'", + evg.getClassString().indexOf("Integer")!=-1); + + checkSerialize(evg,cp); + } + + + //// + // Helper methods + + private void checkSerialize(ElementValueGen evgBefore,ConstantPoolGen cpg) { + try { + String beforeValue = evgBefore.stringifyValue(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + evgBefore.dump(dos); + dos.flush(); + dos.close(); + + byte[] bs = baos.toByteArray(); + + ByteArrayInputStream bais = new ByteArrayInputStream(bs); + DataInputStream dis = new DataInputStream(bais); + ElementValueGen evgAfter = ElementValueGen.readElementValue(dis,cpg); + + dis.close(); + String afterValue = evgAfter.stringifyValue(); + + if (!beforeValue.equals(afterValue)) { + fail("Deserialization failed: before='"+beforeValue+"' after='"+afterValue+"'"); + } + + } catch (IOException ioe) { + fail("Unexpected exception whilst checking serialization: "+ioe); + } + } + + + protected void tearDown() throws Exception { + super.tearDown(); + } + +}
\ No newline at end of file diff --git a/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/EnclosingMethodAttributeTest.java b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/EnclosingMethodAttributeTest.java new file mode 100644 index 000000000..d4d57b934 --- /dev/null +++ b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/EnclosingMethodAttributeTest.java @@ -0,0 +1,104 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation + * ******************************************************************/ + +package org.aspectj.apache.bcel.classfile.tests; + +import java.io.File; +import java.io.IOException; + +import org.aspectj.apache.bcel.classfile.Attribute; +import org.aspectj.apache.bcel.classfile.ConstantPool; +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 { + + 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. + */ + 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")); + } + + /** + * 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")); + } + + /** + * Check that we can save and load the attribute correctly. + */ + 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); + + // 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")); + assertTrue(tfile.delete()); + } + + + protected void tearDown() throws Exception { + super.tearDown(); + } + +} diff --git a/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/EnumAccessFlagTest.java b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/EnumAccessFlagTest.java new file mode 100644 index 000000000..9ede5f03c --- /dev/null +++ b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/EnumAccessFlagTest.java @@ -0,0 +1,56 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation + * ******************************************************************/ + +package org.aspectj.apache.bcel.classfile.tests; + +import java.io.File; + +import junit.framework.TestCase; + +import org.aspectj.apache.bcel.classfile.ConstantPool; +import org.aspectj.apache.bcel.classfile.JavaClass; +import org.aspectj.apache.bcel.util.ClassPath; +import org.aspectj.apache.bcel.util.SyntheticRepository; + +public class EnumAccessFlagTest extends TestCase { + + private boolean verbose = false; + + protected void setUp() throws Exception { + super.setUp(); + } + + /** + * An enumerated type, once compiled, should result in a class file that + * is marked such that we can determine from the access flags (through BCEL) that + * it was originally an enum type declaration. + */ + public void testEnumClassSaysItIs() throws ClassNotFoundException { + ClassPath cp = + new ClassPath("testdata"+File.separator+"testcode.jar"+File.pathSeparator+System.getProperty("java.class.path")); + SyntheticRepository repos = SyntheticRepository.getInstance(cp); + JavaClass clazz = repos.loadClass("SimpleEnum"); + ConstantPool pool = clazz.getConstantPool(); + assertTrue("Expected SimpleEnum class to say it was an enum - but it didn't !", + clazz.isEnum()); + clazz = repos.loadClass("SimpleClass"); + assertTrue("Expected SimpleClass class to say it was not an enum - but it didn't !", + !clazz.isEnum()); + } + + + protected void tearDown() throws Exception { + super.tearDown(); + } + + +} diff --git a/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/FieldAnnotationsTest.java b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/FieldAnnotationsTest.java new file mode 100644 index 000000000..a08df20b6 --- /dev/null +++ b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/FieldAnnotationsTest.java @@ -0,0 +1,147 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation + * ******************************************************************/ + +package org.aspectj.apache.bcel.classfile.tests; + +import java.io.File; +import java.io.IOException; +import java.util.Iterator; + +import org.aspectj.apache.bcel.classfile.Field; +import org.aspectj.apache.bcel.classfile.JavaClass; +import org.aspectj.apache.bcel.classfile.annotation.Annotation; +import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePair; +import org.aspectj.apache.bcel.generic.ClassGen; +import org.aspectj.apache.bcel.generic.FieldGen; +import org.aspectj.apache.bcel.generic.annotation.AnnotationGen; +import org.aspectj.apache.bcel.util.SyntheticRepository; + + +public class FieldAnnotationsTest extends BcelTestCase { + + + protected void setUp() throws Exception { + super.setUp(); + } + + + /** + * Check field annotations are retrievable. + */ + public void testFieldAnnotations() throws ClassNotFoundException { + JavaClass clazz = getClassFromJar("AnnotatedFields"); + + checkAnnotatedField(clazz,"i","SimpleAnnotation","id","1"); + checkAnnotatedField(clazz,"s","SimpleAnnotation","id","2"); + + } + + /** + * Check field annotations (de)serialize ok. + */ + public void testFieldAnnotationsReadWrite() throws ClassNotFoundException,IOException { + JavaClass clazz = getClassFromJar("AnnotatedFields"); + + checkAnnotatedField(clazz,"i","SimpleAnnotation","id","1"); + checkAnnotatedField(clazz,"s","SimpleAnnotation","id","2"); + + // Write it out + File tfile = createTestdataFile("AnnotatedFields.class"); + clazz.dump(tfile); + + SyntheticRepository repos2 = createRepos("."); + JavaClass clazz2 = repos2.loadClass("AnnotatedFields"); + + checkAnnotatedField(clazz,"i","SimpleAnnotation","id","1"); + checkAnnotatedField(clazz,"s","SimpleAnnotation","id","2"); + + assertTrue(tfile.delete()); + } + + /** + * Check we can load in a class, modify its field annotations, save it, reload it and + * everything is correct. + */ + public void testFieldAnnotationsModification() throws ClassNotFoundException, IOException { + boolean dbg = false; + JavaClass clazz = getClassFromJar("AnnotatedFields"); + + ClassGen clg = new ClassGen(clazz); + Field f = clg.getFields()[0]; + if (dbg) System.err.println("Field in freshly constructed class is: "+f); + if (dbg) System.err.println("Annotations on field are: "+dumpAnnotations(f.getAnnotations())); + AnnotationGen fruitBasedAnnotation = createFruitAnnotation(clg.getConstantPool(),"Tomato",false); + FieldGen fg = new FieldGen(f,clg.getConstantPool()); + if (dbg) System.err.println("Adding annotation to the field"); + fg.addAnnotation(fruitBasedAnnotation); + if (dbg) System.err.println("FieldGen (mutable field) is "+fg); + if (dbg) System.err.println("with annotations: "+dumpAnnotations(fg.getAnnotations())); + + if (dbg) System.err.println("Replacing original field with new field that has extra annotation"); + clg.removeField(f); + clg.addField(fg.getField()); + + f = clg.getFields()[1]; // there are two fields in the class, removing and readding has changed the order + // so this time index [1] is the 'int i' field + if (dbg) System.err.println("Field now looks like this: "+f); + if (dbg) System.err.println("With annotations: "+dumpAnnotations(f.getAnnotations())); + assertTrue("Should be 2 annotations on this field, but there are "+f.getAnnotations().length,f.getAnnotations().length==2); + } + + // helper methods + + public void checkAnnotatedField(JavaClass clazz,String fieldname, + String annotationName,String annotationElementName,String annotationElementValue) { + Field[] fields = clazz.getFields(); + + for (int i = 0; i < fields.length; i++) { + Field f = fields[i]; + Annotation[] fieldAnnotations = f.getAnnotations(); + if (f.getName().equals(fieldname)) { + checkAnnotation(fieldAnnotations[0],annotationName,annotationElementName,annotationElementValue); + + } + } + } + + private void checkAnnotation(Annotation a,String name,String elementname,String elementvalue) { + assertTrue("Expected annotation to have name "+name+" but it had name "+a.getTypeName(), + a.getTypeName().equals(name)); + assertTrue("Expected annotation to have one element but it had "+a.getValues().size(),a.getValues().size()==1); + ElementNameValuePair envp = (ElementNameValuePair)a.getValues().get(0); + assertTrue("Expected element name "+elementname+" but was "+envp.getNameString(), + elementname.equals(envp.getNameString())); + assertTrue("Expected element value "+elementvalue+" but was "+envp.getValue().stringifyValue(), + elementvalue.equals(envp.getValue().stringifyValue())); + } + + + // helper methods + + public void checkValue(Annotation a,String name,String tostring) { + for (Iterator i = a.getValues().iterator(); i.hasNext();) { + ElementNameValuePair element = (ElementNameValuePair) i.next(); + if (element.getNameString().equals(name)) { + if (!element.getValue().stringifyValue().equals(tostring)) { + fail("Expected element "+name+" to have value "+tostring+" but it had value "+element.getValue().stringifyValue()); + } + return; + } + } + fail("Didnt find named element "+name); + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + +} diff --git a/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/GeneratingAnnotatedClassesTest.java b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/GeneratingAnnotatedClassesTest.java new file mode 100644 index 000000000..8ba4f2fa1 --- /dev/null +++ b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/GeneratingAnnotatedClassesTest.java @@ -0,0 +1,633 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM All rights reserved. This program and the accompanying + * materials are made available under the terms of the Common Public License + * v1.0 which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: Andy Clement - initial implementation + ******************************************************************************/ + +package org.aspectj.apache.bcel.classfile.tests; + +import java.io.File; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.aspectj.apache.bcel.Constants; +import org.aspectj.apache.bcel.classfile.JavaClass; +import org.aspectj.apache.bcel.classfile.Method; +import org.aspectj.apache.bcel.classfile.annotation.Annotation; +import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePair; +import org.aspectj.apache.bcel.classfile.annotation.ElementValue; +import org.aspectj.apache.bcel.generic.ALOAD; +import org.aspectj.apache.bcel.generic.ASTORE; +import org.aspectj.apache.bcel.generic.ArrayType; +import org.aspectj.apache.bcel.generic.ClassGen; +import org.aspectj.apache.bcel.generic.ConstantPoolGen; +import org.aspectj.apache.bcel.generic.GOTO; +import org.aspectj.apache.bcel.generic.InstructionConstants; +import org.aspectj.apache.bcel.generic.InstructionFactory; +import org.aspectj.apache.bcel.generic.InstructionHandle; +import org.aspectj.apache.bcel.generic.InstructionList; +import org.aspectj.apache.bcel.generic.LocalVariableGen; +import org.aspectj.apache.bcel.generic.MethodGen; +import org.aspectj.apache.bcel.generic.ObjectType; +import org.aspectj.apache.bcel.generic.PUSH; +import org.aspectj.apache.bcel.generic.Type; +import org.aspectj.apache.bcel.generic.annotation.AnnotationElementValueGen; +import org.aspectj.apache.bcel.generic.annotation.AnnotationGen; +import org.aspectj.apache.bcel.generic.annotation.ArrayElementValueGen; +import org.aspectj.apache.bcel.generic.annotation.ElementNameValuePairGen; +import org.aspectj.apache.bcel.generic.annotation.ElementValueGen; +import org.aspectj.apache.bcel.generic.annotation.SimpleElementValueGen; +import org.aspectj.apache.bcel.util.SyntheticRepository; + +/** + * The program that some of the tests generate looks like this: + public class HelloWorld { + public static void main(String[] argv) { + BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + String name = null; + try { + name = "Andy"; + } catch(IOException e) { return; } + System.out.println("Hello, " + name); + } + } + * + */ +public class GeneratingAnnotatedClassesTest extends BcelTestCase { + + protected void setUp() throws Exception { + super.setUp(); + } + + + /* + * Steps in the test: + * 1) Programmatically construct the HelloWorld program + * 2) Add two simple annotations at the class level + * 3) Save the class to disk + * 4) Reload the class using the 'static' variant of the BCEL classes + * 5) Check the attributes are OK + */ + public void testGenerateClassLevelAnnotations() throws ClassNotFoundException { + + // Create HelloWorld + ClassGen cg = createClassGen("HelloWorld"); + ConstantPoolGen cp = cg.getConstantPool(); + InstructionList il = new InstructionList(); + + cg.addAnnotation(createSimpleVisibleAnnotation(cp)); + cg.addAnnotation(createSimpleInvisibleAnnotation(cp)); + + buildClassContents(cg, cp, il); + + dumpClass(cg, "HelloWorld.class"); + + JavaClass jc = getClassFrom(".","HelloWorld"); + + Annotation[] as = jc.getAnnotations(); + assertTrue("Should be two annotations but found "+as.length,as.length==2); + Annotation one = as[0]; + Annotation two = as[1]; + assertTrue("Name of annotation 1 should be SimpleAnnotation but it is "+as[0].getTypeName(), + as[0].getTypeName().equals("SimpleAnnotation")); + assertTrue("Name of annotation 2 should be SimpleAnnotation but it is "+as[1].getTypeName(), + as[1].getTypeName().equals("SimpleAnnotation")); + List vals = as[0].getValues(); + ElementNameValuePair nvp = (ElementNameValuePair) vals.get(0); + assertTrue("Name of element in SimpleAnnotation should be 'id' but it is "+ + nvp.getNameString(),nvp.getNameString().equals("id")); + ElementValue ev = nvp.getValue(); + assertTrue("Type of element value should be int but it is "+ev.getElementValueType(), + ev.getElementValueType()==ElementValue.PRIMITIVE_INT); + assertTrue("Value of element should be 4 but it is "+ev.stringifyValue(), + ev.stringifyValue().equals("4")); + assertTrue(createTestdataFile("HelloWorld.class").delete()); + } + + + + /** + * Just check that we can dump a class that has a method + * annotation on it and it is still there when we read it back in + */ + public void testGenerateMethodLevelAnnotations1() throws ClassNotFoundException { + // Create HelloWorld + ClassGen cg = createClassGen("HelloWorld"); + ConstantPoolGen cp = cg.getConstantPool(); + InstructionList il = new InstructionList(); + + buildClassContentsWithAnnotatedMethods(cg, cp, il); + + // Check annotation is OK + int i = cg.getMethods()[0].getAnnotations().length; + assertTrue("Prior to dumping, main method should have 1 annotation but has "+i,i==1); + + dumpClass(cg, "temp1"+File.separator+"HelloWorld.class"); + + JavaClass jc2 = getClassFrom("temp1","HelloWorld"); + + // Check annotation is OK + i = jc2.getMethods()[0].getAnnotations().length; + assertTrue("JavaClass should say 1 annotation on main method but says "+i,i==1); + + + ClassGen cg2 = new ClassGen(jc2); + + // Check it now it is a ClassGen + Method[] m = cg2.getMethods(); + i = m[0].getAnnotations().length; + assertTrue("The main 'Method' should have one annotation but has "+i,i==1); + MethodGen mg = new MethodGen(m[0],cg2.getClassName(),cg2.getConstantPool()); + + // Check it finally when the Method is changed to a MethodGen + i = mg.getAnnotations().length; + assertTrue("The main 'MethodGen' should have one annotation but has "+i,i==1); + + assertTrue(wipe("temp1"+File.separator+"HelloWorld.class")); + + } + + /** + * Going further than the last test - when we reload the method back in, let's change it (adding a new + * annotation) and then store that, read it back in and verify both annotations are there ! + */ + public void testGenerateMethodLevelAnnotations2() throws ClassNotFoundException { + // Create HelloWorld + ClassGen cg = createClassGen("HelloWorld"); + ConstantPoolGen cp = cg.getConstantPool(); + InstructionList il = new InstructionList(); + + buildClassContentsWithAnnotatedMethods(cg, cp, il); + + dumpClass(cg,"temp2","HelloWorld.class"); + + JavaClass jc2 = getClassFrom("temp2","HelloWorld"); + + ClassGen cg2 = new ClassGen(jc2); + + // Main method after reading the class back in + Method mainMethod1 = jc2.getMethods()[0]; + assertTrue("The 'Method' should have one annotations but has "+mainMethod1.getAnnotations().length, + mainMethod1.getAnnotations().length==1); + + MethodGen mainMethod2 = new MethodGen(mainMethod1,cg2.getClassName(),cg2.getConstantPool()); + + assertTrue("The 'MethodGen' should have one annotations but has "+mainMethod2.getAnnotations().length, + mainMethod2.getAnnotations().length==1); + + mainMethod2.addAnnotation(createFruitAnnotation(cg2.getConstantPool(),"Pear")); + + cg2.removeMethod(mainMethod1); + cg2.addMethod(mainMethod2.getMethod()); + + dumpClass(cg2,"temp3","HelloWorld.class"); + + JavaClass jc3 = getClassFrom("temp3","HelloWorld"); + + ClassGen cg3 = new ClassGen(jc3); + + Method mainMethod3 = cg3.getMethods()[1]; + int i = mainMethod3.getAnnotations().length; + assertTrue("The 'Method' should now have two annotations but has "+i,i==2); + + assertTrue(wipe("temp2","HelloWorld.class")); + assertTrue(wipe("temp3","HelloWorld.class")); + } + + + + //J5TODO: Need to add deleteFile calls to many of these tests + + /** + * Transform simple class from an immutable to a mutable object. + */ + public void testTransformClassToClassGen_SimpleTypes() throws ClassNotFoundException { + JavaClass jc = getClassFrom("testcode.jar","SimpleAnnotatedClass"); + ClassGen cgen = new ClassGen(jc); + + // Check annotations are correctly preserved + AnnotationGen[] annotations = cgen.getAnnotations(); + assertTrue("Expected one annotation but found "+annotations.length, + annotations.length==1); + } + + /** + * Transform simple class from an immutable to a mutable object. The class is + * annotated with an annotation that uses an enum. + */ + public void testTransformClassToClassGen_EnumType() throws ClassNotFoundException { + JavaClass jc = getClassFrom("testcode.jar","AnnotatedWithEnumClass"); + ClassGen cgen = new ClassGen(jc); + + // Check annotations are correctly preserved + AnnotationGen[] annotations = cgen.getAnnotations(); + assertTrue("Expected one annotation but found "+annotations.length, + annotations.length==1); + } + + /** + * Transform simple class from an immutable to a mutable object. The class is + * annotated with an annotation that uses an array of SimpleAnnotations. + */ + public void testTransformClassToClassGen_ArrayAndAnnotationTypes() throws ClassNotFoundException { + JavaClass jc = getClassFrom("testcode.jar","AnnotatedWithCombinedAnnotation"); + ClassGen cgen = new ClassGen(jc); + + // Check annotations are correctly preserved + AnnotationGen[] annotations = cgen.getAnnotations(); + assertTrue("Expected one annotation but found "+annotations.length, + annotations.length==1); + AnnotationGen a = annotations[0]; + assertTrue("That annotation should only have one value but has "+a.getValues().size(),a.getValues().size()==1); + ElementNameValuePairGen nvp = (ElementNameValuePairGen)a.getValues().get(0); + ElementValueGen value = (ElementValueGen)nvp.getValue(); + assertTrue("Value should be ArrayElementValueGen but is "+value,value instanceof ArrayElementValueGen); + ArrayElementValueGen arrayValue = (ArrayElementValueGen)value; + assertTrue("Array value should be size one but is "+arrayValue.getElementValuesSize(), + arrayValue.getElementValuesSize()==1); + ElementValueGen innerValue = (ElementValueGen)arrayValue.getElementValues().get(0); + assertTrue("Value in the array should be AnnotationElementValueGen but is "+innerValue, + innerValue instanceof AnnotationElementValueGen); + AnnotationElementValueGen innerAnnotationValue = (AnnotationElementValueGen)innerValue; + assertTrue("Should be called LSimpleAnnotation; but is called: "+innerAnnotationValue.getAnnotation().getTypeName(), + innerAnnotationValue.getAnnotation().getTypeSignature().equals("LSimpleAnnotation;")); + } + + /** + * Transform complex class from an immutable to a mutable object. + */ + public void testTransformComplexClassToClassGen() throws ClassNotFoundException { + JavaClass jc = getClassFrom("testcode.jar","ComplexAnnotatedClass"); + ClassGen cgen = new ClassGen(jc); + + // Check annotations are correctly preserved + AnnotationGen[] annotations = cgen.getAnnotations(); + assertTrue("Expected one annotation but found "+annotations.length, + annotations.length==1); + List l = annotations[0].getValues(); + boolean found = false; + for (Iterator iter = l.iterator(); iter.hasNext();) { + ElementNameValuePairGen element = (ElementNameValuePairGen) iter.next(); + if (element.getNameString().equals("dval")) { + if (((SimpleElementValueGen)element.getValue()).stringifyValue().equals("33.4")) + found = true; + } + } + assertTrue("Did not find double annotation value with value 33.4",found); + } + + + /** + * Load a class in and modify it with a new attribute - A SimpleAnnotation annotation + */ + public void testModifyingClasses1() throws ClassNotFoundException { + JavaClass jc = getClassFrom("testcode.jar","SimpleAnnotatedClass"); + ClassGen cgen = new ClassGen(jc); + ConstantPoolGen cp = cgen.getConstantPool(); + cgen.addAnnotation(createFruitAnnotation(cp,"Pineapple")); + assertTrue("Should now have two annotations but has "+cgen.getAnnotations().length, + cgen.getAnnotations().length==2); + dumpClass(cgen,"SimpleAnnotatedClass.class"); + assertTrue(wipe("SimpleAnnotatedClass.class")); + } + + /** + * Load a class in and modify it with a new attribute - A ComplexAnnotation annotation + */ + public void testModifyingClasses2() throws ClassNotFoundException { + JavaClass jc = getClassFrom("testcode.jar","SimpleAnnotatedClass"); + ClassGen cgen = new ClassGen(jc); + ConstantPoolGen cp = cgen.getConstantPool(); + cgen.addAnnotation(createCombinedAnnotation(cp)); + assertTrue("Should now have two annotations but has "+cgen.getAnnotations().length, + cgen.getAnnotations().length==2); + dumpClass(cgen,"SimpleAnnotatedClass.class"); + JavaClass jc2 = getClassFrom(".","SimpleAnnotatedClass"); + jc2.getAnnotations(); + assertTrue(wipe("SimpleAnnotatedClass.class")); + // System.err.println(jc2.toString()); + } + + + private void dumpClass(ClassGen cg, String fname) { + try { + File f = createTestdataFile(fname); + cg.getJavaClass().dump(f); + } catch (java.io.IOException e) { + System.err.println(e); + } + } + + + private void dumpClass(ClassGen cg, String dir, String fname) { + dumpClass(cg,dir+File.separator+fname); + } + + private void buildClassContentsWithAnnotatedMethods(ClassGen cg, ConstantPoolGen cp, InstructionList il) { + // Create method 'public static void main(String[]argv)' + MethodGen mg = createMethodGen("main",il,cp); + InstructionFactory factory = new InstructionFactory(cg); + mg.addAnnotation(createSimpleVisibleAnnotation(mg.getConstantPool())); + // We now define some often used types: + + ObjectType i_stream = new ObjectType("java.io.InputStream"); + ObjectType p_stream = new ObjectType("java.io.PrintStream"); + + // Create variables in and name : We call the constructors, i.e., + // execute BufferedReader(InputStreamReader(System.in)) . The reference + // to the BufferedReader object stays on top of the stack and is stored + // in the newly allocated in variable. + + il.append(factory.createNew("java.io.BufferedReader")); + il.append(InstructionConstants.DUP); // Use predefined constant + il.append(factory.createNew("java.io.InputStreamReader")); + il.append(InstructionConstants.DUP); + il.append(factory.createFieldAccess("java.lang.System", "in", i_stream,Constants.GETSTATIC)); + il.append(factory.createInvoke("java.io.InputStreamReader", "<init>", + Type.VOID, new Type[] { i_stream }, Constants.INVOKESPECIAL)); + il.append(factory.createInvoke("java.io.BufferedReader", "<init>", + Type.VOID, new Type[] { new ObjectType("java.io.Reader") }, + Constants.INVOKESPECIAL)); + + LocalVariableGen lg = mg.addLocalVariable("in", new ObjectType( + "java.io.BufferedReader"), null, null); + int in = lg.getIndex(); + lg.setStart(il.append(new ASTORE(in))); // "in" valid from here + + // Create local variable name and initialize it to null + + lg = mg.addLocalVariable("name", Type.STRING, null, null); + int name = lg.getIndex(); + il.append(InstructionConstants.ACONST_NULL); + lg.setStart(il.append(new ASTORE(name))); // "name" valid from here + + // Create try-catch block: We remember the start of the block, read a + // line from the standard input and store it into the variable name . + +// InstructionHandle try_start = il.append(factory.createFieldAccess( +// "java.lang.System", "out", p_stream, Constants.GETSTATIC)); + +// il.append(new PUSH(cp, "Please enter your name> ")); +// il.append(factory.createInvoke("java.io.PrintStream", "print", +// Type.VOID, new Type[] { Type.STRING }, +// Constants.INVOKEVIRTUAL)); +// il.append(new ALOAD(in)); +// il.append(factory.createInvoke("java.io.BufferedReader", "readLine", +// Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); + InstructionHandle try_start = il.append(new PUSH(cp,"Andy")); + il.append(new ASTORE(name)); + + // Upon normal execution we jump behind exception handler, the target + // address is not known yet. + + GOTO g = new GOTO(null); + InstructionHandle try_end = il.append(g); + + // We add the exception handler which simply returns from the method. + + LocalVariableGen var_ex = mg.addLocalVariable("ex",Type.getType("Ljava.io.IOException;"),null,null); + int var_ex_slot = var_ex.getIndex(); + + InstructionHandle handler = il.append(new ASTORE(var_ex_slot)); + var_ex.setStart(handler); + var_ex.setEnd(il.append(InstructionConstants.RETURN)); + + mg.addExceptionHandler(try_start, try_end, handler, + new ObjectType("java.io.IOException")); + + // "Normal" code continues, now we can set the branch target of the GOTO + // . + + InstructionHandle ih = il.append(factory.createFieldAccess( + "java.lang.System", "out", p_stream, Constants.GETSTATIC)); + g.setTarget(ih); + + // Printing "Hello": String concatenation compiles to StringBuffer + // operations. + + il.append(factory.createNew(Type.STRINGBUFFER)); + il.append(InstructionConstants.DUP); + il.append(new PUSH(cp, "Hello, ")); + il + .append(factory.createInvoke("java.lang.StringBuffer", + "<init>", Type.VOID, new Type[] { Type.STRING }, + Constants.INVOKESPECIAL)); + il.append(new ALOAD(name)); + il.append(factory.createInvoke("java.lang.StringBuffer", "append", + Type.STRINGBUFFER, new Type[] { Type.STRING }, + Constants.INVOKEVIRTUAL)); + il.append(factory.createInvoke("java.lang.StringBuffer", "toString", + Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); + + il.append(factory.createInvoke("java.io.PrintStream", "println", + Type.VOID, new Type[] { Type.STRING }, + Constants.INVOKEVIRTUAL)); + il.append(InstructionConstants.RETURN); + + // Finalization: Finally, we have to set the stack size, which normally + // would have to be computed on the fly and add a default constructor + // method to the class, which is empty in this case. + + mg.setMaxStack(); + mg.setMaxLocals(); + cg.addMethod(mg.getMethod()); + il.dispose(); // Allow instruction handles to be reused + cg.addEmptyConstructor(Constants.ACC_PUBLIC); + } + + private void buildClassContents(ClassGen cg, ConstantPoolGen cp, InstructionList il) { + // Create method 'public static void main(String[]argv)' + MethodGen mg = createMethodGen("main",il,cp); + InstructionFactory factory = new InstructionFactory(cg); + // We now define some often used types: + + ObjectType i_stream = new ObjectType("java.io.InputStream"); + ObjectType p_stream = new ObjectType("java.io.PrintStream"); + + // Create variables in and name : We call the constructors, i.e., + // execute BufferedReader(InputStreamReader(System.in)) . The reference + // to the BufferedReader object stays on top of the stack and is stored + // in the newly allocated in variable. + + il.append(factory.createNew("java.io.BufferedReader")); + il.append(InstructionConstants.DUP); // Use predefined constant + il.append(factory.createNew("java.io.InputStreamReader")); + il.append(InstructionConstants.DUP); + il.append(factory.createFieldAccess("java.lang.System", "in", i_stream,Constants.GETSTATIC)); + il.append(factory.createInvoke("java.io.InputStreamReader", "<init>", + Type.VOID, new Type[] { i_stream }, Constants.INVOKESPECIAL)); + il.append(factory.createInvoke("java.io.BufferedReader", "<init>", + Type.VOID, new Type[] { new ObjectType("java.io.Reader") }, + Constants.INVOKESPECIAL)); + + LocalVariableGen lg = mg.addLocalVariable("in", new ObjectType( + "java.io.BufferedReader"), null, null); + int in = lg.getIndex(); + lg.setStart(il.append(new ASTORE(in))); // "in" valid from here + + // Create local variable name and initialize it to null + + lg = mg.addLocalVariable("name", Type.STRING, null, null); + int name = lg.getIndex(); + il.append(InstructionConstants.ACONST_NULL); + lg.setStart(il.append(new ASTORE(name))); // "name" valid from here + + // Create try-catch block: We remember the start of the block, read a + // line from the standard input and store it into the variable name . + +// InstructionHandle try_start = il.append(factory.createFieldAccess( +// "java.lang.System", "out", p_stream, Constants.GETSTATIC)); + +// il.append(new PUSH(cp, "Please enter your name> ")); +// il.append(factory.createInvoke("java.io.PrintStream", "print", +// Type.VOID, new Type[] { Type.STRING }, +// Constants.INVOKEVIRTUAL)); +// il.append(new ALOAD(in)); +// il.append(factory.createInvoke("java.io.BufferedReader", "readLine", +// Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); + InstructionHandle try_start = il.append(new PUSH(cp,"Andy")); + il.append(new ASTORE(name)); + + // Upon normal execution we jump behind exception handler, the target + // address is not known yet. + + GOTO g = new GOTO(null); + InstructionHandle try_end = il.append(g); + + // We add the exception handler which simply returns from the method. + + LocalVariableGen var_ex = mg.addLocalVariable("ex",Type.getType("Ljava.io.IOException;"),null,null); + int var_ex_slot = var_ex.getIndex(); + + InstructionHandle handler = il.append(new ASTORE(var_ex_slot)); + var_ex.setStart(handler); + var_ex.setEnd(il.append(InstructionConstants.RETURN)); + + mg.addExceptionHandler(try_start, try_end, handler, + new ObjectType("java.io.IOException")); + + // "Normal" code continues, now we can set the branch target of the GOTO + // . + + InstructionHandle ih = il.append(factory.createFieldAccess( + "java.lang.System", "out", p_stream, Constants.GETSTATIC)); + g.setTarget(ih); + + // Printing "Hello": String concatenation compiles to StringBuffer + // operations. + + il.append(factory.createNew(Type.STRINGBUFFER)); + il.append(InstructionConstants.DUP); + il.append(new PUSH(cp, "Hello, ")); + il + .append(factory.createInvoke("java.lang.StringBuffer", + "<init>", Type.VOID, new Type[] { Type.STRING }, + Constants.INVOKESPECIAL)); + il.append(new ALOAD(name)); + il.append(factory.createInvoke("java.lang.StringBuffer", "append", + Type.STRINGBUFFER, new Type[] { Type.STRING }, + Constants.INVOKEVIRTUAL)); + il.append(factory.createInvoke("java.lang.StringBuffer", "toString", + Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); + + il.append(factory.createInvoke("java.io.PrintStream", "println", + Type.VOID, new Type[] { Type.STRING }, + Constants.INVOKEVIRTUAL)); + il.append(InstructionConstants.RETURN); + + // Finalization: Finally, we have to set the stack size, which normally + // would have to be computed on the fly and add a default constructor + // method to the class, which is empty in this case. + + mg.setMaxStack(); + mg.setMaxLocals(); + cg.addMethod(mg.getMethod()); + il.dispose(); // Allow instruction handles to be reused + cg.addEmptyConstructor(Constants.ACC_PUBLIC); + } + + private JavaClass getClassFrom(String where,String clazzname) throws ClassNotFoundException { + SyntheticRepository repos = createRepos(where); + return repos.loadClass(clazzname); + } + + + + + // helper methods + + + private ClassGen createClassGen(String classname) { + return new ClassGen(classname, "java.lang.Object", + "<generated>", Constants.ACC_PUBLIC | Constants.ACC_SUPER, null); + } + + private MethodGen createMethodGen(String methodname,InstructionList il,ConstantPoolGen cp) { + return new MethodGen( + Constants.ACC_STATIC | Constants.ACC_PUBLIC, // access flags + Type.VOID, // return type + new Type[] { new ArrayType(Type.STRING, 1) }, // argument types + new String[] { "argv" }, // arg names + methodname, "HelloWorld", // method, class + il, cp); + } + + + public AnnotationGen createSimpleVisibleAnnotation(ConstantPoolGen cp) { + SimpleElementValueGen evg = new SimpleElementValueGen( + ElementValueGen.PRIMITIVE_INT, cp, 4); + + ElementNameValuePairGen nvGen = new ElementNameValuePairGen("id", evg,cp); + + ObjectType t = new ObjectType("SimpleAnnotation"); + + List elements = new ArrayList(); + elements.add(nvGen); + + AnnotationGen a = new AnnotationGen(t, elements,true, cp); + return a; + } + + public AnnotationGen createFruitAnnotation(ConstantPoolGen cp,String aFruit) { + SimpleElementValueGen evg = new SimpleElementValueGen(ElementValueGen.STRING,cp,aFruit); + ElementNameValuePairGen nvGen = new ElementNameValuePairGen("fruit",evg,cp); + ObjectType t = new ObjectType("SimpleStringAnnotation"); + List elements = new ArrayList(); + elements.add(nvGen); + return new AnnotationGen(t,elements,true,cp); + } + + public AnnotationGen createCombinedAnnotation(ConstantPoolGen cp) { + // Create an annotation instance + AnnotationGen a = createSimpleVisibleAnnotation(cp); + ArrayElementValueGen array = new ArrayElementValueGen(cp); + array.addElement(new AnnotationElementValueGen(a,cp)); + ElementNameValuePairGen nvp = new ElementNameValuePairGen("value",array,cp); + List elements = new ArrayList(); + elements.add(nvp); + return new AnnotationGen(new ObjectType("CombinedAnnotation"),elements,true,cp); + } + + public AnnotationGen createSimpleInvisibleAnnotation(ConstantPoolGen cp) { + SimpleElementValueGen evg = new SimpleElementValueGen( + ElementValueGen.PRIMITIVE_INT, cp, 4); + + ElementNameValuePairGen nvGen = new ElementNameValuePairGen("id", evg,cp); + + ObjectType t = new ObjectType("SimpleAnnotation"); + + List elements = new ArrayList(); + elements.add(nvGen); + + AnnotationGen a = new AnnotationGen(t, elements,false, cp); + return a; + } + protected void tearDown() throws Exception { + super.tearDown(); + } + +}
\ No newline at end of file diff --git a/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/LocalVariableTypeTableTest.java b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/LocalVariableTypeTableTest.java new file mode 100644 index 000000000..914085149 --- /dev/null +++ b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/LocalVariableTypeTableTest.java @@ -0,0 +1,72 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation + * ******************************************************************/ + +package org.aspectj.apache.bcel.classfile.tests; + +import org.aspectj.apache.bcel.classfile.Code; +import org.aspectj.apache.bcel.classfile.JavaClass; +import org.aspectj.apache.bcel.classfile.LocalVariable; +import org.aspectj.apache.bcel.classfile.LocalVariableTypeTable; +import org.aspectj.apache.bcel.classfile.Method; +import org.aspectj.apache.bcel.classfile.Utility; + + +public class LocalVariableTypeTableTest extends BcelTestCase { + + + protected void setUp() throws Exception { + super.setUp(); + } + + /** + * Check the local variable type table includes information about generic signatures. + */ + public void testLocalVariableTypeTableAttribute() throws ClassNotFoundException { + JavaClass clazz = getClassFromJar("SimpleGenericsProgram"); + + Method mainMethod = getMethod(clazz,"main"); + Code codeAttr = (Code) findAttribute("Code",mainMethod.getAttributes()); + LocalVariableTypeTable localVariableTypeTable = + (LocalVariableTypeTable) findAttribute("LocalVariableTypeTable",codeAttr.getAttributes()); + + assertTrue("Should be two entries in the LocalVariableTypeTable but found "+localVariableTypeTable.getTableLength(), + localVariableTypeTable.getTableLength()==2); + + LocalVariable[] lvtable = localVariableTypeTable.getLocalVariableTypeTable(); + boolean tc1OK = false; + boolean tc2OK = false; + String errormessage = null; + for (int i = 0; i < lvtable.length; i++) { + String sig = Utility.signatureToString(lvtable[i].getSignature()); + if (lvtable[i].getName().equals("tc1")) { + if (!sig.equals("TreasureChest<String>")) { + errormessage="Expected signature of 'TreasureChest<String>' for tc1 but got "+sig; + } else { + tc1OK = true; + } + } + if (lvtable[i].getName().equals("tc2")) { + if (!sig.equals("TreasureChest<Integer>")) { + errormessage="Expected signature of 'TreasureChest<Integer>' for tc2 but got "+sig; + } else { + tc2OK = true; + } + } + } + if (!tc1OK || !tc2OK) fail(errormessage); + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + +} diff --git a/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/MethodAnnotationsTest.java b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/MethodAnnotationsTest.java new file mode 100644 index 000000000..5740add02 --- /dev/null +++ b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/MethodAnnotationsTest.java @@ -0,0 +1,108 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation + * ******************************************************************/ + +package org.aspectj.apache.bcel.classfile.tests; + +import java.io.File; +import java.io.IOException; +import java.util.Iterator; + +import org.aspectj.apache.bcel.classfile.JavaClass; +import org.aspectj.apache.bcel.classfile.Method; +import org.aspectj.apache.bcel.classfile.annotation.Annotation; +import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePair; +import org.aspectj.apache.bcel.util.SyntheticRepository; + + +public class MethodAnnotationsTest extends BcelTestCase { + + + protected void setUp() throws Exception { + super.setUp(); + } + + + public void testMethodAnnotations() throws ClassNotFoundException { + JavaClass clazz = getClassFromJar("AnnotatedMethods"); + + checkAnnotatedMethod(clazz,"method1","SimpleAnnotation","id","1"); + checkAnnotatedMethod(clazz,"method2","SimpleAnnotation","id","2"); + + } + + public void testMethodAnnotationsReadWrite() throws ClassNotFoundException,IOException { + JavaClass clazz = getClassFromJar("AnnotatedMethods"); + + checkAnnotatedMethod(clazz,"method1","SimpleAnnotation","id","1"); + checkAnnotatedMethod(clazz,"method2","SimpleAnnotation","id","2"); + + // Write it out + File tfile = createTestdataFile("AnnotatedMethods.class"); + clazz.dump(tfile); + + SyntheticRepository repos2 = createRepos("."); + JavaClass clazz2 = repos2.loadClass("AnnotatedMethods"); + + checkAnnotatedMethod(clazz,"method1","SimpleAnnotation","id","1"); + checkAnnotatedMethod(clazz,"method2","SimpleAnnotation","id","2"); + + assertTrue(tfile.delete()); + } + + // helper methods + + public void checkAnnotatedMethod(JavaClass clazz,String methodname, + String annotationName,String annotationElementName,String annotationElementValue) { + Method[] methods = clazz.getMethods(); + + for (int i = 0; i < methods.length; i++) { + Method m = methods[i]; + Annotation[] methodAnnotations = m.getAnnotations(); + if (m.getName().equals(methodname)) { + checkAnnotation(methodAnnotations[0],annotationName,annotationElementName,annotationElementValue); + + } + } + } + + private void checkAnnotation(Annotation a,String name,String elementname,String elementvalue) { + assertTrue("Expected annotation to have name "+name+" but it had name "+a.getTypeName(), + a.getTypeName().equals(name)); + assertTrue("Expected annotation to have one element but it had "+a.getValues().size(),a.getValues().size()==1); + ElementNameValuePair envp = (ElementNameValuePair)a.getValues().get(0); + assertTrue("Expected element name "+elementname+" but was "+envp.getNameString(), + elementname.equals(envp.getNameString())); + assertTrue("Expected element value "+elementvalue+" but was "+envp.getValue().stringifyValue(), + elementvalue.equals(envp.getValue().stringifyValue())); + } + + + // helper methods + + public void checkValue(Annotation a,String name,String tostring) { + for (Iterator i = a.getValues().iterator(); i.hasNext();) { + ElementNameValuePair element = (ElementNameValuePair) i.next(); + if (element.getNameString().equals(name)) { + if (!element.getValue().stringifyValue().equals(tostring)) { + fail("Expected element "+name+" to have value "+tostring+" but it had value "+element.getValue().stringifyValue()); + } + return; + } + } + fail("Didnt find named element "+name); + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + +} diff --git a/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/ParameterAnnotationsTest.java b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/ParameterAnnotationsTest.java new file mode 100644 index 000000000..8d4576284 --- /dev/null +++ b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/ParameterAnnotationsTest.java @@ -0,0 +1,593 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM All rights reserved. This program and the accompanying + * materials are made available under the terms of the Common Public License + * v1.0 which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: Andy Clement - initial implementation + ******************************************************************************/ + +package org.aspectj.apache.bcel.classfile.tests; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.aspectj.apache.bcel.Constants; +import org.aspectj.apache.bcel.classfile.Attribute; +import org.aspectj.apache.bcel.classfile.JavaClass; +import org.aspectj.apache.bcel.classfile.Method; +import org.aspectj.apache.bcel.classfile.annotation.Annotation; +import org.aspectj.apache.bcel.generic.ALOAD; +import org.aspectj.apache.bcel.generic.ASTORE; +import org.aspectj.apache.bcel.generic.ArrayType; +import org.aspectj.apache.bcel.generic.ClassGen; +import org.aspectj.apache.bcel.generic.ConstantPoolGen; +import org.aspectj.apache.bcel.generic.GOTO; +import org.aspectj.apache.bcel.generic.InstructionConstants; +import org.aspectj.apache.bcel.generic.InstructionFactory; +import org.aspectj.apache.bcel.generic.InstructionHandle; +import org.aspectj.apache.bcel.generic.InstructionList; +import org.aspectj.apache.bcel.generic.LocalVariableGen; +import org.aspectj.apache.bcel.generic.MethodGen; +import org.aspectj.apache.bcel.generic.ObjectType; +import org.aspectj.apache.bcel.generic.PUSH; +import org.aspectj.apache.bcel.generic.Type; +import org.aspectj.apache.bcel.generic.annotation.AnnotationElementValueGen; +import org.aspectj.apache.bcel.generic.annotation.AnnotationGen; +import org.aspectj.apache.bcel.generic.annotation.ArrayElementValueGen; +import org.aspectj.apache.bcel.generic.annotation.ElementNameValuePairGen; +import org.aspectj.apache.bcel.generic.annotation.ElementValueGen; +import org.aspectj.apache.bcel.generic.annotation.SimpleElementValueGen; +import org.aspectj.apache.bcel.util.SyntheticRepository; + +/** + * The program that some of the tests generate looks like this: + public class HelloWorld { + public static void main(String[] argv) { + BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + String name = null; + try { + name = "Andy"; + } catch(IOException e) { return; } + System.out.println("Hello, " + name); + } + } + * + */ +public class ParameterAnnotationsTest extends BcelTestCase { + + protected void setUp() throws Exception { + super.setUp(); + } + + /** + * Programmatically construct a class and add an annotation to the main method parameter 'argv' + */ + public void testParameterAnnotations_builtOK() { + ClassGen clg = createClassGen("HelloWorld"); + ConstantPoolGen cpg = clg.getConstantPool(); + InstructionList il = new InstructionList(); + + buildClassContentsWithAnnotatedMethods(clg,cpg,il,true); + + int i = clg.getMethods().length; + assertTrue("Class should have 2 methods but has "+i,i==2); + + Method mainMethod = clg.getMethods()[0]; + Annotation[] annos = mainMethod.getAnnotationsOnParameter(0); + assertTrue("Should be two annotation on the 'argv' parameter to main() but there are "+annos.length,annos.length==2); + assertTrue("This annotation should contain the string 'fruit=Apples' but it is "+annos[0].toString(), + annos[0].toString().indexOf("fruit=Apples")!=-1); + assertTrue("This annotation should contain the string 'fruit=Oranges' but it is "+annos[1].toString(), + annos[1].toString().indexOf("fruit=Oranges")!=-1); + } + + + + /** + * Check we can save and load a constructed class that contains parameter annotations + */ + public void testParameterAnnotations_savedAndLoadedOK() throws ClassNotFoundException { + ClassGen clg = createClassGen("HelloWorld"); + ConstantPoolGen cpg = clg.getConstantPool(); + InstructionList il = new InstructionList(); + + buildClassContentsWithAnnotatedMethods(clg,cpg,il,true); + + dumpClass(clg,"temp5","HelloWorld.class"); + + JavaClass jc = getClassFrom("temp5","HelloWorld"); + + clg = new ClassGen(jc); + + int i = clg.getMethods().length; + assertTrue("Class should have 2 methods but has "+i,i==2); + + Method mainMethod = clg.getMethods()[0]; + Annotation[] annos = mainMethod.getAnnotationsOnParameter(0); + assertTrue("Should be two annotation on the 'argv' parameter to main() but there are "+annos.length,annos.length==2); + assertTrue("This annotation should contain the string 'fruit=Apples' but it is "+annos[0].toString(), + annos[0].toString().indexOf("fruit=Apples")!=-1); + assertTrue("This annotation should contain the string 'fruit=Oranges' but it is "+annos[1].toString(), + annos[1].toString().indexOf("fruit=Oranges")!=-1); + assertTrue(wipe("temp5","HelloWorld.class")); + + } + + + + /* + * Load an existing class, add new parameter annotations, save and then reload it + */ + public void testParameterAnnotations_loadedThenModifiedThenSavedAndLoadedOK() throws ClassNotFoundException { + JavaClass jc = getClassFrom("testcode.jar","AnnotatedParameters"); + + ClassGen clg = new ClassGen(jc); + ConstantPoolGen cpg = clg.getConstantPool(); + + // + // Foo method looks like this: + // public void foo(@SimpleAnnotation(id=2) int arg1, + // @SimpleAnnotation(id=3) @AnnotationEnumElement(enumval=SimpleEnum.Red) String arg2) + Method m = findMethod(clg,"foo"); + assertTrue("Should be able to find method foo but couldn't",m!=null); + + + /////////////////////// 1. Check the right number of annotations are there + int i = m.getAnnotationsOnParameter(1).length; + assertTrue("Should be two annotations on the second parameter but found: "+i,i==2); + + + /////////////////////// 2. Let's add a new parameter annotation, a visible one, to the first parameter. + + // Build a modifiable version of the foo method + MethodGen mg = new MethodGen(m,clg.getClassName(),cpg); + + // Check the annotations survived that transform + i = mg.getAnnotationsOnParameter(1).size(); + assertTrue("Should be two annotations on the second parameter but found: "+i,i==2); + + // That worked, so let's add a new parameter annotation + mg.addParameterAnnotation(0,createFruitAnnotation(cpg,"Banana",true)); + + // Foo method should now look like this: + // public void foo(@SimpleAnnotation(id=2) @SimpleStringAnnotation(fruit=Banana) int arg1, + // @SimpleAnnotation(id=3) @AnnotationEnumElement(enumval=SimpleEnum.Red) String arg2) + i = mg.getAnnotationsOnParameter(0).size(); + assertTrue("Should now be 2 parameter annotations but found "+i,i==2); + i = mg.getAnnotationsOnParameter(0).get(1).toString().indexOf("fruit=Banana"); + assertTrue("Expected 'fruit=Banana' in the 2nd annotation on the first argument but got "+ + mg.getAnnotationsOnParameter(0).get(1).toString(),i!=-1); + + // delete the old method and add the new one + clg.removeMethod(m); + clg.addMethod(mg.getMethod()); + + /////////////////////// 3. Dump it to disk + dumpClass(clg,"temp2","AnnotatedParameters.class"); + + /////////////////////// 4. Load it back in and verify the annotations persisted + JavaClass jc2 = getClassFrom("temp2","AnnotatedParameters"); + + m = jc2.getMethods()[2]; + Annotation[] p1annotations = m.getAnnotationsOnParameter(0); + Annotation[] p2annotations = m.getAnnotationsOnParameter(1); + + assertTrue("Expected two annotations on the first parameter but found "+p1annotations.length,p1annotations.length==2); + assertTrue("Expected two annotations on the second parameter but found "+p2annotations.length,p2annotations.length==2); + String expectedString = "[@SimpleAnnotation(id=2),@SimpleStringAnnotation(fruit=Banana)]"; + assertTrue("Expected formatted short string of '"+expectedString+"' but it was '"+dumpAnnotations(p1annotations)+"'", + dumpAnnotations(p1annotations).equals(expectedString)); + expectedString = "[@SimpleAnnotation(id=3),@AnnotationEnumElement(enumval=Red)]"; + assertTrue("Expected formatted short string of '"+expectedString+"' but it was '"+dumpAnnotations(p2annotations)+"'", + dumpAnnotations(p2annotations).equals(expectedString)); + + assertTrue(wipe("temp2","AnnotatedParameters.class")); + } + + + /** + * same as above test but attaching invisible runtime parameter annotations + */ + public void testParameterAnnotations_loadedThenModifiedWithInvisibleAnnotationThenSavedAndLoadedOK() throws ClassNotFoundException { + JavaClass jc = getClassFrom("testcode.jar","AnnotatedParameters"); + ClassGen clg = new ClassGen(jc); + ConstantPoolGen cpg = clg.getConstantPool(); + + // + // Foo method looks like this: + // public void foo(@SimpleAnnotation(id=2) int arg1, + // @SimpleAnnotation(id=3) @AnnotationEnumElement(enumval=SimpleEnum.Red) String arg2) + Method m = findMethod(clg,"foo"); + assertTrue("Should be able to find method foo but couldn't",m!=null); + + + /////////////////////// 1. Check the right number of annotations are there + int i = m.getAnnotationsOnParameter(1).length; + assertTrue("Should be two annotations on the second parameter but found: "+i,i==2); + + + /////////////////////// 2. Let's add a new parameter annotation, a visible one, to the first parameter. + + // Build a modifiable version of the foo method + MethodGen mg = new MethodGen(m,clg.getClassName(),cpg); + + // Check the annotations survived that transform + i = mg.getAnnotationsOnParameter(1).size(); + assertTrue("Should be two annotations on the second parameter but found: "+i,i==2); + + // That worked, so let's add a new parameter annotation + mg.addParameterAnnotation(0,createFruitAnnotation(cpg,"Banana",false)); + + // Foo method should now look like this: + // public void foo(@SimpleAnnotation(id=2) @SimpleStringAnnotation(fruit=Banana) int arg1, + // @SimpleAnnotation(id=3) @AnnotationEnumElement(enumval=SimpleEnum.Red) String arg2) + i = mg.getAnnotationsOnParameter(0).size(); + assertTrue("Should now be 2 parameter annotations but found "+i,i==2); + i = mg.getAnnotationsOnParameter(0).get(1).toString().indexOf("fruit=Banana"); + assertTrue("Expected 'fruit=Banana' in the 2nd annotation on the first argument but got "+ + mg.getAnnotationsOnParameter(0).get(1).toString(),i!=-1); + assertTrue("New annotation should be runtime invisible?",!((AnnotationGen)mg.getAnnotationsOnParameter(0).get(1)).isRuntimeVisible()); + + // delete the old method and add the new one + clg.removeMethod(m); + clg.addMethod(mg.getMethod()); + + /////////////////////// 3. Dump it to disk + dumpClass(clg,"temp3","AnnotatedParameters.class"); + + /////////////////////// 4. Load it back in and verify the annotations persisted + + JavaClass jc2 = getClassFrom("temp3","AnnotatedParameters"); + + m = jc2.getMethods()[2]; + Annotation[] p1annotations = m.getAnnotationsOnParameter(0); + Annotation[] p2annotations = m.getAnnotationsOnParameter(1); + + assertTrue("Expected two annotations on the first parameter but found "+p1annotations.length,p1annotations.length==2); + assertTrue("Expected two annotations on the second parameter but found "+p2annotations.length,p2annotations.length==2); + String expectedString = "[@SimpleAnnotation(id=2),@SimpleStringAnnotation(fruit=Banana)]"; + assertTrue("Expected formatted short string of '"+expectedString+"' but it was '"+dumpAnnotations(p1annotations)+"'", + dumpAnnotations(p1annotations).equals(expectedString)); + expectedString = "[@SimpleAnnotation(id=3),@AnnotationEnumElement(enumval=Red)]"; + assertTrue("Expected formatted short string of '"+expectedString+"' but it was '"+dumpAnnotations(p2annotations)+"'", + dumpAnnotations(p2annotations).equals(expectedString)); + + assertTrue("Second annotation on first parameter should be runtime invisible?", + !p1annotations[1].isRuntimeVisible()); + assertTrue(wipe("temp3","AnnotatedParameters.class")); + + + // 5. Verify that when annotations for parameters are unpacked from attributes, the + // attributes vanish ! + clg = new ClassGen(jc2); + mg = new MethodGen(m,clg.getClassName(),clg.getConstantPool()); + Attribute[] as = mg.getAttributes(); + assertTrue("Should be 2 (RIPA and RVPA) but there are "+mg.getAttributes().length,mg.getAttributes().length==2); + List l = mg.getAnnotationsOnParameter(0); + assertTrue("Should be 2 annotations on first parameter but there is only "+l.size()+":"+l.toString(), + l.size()==2); + assertTrue("Should be 0 but there are "+mg.getAttributes().length,mg.getAttributes().length==0); + } + + + private Method findMethod(ClassGen c,String mname) { + Method[] ms = c.getMethods(); + for (int i = 0; i < ms.length; i++) { + if (ms[i].getName().equals(mname)) return ms[i]; + } + return null; + } + + private void dumpClass(ClassGen cg, String fname) { + try { + File f = createTestdataFile(fname); + cg.getJavaClass().dump(f); + } catch (java.io.IOException e) { + System.err.println(e); + } + } + + + private void dumpClass(ClassGen cg, String dir, String fname) { + dumpClass(cg,dir+File.separator+fname); + } + + private void buildClassContentsWithAnnotatedMethods(ClassGen cg, ConstantPoolGen cp, InstructionList il,boolean addParameterAnnotations) { + // Create method 'public static void main(String[]argv)' + MethodGen mg = createMethodGen("main",il,cp); + InstructionFactory factory = new InstructionFactory(cg); + mg.addAnnotation(createSimpleVisibleAnnotation(mg.getConstantPool())); + // We now define some often used types: + + ObjectType i_stream = new ObjectType("java.io.InputStream"); + ObjectType p_stream = new ObjectType("java.io.PrintStream"); + + // Create variables in and name : We call the constructors, i.e., + // execute BufferedReader(InputStreamReader(System.in)) . The reference + // to the BufferedReader object stays on top of the stack and is stored + // in the newly allocated in variable. + + il.append(factory.createNew("java.io.BufferedReader")); + il.append(InstructionConstants.DUP); // Use predefined constant + il.append(factory.createNew("java.io.InputStreamReader")); + il.append(InstructionConstants.DUP); + il.append(factory.createFieldAccess("java.lang.System", "in", i_stream,Constants.GETSTATIC)); + il.append(factory.createInvoke("java.io.InputStreamReader", "<init>", + Type.VOID, new Type[] { i_stream }, Constants.INVOKESPECIAL)); + il.append(factory.createInvoke("java.io.BufferedReader", "<init>", + Type.VOID, new Type[] { new ObjectType("java.io.Reader") }, + Constants.INVOKESPECIAL)); + + LocalVariableGen lg = mg.addLocalVariable("in", new ObjectType( + "java.io.BufferedReader"), null, null); + int in = lg.getIndex(); + lg.setStart(il.append(new ASTORE(in))); // "in" valid from here + + // Create local variable name and initialize it to null + + lg = mg.addLocalVariable("name", Type.STRING, null, null); + int name = lg.getIndex(); + il.append(InstructionConstants.ACONST_NULL); + lg.setStart(il.append(new ASTORE(name))); // "name" valid from here + + // Create try-catch block: We remember the start of the block, read a + // line from the standard input and store it into the variable name . + +// InstructionHandle try_start = il.append(factory.createFieldAccess( +// "java.lang.System", "out", p_stream, Constants.GETSTATIC)); + +// il.append(new PUSH(cp, "Please enter your name> ")); +// il.append(factory.createInvoke("java.io.PrintStream", "print", +// Type.VOID, new Type[] { Type.STRING }, +// Constants.INVOKEVIRTUAL)); +// il.append(new ALOAD(in)); +// il.append(factory.createInvoke("java.io.BufferedReader", "readLine", +// Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); + InstructionHandle try_start = il.append(new PUSH(cp,"Andy")); + il.append(new ASTORE(name)); + + // Upon normal execution we jump behind exception handler, the target + // address is not known yet. + + GOTO g = new GOTO(null); + InstructionHandle try_end = il.append(g); + + // We add the exception handler which simply returns from the method. + + LocalVariableGen var_ex = mg.addLocalVariable("ex",Type.getType("Ljava.io.IOException;"),null,null); + int var_ex_slot = var_ex.getIndex(); + + InstructionHandle handler = il.append(new ASTORE(var_ex_slot)); + var_ex.setStart(handler); + var_ex.setEnd(il.append(InstructionConstants.RETURN)); + + mg.addExceptionHandler(try_start, try_end, handler, + new ObjectType("java.io.IOException")); + + // "Normal" code continues, now we can set the branch target of the GOTO + // . + + InstructionHandle ih = il.append(factory.createFieldAccess( + "java.lang.System", "out", p_stream, Constants.GETSTATIC)); + g.setTarget(ih); + + // Printing "Hello": String concatenation compiles to StringBuffer + // operations. + + il.append(factory.createNew(Type.STRINGBUFFER)); + il.append(InstructionConstants.DUP); + il.append(new PUSH(cp, "Hello, ")); + il + .append(factory.createInvoke("java.lang.StringBuffer", + "<init>", Type.VOID, new Type[] { Type.STRING }, + Constants.INVOKESPECIAL)); + il.append(new ALOAD(name)); + il.append(factory.createInvoke("java.lang.StringBuffer", "append", + Type.STRINGBUFFER, new Type[] { Type.STRING }, + Constants.INVOKEVIRTUAL)); + il.append(factory.createInvoke("java.lang.StringBuffer", "toString", + Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); + + il.append(factory.createInvoke("java.io.PrintStream", "println", + Type.VOID, new Type[] { Type.STRING }, + Constants.INVOKEVIRTUAL)); + il.append(InstructionConstants.RETURN); + + // Finalization: Finally, we have to set the stack size, which normally + // would have to be computed on the fly and add a default constructor + // method to the class, which is empty in this case. + + mg.addParameterAnnotation(0,createFruitAnnotation(cp,"Apples",true)); + mg.addParameterAnnotation(0,createFruitAnnotation(cp,"Oranges",true)); + mg.setMaxStack(); + mg.setMaxLocals(); + cg.addMethod(mg.getMethod()); + il.dispose(); // Allow instruction handles to be reused + cg.addEmptyConstructor(Constants.ACC_PUBLIC); + } + + private void buildClassContents(ClassGen cg, ConstantPoolGen cp, InstructionList il) { + // Create method 'public static void main(String[]argv)' + MethodGen mg = createMethodGen("main",il,cp); + InstructionFactory factory = new InstructionFactory(cg); + // We now define some often used types: + + ObjectType i_stream = new ObjectType("java.io.InputStream"); + ObjectType p_stream = new ObjectType("java.io.PrintStream"); + + // Create variables in and name : We call the constructors, i.e., + // execute BufferedReader(InputStreamReader(System.in)) . The reference + // to the BufferedReader object stays on top of the stack and is stored + // in the newly allocated in variable. + + il.append(factory.createNew("java.io.BufferedReader")); + il.append(InstructionConstants.DUP); // Use predefined constant + il.append(factory.createNew("java.io.InputStreamReader")); + il.append(InstructionConstants.DUP); + il.append(factory.createFieldAccess("java.lang.System", "in", i_stream,Constants.GETSTATIC)); + il.append(factory.createInvoke("java.io.InputStreamReader", "<init>", + Type.VOID, new Type[] { i_stream }, Constants.INVOKESPECIAL)); + il.append(factory.createInvoke("java.io.BufferedReader", "<init>", + Type.VOID, new Type[] { new ObjectType("java.io.Reader") }, + Constants.INVOKESPECIAL)); + + LocalVariableGen lg = mg.addLocalVariable("in", new ObjectType( + "java.io.BufferedReader"), null, null); + int in = lg.getIndex(); + lg.setStart(il.append(new ASTORE(in))); // "in" valid from here + + // Create local variable name and initialize it to null + + lg = mg.addLocalVariable("name", Type.STRING, null, null); + int name = lg.getIndex(); + il.append(InstructionConstants.ACONST_NULL); + lg.setStart(il.append(new ASTORE(name))); // "name" valid from here + + // Create try-catch block: We remember the start of the block, read a + // line from the standard input and store it into the variable name . + +// InstructionHandle try_start = il.append(factory.createFieldAccess( +// "java.lang.System", "out", p_stream, Constants.GETSTATIC)); + +// il.append(new PUSH(cp, "Please enter your name> ")); +// il.append(factory.createInvoke("java.io.PrintStream", "print", +// Type.VOID, new Type[] { Type.STRING }, +// Constants.INVOKEVIRTUAL)); +// il.append(new ALOAD(in)); +// il.append(factory.createInvoke("java.io.BufferedReader", "readLine", +// Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); + InstructionHandle try_start = il.append(new PUSH(cp,"Andy")); + il.append(new ASTORE(name)); + + // Upon normal execution we jump behind exception handler, the target + // address is not known yet. + + GOTO g = new GOTO(null); + InstructionHandle try_end = il.append(g); + + // We add the exception handler which simply returns from the method. + + LocalVariableGen var_ex = mg.addLocalVariable("ex",Type.getType("Ljava.io.IOException;"),null,null); + int var_ex_slot = var_ex.getIndex(); + + InstructionHandle handler = il.append(new ASTORE(var_ex_slot)); + var_ex.setStart(handler); + var_ex.setEnd(il.append(InstructionConstants.RETURN)); + + mg.addExceptionHandler(try_start, try_end, handler, + new ObjectType("java.io.IOException")); + + // "Normal" code continues, now we can set the branch target of the GOTO + // . + + InstructionHandle ih = il.append(factory.createFieldAccess( + "java.lang.System", "out", p_stream, Constants.GETSTATIC)); + g.setTarget(ih); + + // Printing "Hello": String concatenation compiles to StringBuffer + // operations. + + il.append(factory.createNew(Type.STRINGBUFFER)); + il.append(InstructionConstants.DUP); + il.append(new PUSH(cp, "Hello, ")); + il + .append(factory.createInvoke("java.lang.StringBuffer", + "<init>", Type.VOID, new Type[] { Type.STRING }, + Constants.INVOKESPECIAL)); + il.append(new ALOAD(name)); + il.append(factory.createInvoke("java.lang.StringBuffer", "append", + Type.STRINGBUFFER, new Type[] { Type.STRING }, + Constants.INVOKEVIRTUAL)); + il.append(factory.createInvoke("java.lang.StringBuffer", "toString", + Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); + + il.append(factory.createInvoke("java.io.PrintStream", "println", + Type.VOID, new Type[] { Type.STRING }, + Constants.INVOKEVIRTUAL)); + il.append(InstructionConstants.RETURN); + + // Finalization: Finally, we have to set the stack size, which normally + // would have to be computed on the fly and add a default constructor + // method to the class, which is empty in this case. + + mg.setMaxStack(); + mg.setMaxLocals(); + cg.addMethod(mg.getMethod()); + il.dispose(); // Allow instruction handles to be reused + cg.addEmptyConstructor(Constants.ACC_PUBLIC); + } + + private JavaClass getClassFrom(String where,String clazzname) throws ClassNotFoundException { + SyntheticRepository repos = createRepos(where); + return repos.loadClass(clazzname); + } + + + + + // helper methods + + + private ClassGen createClassGen(String classname) { + return new ClassGen(classname, "java.lang.Object", + "<generated>", Constants.ACC_PUBLIC | Constants.ACC_SUPER, null); + } + + private MethodGen createMethodGen(String methodname,InstructionList il,ConstantPoolGen cp) { + return new MethodGen( + Constants.ACC_STATIC | Constants.ACC_PUBLIC, // access flags + Type.VOID, // return type + new Type[] { new ArrayType(Type.STRING, 1) }, // argument types + new String[] { "argv" }, // arg names + methodname, "HelloWorld", // method, class + il, cp); + } + + + public AnnotationGen createSimpleVisibleAnnotation(ConstantPoolGen cp) { + SimpleElementValueGen evg = new SimpleElementValueGen( + ElementValueGen.PRIMITIVE_INT, cp, 4); + + ElementNameValuePairGen nvGen = new ElementNameValuePairGen("id", evg,cp); + + ObjectType t = new ObjectType("SimpleAnnotation"); + + List elements = new ArrayList(); + elements.add(nvGen); + + AnnotationGen a = new AnnotationGen(t, elements,true, cp); + return a; + } + + public AnnotationGen createCombinedAnnotation(ConstantPoolGen cp) { + // Create an annotation instance + AnnotationGen a = createSimpleVisibleAnnotation(cp); + ArrayElementValueGen array = new ArrayElementValueGen(cp); + array.addElement(new AnnotationElementValueGen(a,cp)); + ElementNameValuePairGen nvp = new ElementNameValuePairGen("value",array,cp); + List elements = new ArrayList(); + elements.add(nvp); + return new AnnotationGen(new ObjectType("CombinedAnnotation"),elements,true,cp); + } + + public AnnotationGen createSimpleInvisibleAnnotation(ConstantPoolGen cp) { + SimpleElementValueGen evg = new SimpleElementValueGen( + ElementValueGen.PRIMITIVE_INT, cp, 4); + + ElementNameValuePairGen nvGen = new ElementNameValuePairGen("id", evg,cp); + + ObjectType t = new ObjectType("SimpleAnnotation"); + + List elements = new ArrayList(); + elements.add(nvGen); + + AnnotationGen a = new AnnotationGen(t, elements,false, cp); + return a; + } + protected void tearDown() throws Exception { + super.tearDown(); + } + +}
\ No newline at end of file diff --git a/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/RuntimeVisibleAnnotationAttributeTest.java b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/RuntimeVisibleAnnotationAttributeTest.java new file mode 100644 index 000000000..129dbddbe --- /dev/null +++ b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/RuntimeVisibleAnnotationAttributeTest.java @@ -0,0 +1,373 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation + * ******************************************************************/ + +package org.aspectj.apache.bcel.classfile.tests; + +import java.io.File; +import java.io.IOException; +import java.util.Iterator; +import java.util.List; + +import org.aspectj.apache.bcel.classfile.Attribute; +import org.aspectj.apache.bcel.classfile.ConstantPool; +import org.aspectj.apache.bcel.classfile.JavaClass; +import org.aspectj.apache.bcel.classfile.Utility; +import org.aspectj.apache.bcel.classfile.annotation.Annotation; +import org.aspectj.apache.bcel.classfile.annotation.AnnotationElementValue; +import org.aspectj.apache.bcel.classfile.annotation.ArrayElementValue; +import org.aspectj.apache.bcel.classfile.annotation.ClassElementValue; +import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePair; +import org.aspectj.apache.bcel.classfile.annotation.ElementValue; +import org.aspectj.apache.bcel.classfile.annotation.EnumElementValue; +import org.aspectj.apache.bcel.classfile.annotation.SimpleElementValue; +import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisibleAnnotations; +import org.aspectj.apache.bcel.util.SyntheticRepository; + + +public class RuntimeVisibleAnnotationAttributeTest extends BcelTestCase { + + + protected void setUp() throws Exception { + super.setUp(); + } + + public void testSeeAnnotationsAsAttribute() throws ClassNotFoundException { + SyntheticRepository repos = createRepos("testcode.jar"); + JavaClass clazz = repos.loadClass("SimpleAnnotatedClass"); + ConstantPool pool = clazz.getConstantPool(); + Attribute[] rvaAttr = findAttribute("RuntimeVisibleAnnotations",clazz); + assertTrue("Expected a RuntimeVisibleAnnotations attribute but found none", + rvaAttr.length==1); + } + + public void testAnnotationsAttributeContainsRightData() throws ClassNotFoundException { + SyntheticRepository repos = createRepos("testcode.jar"); + JavaClass clazz = repos.loadClass("SimpleAnnotatedClass"); + ConstantPool pool = clazz.getConstantPool(); + Attribute[] rvaAttr = findAttribute("RuntimeVisibleAnnotations",clazz); + RuntimeVisibleAnnotations rva = (RuntimeVisibleAnnotations) rvaAttr[0]; + List anns = rva.getAnnotations(); + assertTrue("Should be one annotation but found "+anns.size(), + anns.size()==1); + Annotation ann = (Annotation) anns.get(0); + assertTrue("Should be called 'SimpleAnnotation' but was called "+ann.getTypeName(), + ann.getTypeName().equals("SimpleAnnotation")); + List l = ann.getValues(); + assertTrue("Should be one value for annotation 'SimpleAnnotation' but found "+l.size(), + l.size()==1); + ElementNameValuePair envp = (ElementNameValuePair)l.get(0); + assertTrue("Name of element in SimpleAnnotation should be 'id' but it is "+envp.getNameString(), + envp.getNameString().equals("id")); + SimpleElementValue evalue = (SimpleElementValue)envp.getValue(); + assertTrue("'id' should be of type int, but it is "+evalue.getElementValueType(),evalue.getElementValueType()==SimpleElementValue.PRIMITIVE_INT); + assertTrue("'id' should have value 4 but it is "+evalue.getValueInt(), + evalue.getValueInt()==4); + } + + public void testAccessingAnnotationsOnClazz() throws ClassNotFoundException { + SyntheticRepository repos = createRepos("testcode.jar"); + JavaClass clazz = repos.loadClass("SimpleAnnotatedClass"); + ConstantPool pool = clazz.getConstantPool(); + Annotation[] anns = clazz.getAnnotations(); + assertTrue("Expected one annotation on SimpleAnnotatedClass class but got "+anns.length, + anns.length==1); + } + + public void testReadingWritingAnnotations() throws ClassNotFoundException, IOException { + SyntheticRepository repos = createRepos("testcode.jar"); + JavaClass clazz = repos.loadClass("SimpleAnnotatedClass"); + ConstantPool pool = clazz.getConstantPool(); + Annotation[] anns = clazz.getAnnotations(); + assertTrue("Expected one annotation on SimpleAnnotatedClass class but got "+anns.length, + anns.length==1); + + // Write it out + File tfile = createTestdataFile("SimpleAnnotatedClass.class"); + clazz.dump(tfile); + + SyntheticRepository repos2 = createRepos("."); + JavaClass clazz2 = repos.loadClass("SimpleAnnotatedClass"); + ConstantPool pool2 = clazz2.getConstantPool(); + Annotation[] anns2 = clazz2.getAnnotations(); + assertTrue("Expected one annotation on SimpleAnnotatedClass class but got "+anns2.length, + anns2.length==1); + + assertTrue(tfile.delete()); + } + + + + //// + // Test for annotations containing string elements + + public void testAnnotationStringElement() throws ClassNotFoundException { + SyntheticRepository repos = createRepos("testcode.jar"); + JavaClass clazz = repos.loadClass("AnnotatedClass"); + verifyAnnotationStringElement(clazz); + } + + + public void testAnnotationStringElementReadWrite() throws ClassNotFoundException, IOException { + SyntheticRepository repos = createRepos("testcode.jar"); + JavaClass clazz = repos.loadClass("AnnotatedClass"); + verifyAnnotationStringElement(clazz); + + // Write it out + File tfile = createTestdataFile("AnnotatedClass.class"); + clazz.dump(tfile); + + SyntheticRepository repos2 = createRepos("."); + JavaClass clazz2 = repos2.loadClass("AnnotatedClass"); + verifyAnnotationStringElement(clazz2); + + assertTrue(tfile.delete()); + } + + private void verifyAnnotationStringElement(JavaClass clazz) { + Annotation[] anns = clazz.getAnnotations(); + assertTrue("should be one annotation but found "+anns.length,anns.length==1); + Annotation ann = anns[0]; + assertTrue("should be called 'AnnotationStringElement' but was called "+ann.getTypeName(), + ann.getTypeName().equals("AnnotationStringElement")); + List l = ann.getValues(); + assertTrue("Should be one value but there were "+l.size(),l.size()==1); + ElementNameValuePair nvp = (ElementNameValuePair)l.get(0); + assertTrue("Name of element should be 'stringval' but was "+nvp.getNameString(), + nvp.getNameString().equals("stringval")); + SimpleElementValue ev = (SimpleElementValue)nvp.getValue(); + assertTrue("String value should be 'hello' but was '"+ev.getValueString()+"'", + ev.getValueString().equals("hello")); + } + + //// + // Test for complex annotation that includes all primitives + + public void testComplexAnnotation() throws ClassNotFoundException { + SyntheticRepository repos = createRepos("testcode.jar"); + JavaClass clazz = repos.loadClass("ComplexAnnotatedClass"); + verifyComplexAnnotation(clazz); + } + + + public void testComplexAnnotationsReadWrite() throws ClassNotFoundException, IOException { + SyntheticRepository repos = createRepos("testcode.jar"); + JavaClass clazz = repos.loadClass("ComplexAnnotatedClass"); + verifyComplexAnnotation(clazz); + + // Write it out + File tfile = createTestdataFile("ComplexAnnotatedClass.class"); + clazz.dump(tfile); + + SyntheticRepository repos2 = createRepos("."); + JavaClass clazz2 = repos.loadClass("ComplexAnnotatedClass"); + verifyComplexAnnotation(clazz2); + + assertTrue(tfile.delete()); + + } + + private void verifyComplexAnnotation(JavaClass clazz) { + Annotation[] anns = clazz.getAnnotations(); + assertTrue("Should be one annotation but found "+anns.length,anns.length==1); + Annotation ann = anns[0]; + assertTrue("Should be called 'ComplexAnnotation' but was called "+ann.getTypeName(), + ann.getTypeName().equals("ComplexAnnotation")); + List l = ann.getValues(); + assertTrue("Should be eight values for annotation 'ComplexAnnotation' but found "+l.size(), + l.size()==8); + List names = Utility.getListOfAnnotationNames(ann); + assertTrue("Cant find expected element ",names.contains("ival")); + assertTrue("Cant find expected element ",names.contains("dval")); + assertTrue("Cant find expected element ",names.contains("zval")); + assertTrue("Cant find expected element ",names.contains("fval")); + assertTrue("Cant find expected element ",names.contains("jval")); + assertTrue("Cant find expected element ",names.contains("sval")); + assertTrue("Cant find expected element ",names.contains("bval")); + assertTrue("Cant find expected element ",names.contains("cval")); + + checkValue(ann,"ival","4"); + checkValue(ann,"jval","56"); + checkValue(ann,"fval","3.0"); + checkValue(ann,"dval","33.4"); + checkValue(ann,"sval","99"); + checkValue(ann,"bval","2"); + checkValue(ann,"cval","5"); + checkValue(ann,"zval","false"); + + } + + private void checkValue(Annotation a,String name,String tostring) { + for (Iterator i = a.getValues().iterator(); i.hasNext();) { + ElementNameValuePair element = (ElementNameValuePair) i.next(); + if (element.getNameString().equals(name)) { + if (!element.getValue().stringifyValue().equals(tostring)) { + fail("Expected element "+name+" to have value "+tostring+" but it had value "+element.getValue().stringifyValue()); + } + return; + } + } + fail("Didnt find named element "+name); + } + + //// + // Test an annotation containing a 'Class' element + + public void testAnnotationClassElement() throws ClassNotFoundException { + SyntheticRepository repos = createRepos("testcode.jar"); + JavaClass clazz = repos.loadClass("AnnotatedWithClassClass"); + verifyClassAnnotation(clazz); + } + + public void testAnnotationClassElementReadWrite() throws ClassNotFoundException,IOException { + SyntheticRepository repos = createRepos("testcode.jar"); + JavaClass clazz = repos.loadClass("AnnotatedWithClassClass"); + verifyClassAnnotation(clazz); + + // Write it out + File tfile = createTestdataFile("AnnotatedWithClassClass.class"); + clazz.dump(tfile); + + SyntheticRepository repos2 = createRepos("."); + JavaClass clazz2 = repos2.loadClass("AnnotatedWithClassClass"); + verifyClassAnnotation(clazz2); + + assertTrue(wipe("AnnotatedWithClassClass.class")); + } + + private void verifyClassAnnotation(JavaClass clazz) { + Annotation[] anns = clazz.getAnnotations(); + assertTrue("should be one annotation but found "+anns.length,anns.length==1); + Annotation ann = anns[0]; + assertTrue("should be called 'AnnotationClassElement' but was called "+ann.getTypeName(), + ann.getTypeName().equals("AnnotationClassElement")); + List l = ann.getValues(); + assertTrue("Should be one value but there were "+l.size(),l.size()==1); + ElementNameValuePair nvp = (ElementNameValuePair)l.get(0); + assertTrue("Name of element should be 'clz' but was "+nvp.getNameString(), + nvp.getNameString().equals("clz")); + ClassElementValue ev = (ClassElementValue)nvp.getValue(); + assertTrue("String value should be 'Ljava/lang/Integer;' but was '"+ev.getClassString()+"'", + ev.getClassString().equals("Ljava/lang/Integer;")); + + } + + //// + // Test an annotation containing an enum element + + public void testAnnotationEnumElement() throws ClassNotFoundException { + SyntheticRepository repos = createRepos("testcode.jar"); + JavaClass clazz = repos.loadClass("AnnotatedWithEnumClass"); + verifyAnnotationEnumElement(clazz); + } + + public void testAnnotationEnumElementReadWrite() throws ClassNotFoundException, IOException { + SyntheticRepository repos = createRepos("testcode.jar"); + JavaClass clazz = repos.loadClass("AnnotatedWithEnumClass"); + verifyAnnotationEnumElement(clazz); + + // Write it out + File tfile = createTestdataFile("AnnotatedWithEnumClass.class"); + clazz.dump(tfile); + + SyntheticRepository repos2 = createRepos("."); + JavaClass clazz2 = repos2.loadClass("AnnotatedWithEnumClass"); + verifyAnnotationEnumElement(clazz2); + + assertTrue(tfile.delete()); + } + + public void verifyAnnotationEnumElement(JavaClass clazz) { + Annotation[] anns = clazz.getAnnotations(); + assertTrue("should be one annotation but found "+anns.length,anns.length==1); + Annotation ann = anns[0]; + assertTrue("should be called 'AnnotationEnumElement' but was called "+ann.getTypeName(), + ann.getTypeName().equals("AnnotationEnumElement")); + List l = ann.getValues(); + assertTrue("Should be one value but there were "+l.size(),l.size()==1); + ElementNameValuePair nvp = (ElementNameValuePair)l.get(0); + assertTrue("Name of element should be 'enumval' but was "+nvp.getNameString(), + nvp.getNameString().equals("enumval")); + ElementValue ev = nvp.getValue(); + assertTrue("Should be of type EnumElementValue but is "+ev,ev instanceof EnumElementValue); + EnumElementValue eev = (EnumElementValue)ev; + assertTrue("Should be an enum type value but is "+eev.getElementValueType(),eev.getElementValueType()==SimpleElementValue.ENUM_CONSTANT); + assertTrue("Enum type for annotation should be 'SimpleEnum' but is "+eev.getEnumTypeString(),eev.getEnumTypeString().equals("SimpleEnum")); + assertTrue("String value should be 'Red' but was '"+eev.getEnumValueString()+"'", + eev.getEnumValueString().equals("Red")); + } + + //// + // Test an annotation with an array element + + public void testAnnotationArraysOfAnnotations() throws ClassNotFoundException { + SyntheticRepository repos = createRepos("testcode.jar"); + JavaClass clazz = repos.loadClass("AnnotatedWithCombinedAnnotation"); + Annotation[] anns = clazz.getAnnotations(); + assertTrue("should be one annotation but found "+anns.length,anns.length==1); + checkCombinedAnnotation(anns[0]); + } + + public void testAnnotationArraysOfAnnotationsReadWrite() throws ClassNotFoundException, IOException { + SyntheticRepository repos = createRepos("testcode.jar"); + JavaClass clazz = repos.loadClass("AnnotatedWithCombinedAnnotation"); + Annotation[] anns = clazz.getAnnotations(); + assertTrue("should be one annotation but found "+anns.length,anns.length==1); + checkCombinedAnnotation(anns[0]); + + // Write it out + File tfile = createTestdataFile("AnnotatedWithCombinedAnnotation.class"); + clazz.dump(tfile); + + SyntheticRepository repos2 = createRepos("."); + JavaClass clazz2 = repos2.loadClass("AnnotatedWithCombinedAnnotation"); + Annotation[] anns2 = clazz2.getAnnotations(); + assertTrue("should be one annotation but found "+anns2.length,anns2.length==1); + checkCombinedAnnotation(anns2[0]); + + assertTrue(tfile.delete()); + } + + + private void checkCombinedAnnotation(Annotation ann) { + assertTrue("should be called 'CombinedAnnotation' but was called "+ann.getTypeName(), + ann.getTypeName().equals("CombinedAnnotation")); + List l = ann.getValues(); + assertTrue("Should be one value but there were "+l.size(),l.size()==1); + ElementNameValuePair nvp = (ElementNameValuePair)l.get(0); + assertTrue("Name of element should be 'value' but was "+nvp.getNameString(), + nvp.getNameString().equals("value")); + ElementValue ev = nvp.getValue(); + assertTrue("Should be of type ArrayElementValue but is "+ev,ev instanceof ArrayElementValue); + ArrayElementValue aev = (ArrayElementValue)ev; + + assertTrue("Array element value should be of size 1 but is "+aev.getElementValuesArraySize(), + aev.getElementValuesArraySize()==1); + ElementValue[] evs = aev.getElementValuesArray(); + assertTrue("Entry in the array should be AnnotationElementValue but is "+evs[0], + evs[0] instanceof AnnotationElementValue); + AnnotationElementValue inner_ev = (AnnotationElementValue)evs[0]; + Annotation a = inner_ev.getAnnotation(); + assertTrue("Should be SimpleAnnotation but is "+a.getTypeName(),a.getTypeName().equals("SimpleAnnotation")); + List envps = a.getValues(); + assertTrue("Should be one name value pair but found "+envps.size(),envps.size()==1); + ElementNameValuePair envp = (ElementNameValuePair) envps.get(0); + assertTrue("Name should be 'id' but it is "+envp.getNameString(),envp.getNameString().equals("id")); + assertTrue("Value of 'id' should be 4 but it is "+envp.getValue().stringifyValue(), + envp.getValue().stringifyValue().equals("4")); + } + + + protected void tearDown() throws Exception { + super.tearDown(); + } + +} diff --git a/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/RuntimeVisibleParameterAnnotationAttributeTest.java b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/RuntimeVisibleParameterAnnotationAttributeTest.java new file mode 100644 index 000000000..4617133fe --- /dev/null +++ b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/RuntimeVisibleParameterAnnotationAttributeTest.java @@ -0,0 +1,143 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation + * ******************************************************************/ + +package org.aspectj.apache.bcel.classfile.tests; + +import java.io.File; +import java.io.IOException; +import java.util.Iterator; + +import org.aspectj.apache.bcel.classfile.Attribute; +import org.aspectj.apache.bcel.classfile.JavaClass; +import org.aspectj.apache.bcel.classfile.Method; +import org.aspectj.apache.bcel.classfile.annotation.Annotation; +import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePair; +import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisibleParameterAnnotations; +import org.aspectj.apache.bcel.util.SyntheticRepository; + + +public class RuntimeVisibleParameterAnnotationAttributeTest extends BcelTestCase { + + + protected void setUp() throws Exception { + super.setUp(); + } + + + public void testAccessingRuntimeVisibleParameterAnnotations() throws ClassNotFoundException { + JavaClass clazz = getClassFromJar("AnnotatedParameters"); + Attribute[] rvaAttr = findAttribute("RuntimeVisibleParameterAnnotations",clazz); + Method[] methods = clazz.getMethods(); + + for (int i = 0; i < methods.length; i++) { + Method m = methods[i]; + if (m.getName().equals("foo")) { + RuntimeVisibleParameterAnnotations paramAnns = + (RuntimeVisibleParameterAnnotations) findAttribute("RuntimeVisibleParameterAnnotations",m.getAttributes()); + assertTrue("foo takes two parameters, not "+paramAnns.getParameterAnnotations().size(), + paramAnns.getParameterAnnotations().size()==2); + + Annotation[] firstParamAnnotations = paramAnns.getAnnotationsOnParameter(0); + checkAnnotation(firstParamAnnotations[0],"SimpleAnnotation","id","2"); + + Annotation[] secondParamAnnotations = paramAnns.getAnnotationsOnParameter(1); + checkAnnotation(secondParamAnnotations[0],"SimpleAnnotation","id","3"); + checkAnnotation(secondParamAnnotations[1],"AnnotationEnumElement","enumval","Red"); + + } + if (m.getName().equals("main")) { + RuntimeVisibleParameterAnnotations paramAnns = + (RuntimeVisibleParameterAnnotations) findAttribute("RuntimeVisibleParameterAnnotations",m.getAttributes()); + assertTrue("main takes one parameter, not "+paramAnns.getParameterAnnotations().size(), + paramAnns.getParameterAnnotations().size()==1); + + Annotation[] firstParamAnnotations = paramAnns.getAnnotationsOnParameter(0); + checkAnnotation(firstParamAnnotations[0],"SimpleAnnotation","id","1"); + } + } + } + + public void testAccessingParameterAnnotationsThroughGetAnnotations() throws ClassNotFoundException { + JavaClass clazz = getClassFromJar("AnnotatedParameters"); + Attribute[] rvaAttr = findAttribute("RuntimeVisibleParameterAnnotations",clazz); + + checkFooMethod(clazz); + } + + public void testParameterAnnotationsReadWrite() throws ClassNotFoundException,IOException { + JavaClass clazz = getClassFromJar("AnnotatedParameters"); + + checkFooMethod(clazz); + + // Write it out + File tfile = createTestdataFile("AnnotatedParameters.class"); + clazz.dump(tfile); + + SyntheticRepository repos2 = createRepos("."); + JavaClass clazz2 = repos2.loadClass("AnnotatedParameters"); + + checkFooMethod(clazz); + + assertTrue(tfile.delete()); + } + + + public void checkFooMethod(JavaClass clazz) { + Method[] methods = clazz.getMethods(); + + for (int i = 0; i < methods.length; i++) { + Method m = methods[i]; + if (m.getName().equals("foo")) { + + Annotation[] firstParamAnnotations = m.getAnnotationsOnParameter(0); + checkAnnotation(firstParamAnnotations[0],"SimpleAnnotation","id","2"); + + Annotation[] secondParamAnnotations = m.getAnnotationsOnParameter(1); + checkAnnotation(secondParamAnnotations[0],"SimpleAnnotation","id","3"); + checkAnnotation(secondParamAnnotations[1],"AnnotationEnumElement","enumval","Red"); + + } + } + } + + private void checkAnnotation(Annotation a,String name,String elementname,String elementvalue) { + assertTrue("Expected annotation to have name "+name+" but it had name "+a.getTypeName(), + a.getTypeName().equals(name)); + assertTrue("Expected annotation to have one element but it had "+a.getValues().size(),a.getValues().size()==1); + ElementNameValuePair envp = (ElementNameValuePair)a.getValues().get(0); + assertTrue("Expected element name "+elementname+" but was "+envp.getNameString(), + elementname.equals(envp.getNameString())); + assertTrue("Expected element value "+elementvalue+" but was "+envp.getValue().stringifyValue(), + elementvalue.equals(envp.getValue().stringifyValue())); + } + + + // helper methods + + public void checkValue(Annotation a,String name,String tostring) { + for (Iterator i = a.getValues().iterator(); i.hasNext();) { + ElementNameValuePair element = (ElementNameValuePair) i.next(); + if (element.getNameString().equals(name)) { + if (!element.getValue().stringifyValue().equals(tostring)) { + fail("Expected element "+name+" to have value "+tostring+" but it had value "+element.getValue().stringifyValue()); + } + return; + } + } + fail("Didnt find named element "+name); + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + +} diff --git a/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/VarargsTest.java b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/VarargsTest.java new file mode 100644 index 000000000..e8e6e2d19 --- /dev/null +++ b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/VarargsTest.java @@ -0,0 +1,97 @@ +/* ******************************************************************* + * Copyright (c) 2004 IBM + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Andy Clement - initial implementation + * ******************************************************************/ + +package org.aspectj.apache.bcel.classfile.tests; + +import java.io.File; +import java.io.IOException; +import java.util.Iterator; + +import org.aspectj.apache.bcel.classfile.JavaClass; +import org.aspectj.apache.bcel.classfile.Method; +import org.aspectj.apache.bcel.classfile.annotation.Annotation; +import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePair; +import org.aspectj.apache.bcel.util.SyntheticRepository; + + +public class VarargsTest extends BcelTestCase { + + + protected void setUp() throws Exception { + super.setUp(); + } + + + public void testVarargs() throws ClassNotFoundException { + JavaClass clazz = getClassFromJar("VarargsClass"); + + checkMarkedVarargs(clazz,"foo",true); + checkMarkedVarargs(clazz,"goo",true); + checkMarkedVarargs(clazz,"hoo",false); + } + + public void testVarargsReadWrite() throws ClassNotFoundException,IOException { + JavaClass clazz = getClassFromJar("VarargsClass"); + + checkMarkedVarargs(clazz,"foo",true); + checkMarkedVarargs(clazz,"goo",true); + checkMarkedVarargs(clazz,"hoo",false); + + // Write it out + File tfile = createTestdataFile("VarargsClass.class"); + clazz.dump(tfile); + + SyntheticRepository repos2 = createRepos("."); + JavaClass clazz2 = repos2.loadClass("VarargsClass"); + + checkMarkedVarargs(clazz,"foo",true); + checkMarkedVarargs(clazz,"goo",true); + checkMarkedVarargs(clazz,"hoo",false); + + assertTrue(tfile.delete()); + } + + // helper methods + + public void checkMarkedVarargs(JavaClass clazz,String methodname,boolean shouldBeMarked) { + Method[] methods = clazz.getMethods(); + + for (int i = 0; i < methods.length; i++) { + Method m = methods[i]; + if (m.getName().equals(methodname)) { + assertTrue("Method '"+methodname+"' should answer varargs="+shouldBeMarked, + m.isVarargs()==shouldBeMarked); + } + } + } + + + // helper methods + + public void checkValue(Annotation a,String name,String tostring) { + for (Iterator i = a.getValues().iterator(); i.hasNext();) { + ElementNameValuePair element = (ElementNameValuePair) i.next(); + if (element.getNameString().equals(name)) { + if (!element.getValue().stringifyValue().equals(tostring)) { + fail("Expected element "+name+" to have value "+tostring+" but it had value "+element.getValue().stringifyValue()); + } + return; + } + } + fail("Didnt find named element "+name); + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + +} |