diff options
author | aclement <aclement> | 2004-11-19 16:35:15 +0000 |
---|---|---|
committer | aclement <aclement> | 2004-11-19 16:35:15 +0000 |
commit | 8644e07c0dcee8a4e24b0bcdb320c9bfa47d9612 (patch) | |
tree | 73e8702570983a46ba4129d57fa16d6df9950327 /bcel-builder/testsrc/org | |
parent | bfd1d4d0b5a553afdbbf93eb1972ff9d802906b3 (diff) | |
download | aspectj-8644e07c0dcee8a4e24b0bcdb320c9bfa47d9612.tar.gz aspectj-8644e07c0dcee8a4e24b0bcdb320c9bfa47d9612.zip |
BCEL Java5 Support
Diffstat (limited to 'bcel-builder/testsrc/org')
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(); + } + +} |