summaryrefslogtreecommitdiffstats
path: root/bcel-builder/testsrc/org
diff options
context:
space:
mode:
Diffstat (limited to 'bcel-builder/testsrc/org')
-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
16 files changed, 2983 insertions, 0 deletions
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();
+ }
+
+}