summaryrefslogtreecommitdiffstats
path: root/bcel-builder
diff options
context:
space:
mode:
authoraclement <aclement>2004-11-19 16:35:15 +0000
committeraclement <aclement>2004-11-19 16:35:15 +0000
commit8644e07c0dcee8a4e24b0bcdb320c9bfa47d9612 (patch)
tree73e8702570983a46ba4129d57fa16d6df9950327 /bcel-builder
parentbfd1d4d0b5a553afdbbf93eb1972ff9d802906b3 (diff)
downloadaspectj-8644e07c0dcee8a4e24b0bcdb320c9bfa47d9612.tar.gz
aspectj-8644e07c0dcee8a4e24b0bcdb320c9bfa47d9612.zip
BCEL Java5 Support
Diffstat (limited to 'bcel-builder')
-rw-r--r--bcel-builder/.classpath10
-rw-r--r--bcel-builder/build.xml11
-rw-r--r--bcel-builder/notamodule0
-rw-r--r--bcel-builder/readme.html62
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/Annotation.java125
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/AnnotationElementValue.java51
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/ArrayElementValue.java66
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/ClassElementValue.java53
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/ElementNameValuePair.java62
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/ElementValue.java112
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/EnumElementValue.java63
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeAnnotations.java83
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeInvisibleAnnotations.java40
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeInvisibleParameterAnnotations.java34
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeParameterAnnotations.java110
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeVisibleAnnotations.java40
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/RuntimeVisibleParameterAnnotations.java34
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/annotation/SimpleElementValue.java119
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/AnnotationElementValueGen.java55
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/AnnotationGen.java148
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/ArrayElementValueGen.java87
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/ClassElementValueGen.java59
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/ElementNameValuePairGen.java70
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/ElementValueGen.java137
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/EnumElementValueGen.java84
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/generic/annotation/SimpleElementValueGen.java173
-rw-r--r--bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/AllTests.java54
-rw-r--r--bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/AnnotationAccessFlagTest.java55
-rw-r--r--bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/AnnotationDefaultAttributeTest.java49
-rw-r--r--bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/AnnotationGenTest.java122
-rw-r--r--bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/BcelTestCase.java150
-rw-r--r--bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/ElementValueGenTest.java227
-rw-r--r--bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/EnclosingMethodAttributeTest.java104
-rw-r--r--bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/EnumAccessFlagTest.java56
-rw-r--r--bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/FieldAnnotationsTest.java147
-rw-r--r--bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/GeneratingAnnotatedClassesTest.java633
-rw-r--r--bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/LocalVariableTypeTableTest.java72
-rw-r--r--bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/MethodAnnotationsTest.java108
-rw-r--r--bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/ParameterAnnotationsTest.java593
-rw-r--r--bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/RuntimeVisibleAnnotationAttributeTest.java373
-rw-r--r--bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/RuntimeVisibleParameterAnnotationAttributeTest.java143
-rw-r--r--bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/VarargsTest.java97
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();
+ }
+
+}