@@ -1,7 +1,9 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<classpath> | |||
<classpathentry kind="src" path="src"/> | |||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> | |||
<classpathentry kind="lib" path="/lib/regexp/jakarta-regexp-1.2.jar"/> | |||
<classpathentry kind="output" path="bin"/> | |||
<classpathentry kind="src" path="src"/> | |||
<classpathentry kind="src" path="testsrc"/> | |||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> | |||
<classpathentry kind="lib" path="/lib/regexp/jakarta-regexp-1.2.jar"/> | |||
<classpathentry sourcepath="/lib/junit/junit-src.jar" kind="lib" path="/lib/junit/junit.jar"/> | |||
<classpathentry kind="output" path="bin"/> | |||
</classpath> |
@@ -1,10 +1,12 @@ | |||
<project default="extractAndPatchAndJar" basedir="."> | |||
<project default="packageAndPush" basedir="."> | |||
<!-- top-level --> | |||
<target name="extractAndPatchAndJar" depends="extractAndPatch,jar,srcjar" /> | |||
<target name="extractAndPatch" depends="unzipSource,createPatchedSource" /> | |||
<target name="packageAndPush" depends="buildTheJars,push"/> | |||
<target name="jar" depends="pack"> | |||
<copy file="../lib/regexp/jakarta-regexp-1.2.jar" | |||
tofile="bcel/lib/Regex.jar" /> | |||
@@ -20,6 +22,11 @@ | |||
<copy file="bcel.jar" todir="../lib/bcel" /> | |||
<copy file="bcel-src.zip" todir="../lib/bcel" /> | |||
</target> | |||
<target name="buildTheJars"> | |||
<zip file="bcel.jar" basedir="bin" includes="**/*" excludes="**/tests/*.class"/> | |||
<zip file="bcel-src.zip" basedir="src" includes="**/*"/> | |||
</target> | |||
<target name="diff" depends="transformFromAJ,pack"> | |||
@@ -6,15 +6,73 @@ | |||
<body> | |||
<h1>The BCEL-builder module</h1> | |||
This module includes a modified form of BCEL - with some fixes in *and* support for Java5. | |||
<hr> | |||
<h3>Java 5 support</h3> | |||
<p>The best way to see how it works is look in the testcases. The only feature that | |||
is definetly not implemented yet is package level annotations. What is working is:</p> | |||
<ul> | |||
<li>You can ask a type: are you an annotation type? are you an enum type?</li> | |||
<li>You can ask a method: were you defined with varargs? Are you a bridge method?</li> | |||
<li>All annotation values types are supported (primitive, string, array, enum, annotation, class).</li> | |||
<li>Runtime visible and invisible annotations are supported.</li> | |||
<li>Annotations are accessible on types, methods, fields.</li> | |||
<li>Parameter annotations are accessible on methods.</li> | |||
<li>You can programmatically construct annotations and attach them to types, methods, fields.</li> | |||
<li>You can construct parameter annotations and add them to methods.</li> | |||
<li>The EnclosingMethod attribute is supported (it is used to let you know the containing method for local/anonymous types)</li> | |||
<li>The LocalVariableTypeTable attribute is supported (used for generics to tell you the original variable signature)</li> | |||
</ul> | |||
<p>All this is implemented without using any Java 5 APIs.</p> | |||
<p>There are a number of new TODO type tags in the code that may prove useful:</p> | |||
<ul> | |||
<li>J5SUPPORT: Marks places where BCEL has been changed for 1.5 (might have missed a couple...)</li> | |||
<li>BCELBUG: Marks things that might be BCEL problems that I came across</li> | |||
<li>J5TODO: Marks either a missing bit of implementation (hopefully corner case) or an optimization we could make</li> | |||
</ul> | |||
<hr> | |||
<p> The contents of this directory are: | |||
</p> | |||
<ul> | |||
<li>This file</li> | |||
<li>build.xml -- an ant script </li> | |||
<li>patch.txt -- a diff patchfile</li> | |||
<li>src -- contains the source for BCEL, a modified variant of BCEL 5.1 that includes bug fixes and Java 5 support</li> | |||
<li>testsrc -- JUnit test cases for the Java 5 support</li> | |||
<li>testdata -- Java5 testcode that can be built using the build.xml script in the testdata directory (see note on this below)</li> | |||
<li>build.xml -- an ant script for manipulating the src folder, possibly useful if ever merging a base BCEL version</li> | |||
</ul> | |||
<hr> | |||
<h3>Development Process</h3> | |||
<p> | |||
We can now follow normal TDD for this. Add a JUnit testcase to the testsrc folder, plus any | |||
associated test materials into the testdata directory. Then change BCEL to get your test passing, | |||
when you are happy with the result (i.e. all the tests in the bcel-builder module are passing), you | |||
should execute the build.xml script whose default target will package up bcel (and bcel src) and | |||
deliver it into the lib module, the rest of AspectJ is driven off the version of bcel in the lib/bcel | |||
folder - it is *not* driven off the bcel-builder code (we could choose to change that sometime later). | |||
<p> | |||
Once you have done this execute all the tests for AspectJ, if they all pass you can check in your | |||
mods for bcel-builder and to the lib project. | |||
<hr> | |||
<h3>testdata</h3> | |||
The testdata folder includes a load of Java5 code, it needs to be built with a Java5 compiler. There | |||
is an ant script in there (build.xml) that builds all the source code into a testcode.jar which is | |||
then used by the testcases - so if you do change the testdata code then you should run build.xml | |||
to rebuild testcode.jar. | |||
<hr> | |||
<h3>The old stuff...</h3> | |||
Before the Java 5 support was added we maintained this module as basically a patch to apply against | |||
a particular download of BCEL. Changes to BCEL are occurring more frequently than we integrate | |||
a new version of BCEL so it made sense to make the patching process easier, so we have checked in | |||
the modified source for BCEL. | |||
The original instructions for patching BCEL in the old way are below... | |||
<p> And pretty much nothing else. Well, then, what do you do with | |||
this directory? Well, the whole point is to generate bcel/bcel.jar in | |||
the lib package. To do so, first stick |
@@ -0,0 +1,125 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2004 IBM Corporation | |||
* | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Common Public License v1.0 | |||
* which accompanies this distribution and is available at | |||
* http://www.eclipse.org/legal/cpl-v10.html | |||
* | |||
* Contributors: | |||
* Andy Clement initial implementation | |||
* ******************************************************************/ | |||
package org.aspectj.apache.bcel.classfile.annotation; | |||
import java.io.DataInputStream; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import org.aspectj.apache.bcel.Constants; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
import org.aspectj.apache.bcel.classfile.ConstantUtf8; | |||
import org.aspectj.apache.bcel.classfile.Utility; | |||
/** | |||
* An annotation is an immutable object (AnnotationGen is the mutable variant) - it basically contains a list | |||
* of name-value pairs. | |||
*/ | |||
public class Annotation { | |||
private int typeIndex; | |||
private List /* ElementNameValuePair */ evs; | |||
private ConstantPool cpool; | |||
private boolean isRuntimeVisible; | |||
public String toString() { | |||
StringBuffer sb = new StringBuffer(); | |||
sb.append("ANNOTATION ["+getTypeSignature()+"] ["+ | |||
(isRuntimeVisible?"runtimeVisible":"runtimeInvisible")+"] ["); | |||
for (Iterator iter = evs.iterator(); iter.hasNext();) { | |||
ElementNameValuePair element = (ElementNameValuePair) iter.next(); | |||
sb.append(element.toString()); | |||
if (iter.hasNext()) sb.append(","); | |||
} | |||
sb.append("]"); | |||
return sb.toString(); | |||
} | |||
private Annotation(ConstantPool cpool) { | |||
this.cpool = cpool; | |||
} | |||
protected static Annotation read(DataInputStream dis,ConstantPool cpool,boolean isRuntimeVisible) throws IOException { | |||
Annotation a = new Annotation(cpool); | |||
a.typeIndex = dis.readUnsignedShort(); | |||
int elemValuePairCount = dis.readUnsignedShort(); | |||
for (int i=0;i<elemValuePairCount;i++) { | |||
int nidx = dis.readUnsignedShort(); | |||
a.addElementNameValuePair( | |||
new ElementNameValuePair(nidx,ElementValue.readElementValue(dis,cpool),cpool)); | |||
} | |||
a.isRuntimeVisible(isRuntimeVisible); | |||
return a; | |||
} | |||
protected void dump(DataOutputStream dos) throws IOException { | |||
dos.writeShort(typeIndex); // u2 index of type name in cpool | |||
dos.writeShort(evs.size()); // u2 element_value pair count | |||
for (int i = 0 ; i<evs.size();i++) { | |||
ElementNameValuePair envp = (ElementNameValuePair) evs.get(i); | |||
envp.dump(dos); | |||
} | |||
} | |||
public void addElementNameValuePair(ElementNameValuePair evp) { | |||
if (evs == null) evs = new ArrayList(); | |||
evs.add(evp); | |||
} | |||
public int getTypeIndex() { | |||
return typeIndex; | |||
} | |||
public final String getTypeSignature() { | |||
ConstantUtf8 c = (ConstantUtf8)cpool.getConstant(typeIndex,Constants.CONSTANT_Utf8); | |||
return c.getBytes(); | |||
} | |||
public final String getTypeName() { | |||
ConstantUtf8 c = (ConstantUtf8)cpool.getConstant(typeIndex,Constants.CONSTANT_Utf8); | |||
return Utility.signatureToString(c.getBytes()); | |||
} | |||
/** | |||
* Returns list of ElementNameValuePair objects | |||
*/ | |||
public List getValues() { | |||
return evs; | |||
} | |||
protected void isRuntimeVisible(boolean b) { | |||
isRuntimeVisible = b; | |||
} | |||
public boolean isRuntimeVisible() { | |||
return isRuntimeVisible; | |||
} | |||
public String toShortString() { | |||
StringBuffer result = new StringBuffer(); | |||
result.append("@"); | |||
result.append(getTypeName()); | |||
if (getValues().size()>0) { | |||
result.append("("); | |||
for (Iterator iter = getValues().iterator(); iter.hasNext();) { | |||
ElementNameValuePair element = (ElementNameValuePair) iter.next(); | |||
result.append(element.toShortString()); | |||
} | |||
result.append(")"); | |||
} | |||
return result.toString(); | |||
} | |||
} |
@@ -0,0 +1,51 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2004 IBM | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Common Public License v1.0 | |||
* which accompanies this distribution and is available at | |||
* http://www.eclipse.org/legal/cpl-v10.html | |||
* | |||
* Contributors: | |||
* Andy Clement - initial implementation {date} | |||
* ******************************************************************/ | |||
package org.aspectj.apache.bcel.classfile.annotation; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
/** | |||
* An element value that is an annotation. | |||
*/ | |||
public class AnnotationElementValue extends ElementValue { | |||
// For annotation element values, this is the annotation | |||
private Annotation a; | |||
public AnnotationElementValue(int type, Annotation annotation, ConstantPool cpool) { | |||
super(type,cpool); | |||
if (type != ANNOTATION) | |||
throw new RuntimeException("Only element values of type annotation can be built with this ctor"); | |||
this.a = annotation; | |||
} | |||
public void dump(DataOutputStream dos) throws IOException { | |||
dos.writeByte(type); // u1 type of value (ANNOTATION == '@') | |||
a.dump(dos); | |||
} | |||
public String stringifyValue() { | |||
StringBuffer sb = new StringBuffer(); | |||
sb.append(a.toString()); | |||
return sb.toString(); | |||
} | |||
public String toString() { | |||
return stringifyValue(); | |||
} | |||
public Annotation getAnnotation() { return a;} | |||
} |
@@ -0,0 +1,66 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2004 IBM | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Common Public License v1.0 | |||
* which accompanies this distribution and is available at | |||
* http://www.eclipse.org/legal/cpl-v10.html | |||
* | |||
* Contributors: | |||
* Andy Clement - initial implementation {date} | |||
* ******************************************************************/ | |||
package org.aspectj.apache.bcel.classfile.annotation; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
public class ArrayElementValue extends ElementValue { | |||
// For array types, this is the array | |||
private ElementValue[] evalues; | |||
public String toString() { | |||
StringBuffer sb = new StringBuffer(); | |||
sb.append("{"); | |||
for (int i = 0; i < evalues.length; i++) { | |||
sb.append(evalues[i].toString()); | |||
if ((i+1)<evalues.length) sb.append(","); | |||
} | |||
sb.append("}"); | |||
return sb.toString(); | |||
} | |||
public ArrayElementValue(int type, ElementValue[] datums, ConstantPool cpool) { | |||
super(type,cpool); | |||
if (type != ARRAY) | |||
throw new RuntimeException("Only element values of type array can be built with this ctor"); | |||
this.evalues = datums; | |||
} | |||
public void dump(DataOutputStream dos) throws IOException { | |||
dos.writeByte(type); // u1 type of value (ARRAY == '[') | |||
dos.writeShort(evalues.length); | |||
for (int i=0; i<evalues.length; i++) { | |||
evalues[i].dump(dos); | |||
} | |||
} | |||
public String stringifyValue() { | |||
StringBuffer sb = new StringBuffer(); | |||
sb.append("["); | |||
for(int i=0; i<evalues.length; i++) { | |||
sb.append(evalues[i].stringifyValue()); | |||
if ((i+1)<evalues.length) sb.append(","); | |||
} | |||
sb.append("]"); | |||
return sb.toString(); | |||
} | |||
public ElementValue[] getElementValuesArray() { return evalues;} | |||
public int getElementValuesArraySize() { return evalues.length;} | |||
} |
@@ -0,0 +1,53 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2004 IBM | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Common Public License v1.0 | |||
* which accompanies this distribution and is available at | |||
* http://www.eclipse.org/legal/cpl-v10.html | |||
* | |||
* Contributors: | |||
* Andy Clement - initial implementation {date} | |||
* ******************************************************************/ | |||
package org.aspectj.apache.bcel.classfile.annotation; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import org.aspectj.apache.bcel.Constants; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
import org.aspectj.apache.bcel.classfile.ConstantUtf8; | |||
public class ClassElementValue extends ElementValue { | |||
// For primitive types and string type, this points to the value entry in the cpool | |||
// For 'class' this points to the class entry in the cpool | |||
private int idx; | |||
protected ClassElementValue(int type,int idx,ConstantPool cpool) { | |||
super(type,cpool); | |||
this.idx = idx; | |||
} | |||
public int getIndex() { | |||
return idx; | |||
} | |||
public String getClassString() { | |||
ConstantUtf8 c = (ConstantUtf8)cpool.getConstant(idx,Constants.CONSTANT_Utf8); | |||
return c.getBytes(); | |||
} | |||
public String stringifyValue() { | |||
ConstantUtf8 cu8 = (ConstantUtf8)cpool.getConstant(idx,Constants.CONSTANT_Utf8); | |||
return cu8.getBytes(); | |||
} | |||
public void dump(DataOutputStream dos) throws IOException { | |||
dos.writeByte(type); // u1 kind of value | |||
dos.writeShort(idx); | |||
} | |||
} |
@@ -0,0 +1,62 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2004 IBM | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Common Public License v1.0 | |||
* which accompanies this distribution and is available at | |||
* http://www.eclipse.org/legal/cpl-v10.html | |||
* | |||
* Contributors: | |||
* Andy Clement - initial implementation {date} | |||
* ******************************************************************/ | |||
package org.aspectj.apache.bcel.classfile.annotation; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import org.aspectj.apache.bcel.Constants; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
import org.aspectj.apache.bcel.classfile.ConstantUtf8; | |||
public class ElementNameValuePair { | |||
private int nameIdx; | |||
private ElementValue value; | |||
private ConstantPool cpool; | |||
public String toString() { | |||
StringBuffer sb = new StringBuffer(); | |||
sb.append(getNameString()+"="+value.toString()); | |||
return sb.toString(); | |||
} | |||
public ElementNameValuePair(int idx,ElementValue value,ConstantPool cpool) { | |||
this.nameIdx = idx; | |||
this.value = value; | |||
this.cpool = cpool; | |||
} | |||
protected void dump(DataOutputStream dos) throws IOException { | |||
dos.writeShort(nameIdx); // u2 name of the element | |||
value.dump(dos); | |||
} | |||
public int getNameIndex() { | |||
return nameIdx; | |||
} | |||
public final String getNameString() { | |||
ConstantUtf8 c = (ConstantUtf8)cpool.getConstant(nameIdx,Constants.CONSTANT_Utf8); | |||
return c.getBytes(); | |||
} | |||
public final ElementValue getValue() { | |||
return value; | |||
} | |||
public String toShortString() { | |||
StringBuffer result = new StringBuffer(); | |||
result.append(getNameString()).append("=").append(getValue().toShortString()); | |||
return result.toString(); | |||
} | |||
} |
@@ -0,0 +1,112 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2004 IBM | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Common Public License v1.0 | |||
* which accompanies this distribution and is available at | |||
* http://www.eclipse.org/legal/cpl-v10.html | |||
* | |||
* Contributors: | |||
* Andy Clement - initial implementation {date} | |||
* ******************************************************************/ | |||
package org.aspectj.apache.bcel.classfile.annotation; | |||
import java.io.DataInputStream; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
public abstract class ElementValue { | |||
protected int type; | |||
protected ConstantPool cpool; | |||
public String toString() { | |||
return stringifyValue(); | |||
} | |||
protected ElementValue(int type,ConstantPool cpool) { | |||
this.type = type; | |||
this.cpool = cpool; | |||
} | |||
public int getElementValueType() { | |||
return type; | |||
} | |||
public abstract String stringifyValue(); | |||
public abstract void dump(DataOutputStream dos) throws IOException; | |||
public static final int STRING = 's'; | |||
public static final int ENUM_CONSTANT = 'e'; | |||
public static final int CLASS = 'c'; | |||
public static final int ANNOTATION = '@'; | |||
public static final int ARRAY = '['; | |||
public static final int PRIMITIVE_INT = 'I'; | |||
public static final int PRIMITIVE_BYTE = 'B'; | |||
public static final int PRIMITIVE_CHAR = 'C'; | |||
public static final int PRIMITIVE_DOUBLE = 'D'; | |||
public static final int PRIMITIVE_FLOAT = 'F'; | |||
public static final int PRIMITIVE_LONG = 'J'; | |||
public static final int PRIMITIVE_SHORT = 'S'; | |||
public static final int PRIMITIVE_BOOLEAN= 'Z'; | |||
public static ElementValue readElementValue(DataInputStream dis,ConstantPool cpool) throws IOException { | |||
int type= dis.readUnsignedByte(); | |||
switch (type) { | |||
case 'B': // byte | |||
return new SimpleElementValue(PRIMITIVE_BYTE,dis.readUnsignedShort(),cpool); | |||
case 'C': // char | |||
return new SimpleElementValue(PRIMITIVE_CHAR,dis.readUnsignedShort(),cpool); | |||
case 'D': // double | |||
return new SimpleElementValue(PRIMITIVE_DOUBLE,dis.readUnsignedShort(),cpool); | |||
case 'F': // float | |||
return new SimpleElementValue(PRIMITIVE_FLOAT,dis.readUnsignedShort(),cpool); | |||
case 'I': // int | |||
return new SimpleElementValue(PRIMITIVE_INT,dis.readUnsignedShort(),cpool); | |||
case 'J': // long | |||
return new SimpleElementValue(PRIMITIVE_LONG,dis.readUnsignedShort(),cpool); | |||
case 'S': // short | |||
return new SimpleElementValue(PRIMITIVE_SHORT,dis.readUnsignedShort(),cpool); | |||
case 'Z': // boolean | |||
return new SimpleElementValue(PRIMITIVE_BOOLEAN,dis.readUnsignedShort(),cpool); | |||
case 's': // String | |||
return new SimpleElementValue(STRING,dis.readUnsignedShort(),cpool); | |||
case 'e': // Enum constant | |||
return new EnumElementValue(ENUM_CONSTANT,dis.readUnsignedShort(),dis.readUnsignedShort(),cpool); | |||
case 'c': // Class | |||
return new ClassElementValue(CLASS,dis.readUnsignedShort(),cpool); | |||
//J5TODO: Should it be 'true' in the next statement? What difference does it make? Should it be | |||
// the same as the 'super annotation' in which we are contained? | |||
case '@': // Annotation | |||
return new AnnotationElementValue(ANNOTATION,Annotation.read(dis,cpool,true),cpool); | |||
case '[': // Array | |||
int numArrayVals = dis.readUnsignedShort(); | |||
List arrayVals = new ArrayList(); | |||
ElementValue[] evalues = new ElementValue[numArrayVals]; | |||
for (int j=0;j<numArrayVals;j++) { | |||
evalues[j] = ElementValue.readElementValue(dis,cpool); | |||
} | |||
return new ArrayElementValue(ARRAY,evalues,cpool); | |||
default: | |||
throw new RuntimeException("Unexpected element value kind in annotation: "+type); | |||
} | |||
} | |||
public String toShortString() { | |||
StringBuffer result = new StringBuffer(); | |||
result.append(stringifyValue()); | |||
return result.toString(); | |||
} | |||
} |
@@ -0,0 +1,63 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2004 IBM | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Common Public License v1.0 | |||
* which accompanies this distribution and is available at | |||
* http://www.eclipse.org/legal/cpl-v10.html | |||
* | |||
* Contributors: | |||
* Andy Clement - initial implementation {date} | |||
* ******************************************************************/ | |||
package org.aspectj.apache.bcel.classfile.annotation; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import org.aspectj.apache.bcel.Constants; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
import org.aspectj.apache.bcel.classfile.ConstantUtf8; | |||
import org.aspectj.apache.bcel.classfile.Utility; | |||
public class EnumElementValue extends ElementValue { | |||
// For enum types, these two indices point to the type and value | |||
private int typeIdx; | |||
private int valueIdx; | |||
public EnumElementValue(int type,int typeIdx,int valueIdx,ConstantPool cpool) { | |||
super(type,cpool); | |||
if (type != ENUM_CONSTANT) | |||
throw new RuntimeException("Only element values of type enum can be built with this ctor"); | |||
this.typeIdx = typeIdx; | |||
this.valueIdx= valueIdx; | |||
} | |||
public void dump(DataOutputStream dos) throws IOException { | |||
dos.writeByte(type); // u1 type of value (ENUM_CONSTANT == 'e') | |||
dos.writeShort(typeIdx); // u2 | |||
dos.writeShort(valueIdx); // u2 | |||
} | |||
public String stringifyValue() { | |||
ConstantUtf8 cu8 = (ConstantUtf8)cpool.getConstant(valueIdx,Constants.CONSTANT_Utf8); | |||
return cu8.getBytes(); | |||
} | |||
public String getEnumTypeString() { | |||
ConstantUtf8 cu8 = (ConstantUtf8)cpool.getConstant(typeIdx,Constants.CONSTANT_Utf8); | |||
return Utility.signatureToString(cu8.getBytes()); | |||
} | |||
public String getEnumValueString() { | |||
ConstantUtf8 cu8 = (ConstantUtf8)cpool.getConstant(valueIdx,Constants.CONSTANT_Utf8); | |||
return cu8.getBytes(); | |||
} | |||
public int getValueIndex() { return valueIdx;} | |||
public int getTypeIndex() { return typeIdx; } | |||
} |
@@ -0,0 +1,83 @@ | |||
package org.aspectj.apache.bcel.classfile.annotation; | |||
import java.io.ByteArrayInputStream; | |||
import java.io.DataInputStream; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import org.aspectj.apache.bcel.classfile.Attribute; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
public abstract class RuntimeAnnotations extends Attribute { | |||
private List /*Annotation*/ annotations; | |||
private boolean visible; | |||
// Keep just a byte stream of the data until someone actually asks for it | |||
private boolean inflated = false; | |||
private byte[] annotation_data; | |||
public RuntimeAnnotations(byte attrid, boolean visible, | |||
int nameIdx, int len, | |||
ConstantPool cpool) { | |||
super(attrid,nameIdx,len,cpool); | |||
this.visible = visible; | |||
annotations = new ArrayList(); | |||
} | |||
public RuntimeAnnotations(byte attrid,boolean visible,int nameIdx,int len,byte[] data,ConstantPool cpool) { | |||
super(attrid,nameIdx,len,cpool); | |||
this.visible = visible; | |||
annotations = new ArrayList(); | |||
annotation_data = data; | |||
} | |||
public List getAnnotations() { | |||
if (!inflated) inflate(); | |||
return annotations; | |||
} | |||
public boolean areVisible() { | |||
return visible; | |||
} | |||
protected void readAnnotations(DataInputStream dis,ConstantPool cpool) throws IOException { | |||
annotation_data = new byte[length]; | |||
dis.read(annotation_data,0,length); | |||
} | |||
private void inflate() { | |||
try { | |||
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(annotation_data)); | |||
int numberOfAnnotations = dis.readUnsignedShort(); | |||
for (int i = 0 ;i<numberOfAnnotations;i++) { | |||
annotations.add(Annotation.read(dis,getConstantPool(),visible)); | |||
} | |||
dis.close(); | |||
inflated = true; | |||
} catch (IOException ioe) { | |||
throw new RuntimeException("Unabled to inflate annotation data, badly formed? "); | |||
} | |||
} | |||
protected void writeAnnotations(DataOutputStream dos) throws IOException { | |||
if (!inflated) { | |||
dos.write(annotation_data,0,length); | |||
} else { | |||
dos.writeShort(annotations.size()); | |||
for (Iterator i = annotations.iterator(); i.hasNext();) { | |||
Annotation ann = (Annotation) i.next(); | |||
ann.dump(dos); | |||
} | |||
} | |||
} | |||
/** FOR TESTING ONLY: Tells you if the annotations have been inflated to an object graph */ | |||
public boolean isInflated() { | |||
return inflated; | |||
} | |||
} |
@@ -0,0 +1,40 @@ | |||
package org.aspectj.apache.bcel.classfile.annotation; | |||
import java.io.DataInputStream; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import org.aspectj.apache.bcel.Constants; | |||
import org.aspectj.apache.bcel.classfile.Attribute; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
import org.aspectj.apache.bcel.classfile.Visitor; | |||
public class RuntimeInvisibleAnnotations extends RuntimeAnnotations { | |||
public RuntimeInvisibleAnnotations(int nameIdx, int len, ConstantPool cpool) { | |||
super(Constants.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS, false, nameIdx, len, cpool); | |||
} | |||
public RuntimeInvisibleAnnotations(int nameIdx, int len, | |||
DataInputStream dis,ConstantPool cpool) throws IOException { | |||
this(nameIdx, len, cpool); | |||
readAnnotations(dis,cpool); | |||
} | |||
public RuntimeInvisibleAnnotations(int nameIndex, int len, byte[] rvaData,ConstantPool cpool) { | |||
super(Constants.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS,true,nameIndex,len,rvaData,cpool); | |||
} | |||
public void accept(Visitor v) { | |||
v.visitRuntimeInvisibleAnnotations(this); | |||
} | |||
public final void dump(DataOutputStream dos) throws IOException { | |||
super.dump(dos); | |||
writeAnnotations(dos); | |||
} | |||
public Attribute copy(ConstantPool constant_pool) { | |||
throw new RuntimeException("Not implemented yet!"); | |||
} | |||
} |
@@ -0,0 +1,34 @@ | |||
package org.aspectj.apache.bcel.classfile.annotation; | |||
import java.io.DataInputStream; | |||
import java.io.IOException; | |||
import org.aspectj.apache.bcel.Constants; | |||
import org.aspectj.apache.bcel.classfile.Attribute; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
import org.aspectj.apache.bcel.classfile.Visitor; | |||
public class RuntimeInvisibleParameterAnnotations extends RuntimeParameterAnnotations { | |||
public RuntimeInvisibleParameterAnnotations(int nameIdx, int len, ConstantPool cpool) { | |||
super(Constants.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, false, nameIdx, len, cpool); | |||
} | |||
public RuntimeInvisibleParameterAnnotations(int nameIdx, int len, | |||
DataInputStream dis,ConstantPool cpool) throws IOException { | |||
this(nameIdx, len, cpool); | |||
readParameterAnnotations(dis,cpool); | |||
} | |||
public RuntimeInvisibleParameterAnnotations(int nameIndex, int len, byte[] rvaData,ConstantPool cpool) { | |||
super(Constants.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS,true,nameIndex,len,rvaData,cpool); | |||
} | |||
public void accept(Visitor v) { | |||
v.visitRuntimeInvisibleParameterAnnotations(this); | |||
} | |||
public Attribute copy(ConstantPool constant_pool) { | |||
throw new RuntimeException("Not implemented yet!"); | |||
} | |||
} |
@@ -0,0 +1,110 @@ | |||
package org.aspectj.apache.bcel.classfile.annotation; | |||
import java.io.ByteArrayInputStream; | |||
import java.io.DataInputStream; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.aspectj.apache.bcel.classfile.Attribute; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
public abstract class RuntimeParameterAnnotations extends Attribute { | |||
private List /*Annotation[]*/ parameterAnnotations; | |||
private boolean visible; | |||
// Keep just a byte stream of the data until someone actually asks for it | |||
private boolean inflated = false; | |||
private byte[] annotation_data; | |||
public RuntimeParameterAnnotations(byte attrid, boolean visible, | |||
int nameIdx, int len, ConstantPool cpool) { | |||
super(attrid,nameIdx,len,cpool); | |||
this.visible = visible; | |||
parameterAnnotations = new ArrayList(); | |||
} | |||
public RuntimeParameterAnnotations(byte attrid,boolean visible,int nameIdx,int len,byte[] data,ConstantPool cpool) { | |||
super(attrid,nameIdx,len,cpool); | |||
this.visible = visible; | |||
parameterAnnotations = new ArrayList(); | |||
annotation_data = data; | |||
} | |||
public final void dump(DataOutputStream dos) throws IOException { | |||
super.dump(dos); | |||
writeAnnotations(dos); | |||
} | |||
public Attribute copy(ConstantPool constant_pool) { | |||
throw new RuntimeException("Not implemented yet!"); | |||
} | |||
/** Return a list of Annotation[] - each list entry contains the annotations for one parameter */ | |||
public List /*Annotation[]*/ getParameterAnnotations() { | |||
if (!inflated) inflate(); | |||
return parameterAnnotations; | |||
} | |||
public Annotation[] getAnnotationsOnParameter(int parameterIndex) { | |||
if (!inflated) inflate(); | |||
return (Annotation[])parameterAnnotations.get(parameterIndex); | |||
} | |||
public boolean areVisible() { | |||
return visible; | |||
} | |||
protected void readParameterAnnotations(DataInputStream dis,ConstantPool cpool) throws IOException { | |||
annotation_data = new byte[length]; | |||
dis.read(annotation_data,0,length); | |||
} | |||
private void inflate() { | |||
try { | |||
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(annotation_data)); | |||
int numParameters = dis.readUnsignedByte(); | |||
for (int i=0; i<numParameters; i++) { | |||
int numAnnotations = dis.readUnsignedShort(); | |||
Annotation[] annotations = new Annotation[numAnnotations]; | |||
for (int j=0; j<numAnnotations; j++) { | |||
annotations[j] = Annotation.read(dis,getConstantPool(),visible); | |||
} | |||
parameterAnnotations.add(annotations); | |||
} | |||
inflated = true; | |||
} catch (IOException ioe) { | |||
throw new RuntimeException("Unabled to inflate annotation data, badly formed?"); | |||
} | |||
} | |||
protected void writeAnnotations(DataOutputStream dos) throws IOException { | |||
if (!inflated) { | |||
dos.write(annotation_data,0,length); | |||
} else { | |||
dos.writeByte(parameterAnnotations.size()); | |||
for (int i=0; i<parameterAnnotations.size(); i++) { | |||
Annotation[] annotations = (Annotation[])parameterAnnotations.get(i); | |||
dos.writeShort(annotations.length); | |||
for (int j=0; j<annotations.length;j++) { | |||
annotations[j].dump(dos); | |||
} | |||
} | |||
} | |||
} | |||
/** FOR TESTING ONLY: Tells you if the annotations have been inflated to an object graph */ | |||
public boolean isInflated() { | |||
return inflated; | |||
} | |||
public String toString() { | |||
return "Runtime"+(visible?"Visible":"Invisible")+"ParameterAnnotations ["+(inflated?"inflated":"not yet inflated")+"]"; | |||
} | |||
} |
@@ -0,0 +1,40 @@ | |||
package org.aspectj.apache.bcel.classfile.annotation; | |||
import java.io.DataInputStream; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import org.aspectj.apache.bcel.Constants; | |||
import org.aspectj.apache.bcel.classfile.Attribute; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
import org.aspectj.apache.bcel.classfile.Visitor; | |||
public class RuntimeVisibleAnnotations extends RuntimeAnnotations { | |||
public RuntimeVisibleAnnotations(int nameIdx, int len, ConstantPool cpool) { | |||
super(Constants.ATTR_RUNTIME_VISIBLE_ANNOTATIONS, true, nameIdx, len, cpool); | |||
} | |||
public RuntimeVisibleAnnotations(int nameIdx, int len, | |||
DataInputStream dis,ConstantPool cpool) throws IOException { | |||
this(nameIdx, len, cpool); | |||
readAnnotations(dis,cpool); | |||
} | |||
public RuntimeVisibleAnnotations(int nameIndex, int len, byte[] rvaData,ConstantPool cpool) { | |||
super(Constants.ATTR_RUNTIME_VISIBLE_ANNOTATIONS,true,nameIndex,len,rvaData,cpool); | |||
} | |||
public void accept(Visitor v) { | |||
v.visitRuntimeVisibleAnnotations(this); | |||
} | |||
public final void dump(DataOutputStream dos) throws IOException { | |||
super.dump(dos); | |||
writeAnnotations(dos); | |||
} | |||
public Attribute copy(ConstantPool constant_pool) { | |||
throw new RuntimeException("Not implemented yet!"); | |||
} | |||
} |
@@ -0,0 +1,34 @@ | |||
package org.aspectj.apache.bcel.classfile.annotation; | |||
import java.io.DataInputStream; | |||
import java.io.IOException; | |||
import org.aspectj.apache.bcel.Constants; | |||
import org.aspectj.apache.bcel.classfile.Attribute; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
import org.aspectj.apache.bcel.classfile.Visitor; | |||
public class RuntimeVisibleParameterAnnotations extends RuntimeParameterAnnotations { | |||
public RuntimeVisibleParameterAnnotations(int nameIdx, int len, ConstantPool cpool) { | |||
super(Constants.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, true, nameIdx, len, cpool); | |||
} | |||
public RuntimeVisibleParameterAnnotations(int nameIndex, int len, byte[] rvaData,ConstantPool cpool) { | |||
super(Constants.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS,true,nameIndex,len,rvaData,cpool); | |||
} | |||
public RuntimeVisibleParameterAnnotations(int nameIdx, int len, | |||
DataInputStream dis,ConstantPool cpool) throws IOException { | |||
this(nameIdx, len, cpool); | |||
readParameterAnnotations(dis,cpool); | |||
} | |||
public void accept(Visitor v) { | |||
v.visitRuntimeVisibleParameterAnnotations(this); | |||
} | |||
public Attribute copy(ConstantPool constant_pool) { | |||
throw new RuntimeException("Not implemented yet!"); | |||
} | |||
} |
@@ -0,0 +1,119 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2004 IBM | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Common Public License v1.0 | |||
* which accompanies this distribution and is available at | |||
* http://www.eclipse.org/legal/cpl-v10.html | |||
* | |||
* Contributors: | |||
* Andy Clement - initial implementation {date} | |||
* ******************************************************************/ | |||
package org.aspectj.apache.bcel.classfile.annotation; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import org.aspectj.apache.bcel.Constants; | |||
import org.aspectj.apache.bcel.classfile.ConstantDouble; | |||
import org.aspectj.apache.bcel.classfile.ConstantFloat; | |||
import org.aspectj.apache.bcel.classfile.ConstantInteger; | |||
import org.aspectj.apache.bcel.classfile.ConstantLong; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
import org.aspectj.apache.bcel.classfile.ConstantUtf8; | |||
/** | |||
* An element value representing a primitive or string value. | |||
*/ | |||
public class SimpleElementValue extends ElementValue { | |||
// For primitive types and string type, this points to the value entry in the cpool | |||
// For 'class' this points to the class entry in the cpool | |||
private int idx; | |||
protected SimpleElementValue(int type,int idx,ConstantPool cpool) { | |||
super(type,cpool); | |||
this.idx = idx; | |||
} | |||
public int getIndex() { | |||
return idx; | |||
} | |||
public String getValueString() { | |||
if (type != STRING) | |||
throw new RuntimeException("Dont call getValueString() on a non STRING ElementValue"); | |||
ConstantUtf8 c = (ConstantUtf8)cpool.getConstant(idx,Constants.CONSTANT_Utf8); | |||
return c.getBytes(); | |||
} | |||
public int getValueInt() { | |||
if (type != PRIMITIVE_INT) | |||
throw new RuntimeException("Dont call getValueString() on a non STRING ElementValue"); | |||
ConstantInteger c = (ConstantInteger)cpool.getConstant(idx,Constants.CONSTANT_Integer); | |||
return c.getBytes(); | |||
} | |||
public String toString() { | |||
return stringifyValue(); | |||
} | |||
// Whatever kind of value it is, return it as a string | |||
public String stringifyValue() { | |||
switch (type) { | |||
case PRIMITIVE_INT: | |||
ConstantInteger c = (ConstantInteger)cpool.getConstant(idx,Constants.CONSTANT_Integer); | |||
return Integer.toString(c.getBytes()); | |||
case PRIMITIVE_LONG: | |||
ConstantLong j = (ConstantLong)cpool.getConstant(idx,Constants.CONSTANT_Long); | |||
return Long.toString(j.getBytes()); | |||
case PRIMITIVE_DOUBLE: | |||
ConstantDouble d = (ConstantDouble)cpool.getConstant(idx,Constants.CONSTANT_Double); | |||
return Double.toString(d.getBytes()); | |||
case PRIMITIVE_FLOAT: | |||
ConstantFloat f = (ConstantFloat)cpool.getConstant(idx,Constants.CONSTANT_Float); | |||
return Float.toString(f.getBytes()); | |||
case PRIMITIVE_SHORT: | |||
ConstantInteger s = (ConstantInteger)cpool.getConstant(idx,Constants.CONSTANT_Integer); | |||
return Integer.toString(s.getBytes()); | |||
case PRIMITIVE_BYTE: | |||
ConstantInteger b = (ConstantInteger)cpool.getConstant(idx,Constants.CONSTANT_Integer); | |||
return Integer.toString(b.getBytes()); | |||
case PRIMITIVE_CHAR: | |||
ConstantInteger ch = (ConstantInteger)cpool.getConstant(idx,Constants.CONSTANT_Integer); | |||
return Integer.toString(ch.getBytes()); | |||
case PRIMITIVE_BOOLEAN: | |||
ConstantInteger bo = (ConstantInteger)cpool.getConstant(idx,Constants.CONSTANT_Integer); | |||
if (bo.getBytes() == 0) return "false"; | |||
if (bo.getBytes() != 0) return "true"; | |||
case STRING: | |||
ConstantUtf8 cu8 = (ConstantUtf8)cpool.getConstant(idx,Constants.CONSTANT_Utf8); | |||
return cu8.getBytes(); | |||
default: | |||
throw new RuntimeException("SimpleElementValue class does not know how to stringify type "+type); | |||
} | |||
} | |||
public void dump(DataOutputStream dos) throws IOException { | |||
dos.writeByte(type); // u1 kind of value | |||
switch (type) { | |||
case PRIMITIVE_INT: | |||
case PRIMITIVE_BYTE: | |||
case PRIMITIVE_CHAR: | |||
case PRIMITIVE_FLOAT: | |||
case PRIMITIVE_LONG: | |||
case PRIMITIVE_BOOLEAN: | |||
case PRIMITIVE_SHORT: | |||
case PRIMITIVE_DOUBLE: | |||
case STRING: | |||
dos.writeShort(idx); | |||
break; | |||
default: | |||
throw new RuntimeException("SimpleElementValue doesnt know how to write out type "+type); | |||
} | |||
} | |||
} |
@@ -0,0 +1,55 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2004 IBM | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Common Public License v1.0 | |||
* which accompanies this distribution and is available at | |||
* http://www.eclipse.org/legal/cpl-v10.html | |||
* | |||
* Contributors: | |||
* Andy Clement - initial implementation {date} | |||
* ******************************************************************/ | |||
package org.aspectj.apache.bcel.generic.annotation; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import org.aspectj.apache.bcel.classfile.annotation.AnnotationElementValue; | |||
import org.aspectj.apache.bcel.generic.ConstantPoolGen; | |||
public class AnnotationElementValueGen extends ElementValueGen { | |||
// For annotation element values, this is the annotation | |||
private AnnotationGen a; | |||
public AnnotationElementValueGen(AnnotationGen a,ConstantPoolGen cpool) { | |||
super(ANNOTATION,cpool); | |||
this.a = a; | |||
} | |||
public AnnotationElementValueGen(int type, AnnotationGen annotation, ConstantPoolGen cpool) { | |||
super(type,cpool); | |||
if (type != ANNOTATION) | |||
throw new RuntimeException("Only element values of type annotation can be built with this ctor"); | |||
this.a = annotation; | |||
} | |||
public AnnotationElementValueGen(AnnotationElementValue value, ConstantPoolGen cpool) { | |||
super(ANNOTATION,cpool); | |||
a = new AnnotationGen(value.getAnnotation(),cpool); | |||
} | |||
public void dump(DataOutputStream dos) throws IOException { | |||
dos.writeByte(type); // u1 type of value (ANNOTATION == '@') | |||
a.dump(dos); | |||
} | |||
public String stringifyValue() { | |||
throw new RuntimeException("Not implemented yet"); | |||
} | |||
public AnnotationGen getAnnotation() { return a;} | |||
} |
@@ -0,0 +1,148 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2004 IBM Corporation | |||
* | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Common Public License v1.0 | |||
* which accompanies this distribution and is available at | |||
* http://www.eclipse.org/legal/cpl-v10.html | |||
* | |||
* Contributors: | |||
* Andy Clement initial implementation | |||
* ******************************************************************/ | |||
package org.aspectj.apache.bcel.generic.annotation; | |||
import java.io.DataInputStream; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import org.aspectj.apache.bcel.classfile.ConstantUtf8; | |||
import org.aspectj.apache.bcel.classfile.annotation.Annotation; | |||
import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePair; | |||
import org.aspectj.apache.bcel.generic.ConstantPoolGen; | |||
import org.aspectj.apache.bcel.generic.ObjectType; | |||
public class AnnotationGen { | |||
private int typeIndex; | |||
private List /* ElementNameValuePairGen */ evs; | |||
private ConstantPoolGen cpool; | |||
private boolean isRuntimeVisible = false; | |||
/** | |||
* Here we are taking a fixed annotation of type Annotation and building a | |||
* modifiable AnnotationGen object. The ConstantPool entries should already | |||
* be correct, we could assert that ... | |||
* We need to copy the type and the element name value pairs and the visibility. | |||
*/ | |||
public AnnotationGen(Annotation a,ConstantPoolGen cpool) { | |||
this.cpool = cpool; | |||
// Could assert a.getTypeSignature() == (ConstantUtf8)cpool.getConstant(a.getTypeIndex())).getBytes() | |||
typeIndex = a.getTypeIndex(); | |||
isRuntimeVisible = a.isRuntimeVisible(); | |||
evs = copyValues(a.getValues(),cpool); | |||
} | |||
private List copyValues(List in,ConstantPoolGen cpool) { | |||
List out = new ArrayList(); | |||
for (Iterator iter = in.iterator(); iter.hasNext();) { | |||
ElementNameValuePair nvp = (ElementNameValuePair) iter.next(); | |||
out.add(new ElementNameValuePairGen(nvp,cpool)); | |||
} | |||
return out; | |||
} | |||
private AnnotationGen(ConstantPoolGen cpool) { | |||
this.cpool = cpool; | |||
} | |||
public AnnotationGen(ObjectType type,List /*ElementNameValuePairGen*/ elements,boolean vis,ConstantPoolGen cpool) { | |||
this.cpool = cpool; | |||
this.typeIndex = cpool.addUtf8(type.getSignature()); | |||
evs = elements; | |||
isRuntimeVisible = vis; | |||
} | |||
public static AnnotationGen read(DataInputStream dis,ConstantPoolGen cpool,boolean b) throws IOException { | |||
AnnotationGen a = new AnnotationGen(cpool); | |||
a.typeIndex = dis.readUnsignedShort(); | |||
int elemValuePairCount = dis.readUnsignedShort(); | |||
for (int i=0;i<elemValuePairCount;i++) { | |||
int nidx = dis.readUnsignedShort(); | |||
a.addElementNameValuePair( | |||
new ElementNameValuePairGen(nidx,ElementValueGen.readElementValue(dis,cpool),cpool)); | |||
} | |||
a.isRuntimeVisible(b); | |||
return a; | |||
} | |||
public void dump(DataOutputStream dos) throws IOException { | |||
dos.writeShort(typeIndex); // u2 index of type name in cpool | |||
dos.writeShort(evs.size()); // u2 element_value pair count | |||
for (int i = 0 ; i<evs.size();i++) { | |||
ElementNameValuePairGen envp = (ElementNameValuePairGen) evs.get(i); | |||
envp.dump(dos); | |||
} | |||
} | |||
public void addElementNameValuePair(ElementNameValuePairGen evp) { | |||
if (evs == null) evs = new ArrayList(); | |||
evs.add(evp); | |||
} | |||
public int getTypeIndex() { | |||
return typeIndex; | |||
} | |||
public final String getTypeSignature() { | |||
// ConstantClass c = (ConstantClass)cpool.getConstant(typeIndex); | |||
ConstantUtf8 utf8 = (ConstantUtf8)cpool.getConstant(typeIndex/*c.getNameIndex()*/); | |||
return utf8.getBytes(); | |||
} | |||
public final String getTypeName() { | |||
return getTypeSignature();// BCELBUG: Should I use this instead? Utility.signatureToString(getTypeSignature()); | |||
} | |||
/** | |||
* Returns list of ElementNameValuePair objects | |||
*/ | |||
public List getValues() { | |||
return evs; | |||
} | |||
public String toString() { | |||
StringBuffer s = new StringBuffer(); | |||
s.append("AnnotationGen:["+getTypeName()+" #"+evs.size()+" {"); | |||
for (int i = 0; i<evs.size();i++) { | |||
s.append(evs.get(i)); | |||
if (i+1<evs.size()) s.append(","); | |||
} | |||
s.append("}]"); | |||
return s.toString(); | |||
} | |||
public String toShortString() { | |||
StringBuffer s = new StringBuffer(); | |||
s.append("@"+getTypeName()+"("); | |||
for (int i = 0; i<evs.size();i++) { | |||
s.append(evs.get(i)); | |||
if (i+1<evs.size()) s.append(","); | |||
} | |||
s.append(")"); | |||
return s.toString(); | |||
} | |||
private void isRuntimeVisible(boolean b) { | |||
isRuntimeVisible = b; | |||
} | |||
public boolean isRuntimeVisible() { | |||
return isRuntimeVisible; | |||
} | |||
} |
@@ -0,0 +1,87 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2004 IBM | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Common Public License v1.0 | |||
* which accompanies this distribution and is available at | |||
* http://www.eclipse.org/legal/cpl-v10.html | |||
* | |||
* Contributors: | |||
* Andy Clement - initial implementation {date} | |||
* ******************************************************************/ | |||
package org.aspectj.apache.bcel.generic.annotation; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import org.aspectj.apache.bcel.classfile.annotation.ArrayElementValue; | |||
import org.aspectj.apache.bcel.classfile.annotation.ElementValue; | |||
import org.aspectj.apache.bcel.generic.ConstantPoolGen; | |||
public class ArrayElementValueGen extends ElementValueGen { | |||
// J5TODO: Should we make this an array or a list? A list would be easier to modify ... | |||
private List /*ElementValueGen*/ evalues; | |||
public ArrayElementValueGen(ConstantPoolGen cp) { | |||
super(ARRAY,cp); | |||
evalues = new ArrayList(); | |||
} | |||
public ArrayElementValueGen(int type, ElementValueGen[] datums, ConstantPoolGen cpool) { | |||
super(type,cpool); | |||
if (type != ARRAY) | |||
throw new RuntimeException("Only element values of type array can be built with this ctor"); | |||
this.evalues = new ArrayList(); | |||
for (int i = 0; i < datums.length; i++) { | |||
evalues.add(datums[i]); | |||
} | |||
} | |||
/** | |||
* @param value | |||
* @param cpool | |||
*/ | |||
public ArrayElementValueGen(ArrayElementValue value, ConstantPoolGen cpool) { | |||
super(ARRAY,cpool); | |||
evalues = new ArrayList(); | |||
ElementValue[] in = value.getElementValuesArray(); | |||
for (int i = 0; i < in.length; i++) { | |||
evalues.add(ElementValueGen.copy(in[i],cpool)); | |||
} | |||
} | |||
public void dump(DataOutputStream dos) throws IOException { | |||
dos.writeByte(type); // u1 type of value (ARRAY == '[') | |||
dos.writeShort(evalues.size()); | |||
for (Iterator iter = evalues.iterator(); iter.hasNext();) { | |||
ElementValueGen element = (ElementValueGen) iter.next(); | |||
element.dump(dos); | |||
} | |||
} | |||
public String stringifyValue() { | |||
StringBuffer sb = new StringBuffer(); | |||
sb.append("["); | |||
for (Iterator iter = evalues.iterator(); iter.hasNext();) { | |||
ElementValueGen element = (ElementValueGen) iter.next(); | |||
sb.append(element.stringifyValue()); | |||
if (iter.hasNext()) sb.append(","); | |||
} | |||
sb.append("]"); | |||
return sb.toString(); | |||
} | |||
public List getElementValues() { return evalues;} | |||
public int getElementValuesSize() { return evalues.size();} | |||
public void addElement(ElementValueGen gen) { | |||
evalues.add(gen); | |||
} | |||
} |
@@ -0,0 +1,59 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2004 IBM | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Common Public License v1.0 | |||
* which accompanies this distribution and is available at | |||
* http://www.eclipse.org/legal/cpl-v10.html | |||
* | |||
* Contributors: | |||
* Andy Clement - initial implementation {date} | |||
* ******************************************************************/ | |||
package org.aspectj.apache.bcel.generic.annotation; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import org.aspectj.apache.bcel.classfile.ConstantClass; | |||
import org.aspectj.apache.bcel.classfile.ConstantUtf8; | |||
import org.aspectj.apache.bcel.generic.ConstantPoolGen; | |||
import org.aspectj.apache.bcel.generic.ObjectType; | |||
public class ClassElementValueGen extends ElementValueGen { | |||
// For primitive types and string type, this points to the value entry in the cpool | |||
// For 'class' this points to the class entry in the cpool | |||
private int idx; | |||
protected ClassElementValueGen(int typeIdx,ConstantPoolGen cpool) { | |||
super(ElementValueGen.CLASS,cpool); | |||
this.idx = typeIdx; | |||
} | |||
public ClassElementValueGen(ObjectType t,ConstantPoolGen cpool) { | |||
super(ElementValueGen.CLASS,cpool); | |||
this.idx = cpool.addClass(t); | |||
} | |||
public int getIndex() { | |||
return idx; | |||
} | |||
public String getClassString() { | |||
ConstantClass c = (ConstantClass)getConstantPool().getConstant(idx); | |||
ConstantUtf8 utf8 = (ConstantUtf8)getConstantPool().getConstant(c.getNameIndex()); | |||
return utf8.getBytes(); | |||
} | |||
public String stringifyValue() { | |||
return getClassString(); | |||
} | |||
public void dump(DataOutputStream dos) throws IOException { | |||
dos.writeByte(type); // u1 kind of value | |||
dos.writeShort(idx); | |||
} | |||
} |
@@ -0,0 +1,70 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2004 IBM | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Common Public License v1.0 | |||
* which accompanies this distribution and is available at | |||
* http://www.eclipse.org/legal/cpl-v10.html | |||
* | |||
* Contributors: | |||
* Andy Clement - initial implementation | |||
* ******************************************************************/ | |||
package org.aspectj.apache.bcel.generic.annotation; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import org.aspectj.apache.bcel.classfile.ConstantUtf8; | |||
import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePair; | |||
import org.aspectj.apache.bcel.generic.ConstantPoolGen; | |||
public class ElementNameValuePairGen { | |||
private int nameIdx; | |||
private ElementValueGen value; | |||
private ConstantPoolGen cpool; | |||
public ElementNameValuePairGen(ElementNameValuePair nvp, ConstantPoolGen cpool) { | |||
this.cpool = cpool; | |||
// J5ASSERT: | |||
// Could assert nvp.getNameString() points to the same thing as cpool.getConstant(nvp.getNameIndex()) | |||
nameIdx = nvp.getNameIndex(); | |||
value = ElementValueGen.copy(nvp.getValue(),cpool); | |||
} | |||
protected ElementNameValuePairGen(int idx,ElementValueGen value,ConstantPoolGen cpool) { | |||
this.nameIdx = idx; | |||
this.value = value; | |||
this.cpool = cpool; | |||
} | |||
public ElementNameValuePairGen(String name,ElementValueGen value,ConstantPoolGen cpool) { | |||
this.nameIdx = cpool.addUtf8(name); | |||
this.value = value; | |||
this.cpool = cpool; | |||
} | |||
protected void dump(DataOutputStream dos) throws IOException { | |||
dos.writeShort(nameIdx); // u2 name of the element | |||
value.dump(dos); | |||
} | |||
public int getNameIndex() { | |||
return nameIdx; | |||
} | |||
public final String getNameString() { | |||
// ConstantString cu8 = (ConstantString)cpool.getConstant(nameIdx); | |||
return ((ConstantUtf8)cpool.getConstant(nameIdx)).getBytes(); | |||
} | |||
public final ElementValueGen getValue() { | |||
return value; | |||
} | |||
public String toString() { | |||
return "ElementNameValuePair:["+getNameString()+"="+value.stringifyValue()+"]"; | |||
} | |||
} |
@@ -0,0 +1,137 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2004 IBM | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Common Public License v1.0 | |||
* which accompanies this distribution and is available at | |||
* http://www.eclipse.org/legal/cpl-v10.html | |||
* | |||
* Contributors: | |||
* Andy Clement - initial implementation {date} | |||
* ******************************************************************/ | |||
package org.aspectj.apache.bcel.generic.annotation; | |||
import java.io.DataInputStream; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import org.aspectj.apache.bcel.classfile.annotation.AnnotationElementValue; | |||
import org.aspectj.apache.bcel.classfile.annotation.ArrayElementValue; | |||
import org.aspectj.apache.bcel.classfile.annotation.ElementValue; | |||
import org.aspectj.apache.bcel.classfile.annotation.EnumElementValue; | |||
import org.aspectj.apache.bcel.classfile.annotation.SimpleElementValue; | |||
import org.aspectj.apache.bcel.generic.ConstantPoolGen; | |||
public abstract class ElementValueGen { | |||
protected int type; | |||
protected ConstantPoolGen cpGen; | |||
protected ElementValueGen(int type,ConstantPoolGen cpGen) { | |||
this.type = type; | |||
this.cpGen = cpGen; | |||
} | |||
public int getElementValueType() { | |||
return type; | |||
} | |||
public abstract String stringifyValue(); | |||
public abstract void dump(DataOutputStream dos) throws IOException; | |||
public static final int STRING = 's'; | |||
public static final int ENUM_CONSTANT = 'e'; | |||
public static final int CLASS = 'c'; | |||
public static final int ANNOTATION = '@'; | |||
public static final int ARRAY = '['; | |||
public static final int PRIMITIVE_INT = 'I'; | |||
public static final int PRIMITIVE_BYTE = 'B'; | |||
public static final int PRIMITIVE_CHAR = 'C'; | |||
public static final int PRIMITIVE_DOUBLE = 'D'; | |||
public static final int PRIMITIVE_FLOAT = 'F'; | |||
public static final int PRIMITIVE_LONG = 'J'; | |||
public static final int PRIMITIVE_SHORT = 'S'; | |||
public static final int PRIMITIVE_BOOLEAN= 'Z'; | |||
public static ElementValueGen readElementValue(DataInputStream dis,ConstantPoolGen cpGen) throws IOException { | |||
int type= dis.readUnsignedByte(); | |||
switch (type) { | |||
case 'B': // byte | |||
return new SimpleElementValueGen(PRIMITIVE_BYTE,dis.readUnsignedShort(),cpGen); | |||
case 'C': // char | |||
return new SimpleElementValueGen(PRIMITIVE_CHAR,dis.readUnsignedShort(),cpGen); | |||
case 'D': // double | |||
return new SimpleElementValueGen(PRIMITIVE_DOUBLE,dis.readUnsignedShort(),cpGen); | |||
case 'F': // float | |||
return new SimpleElementValueGen(PRIMITIVE_FLOAT,dis.readUnsignedShort(),cpGen); | |||
case 'I': // int | |||
return new SimpleElementValueGen(PRIMITIVE_INT,dis.readUnsignedShort(),cpGen); | |||
case 'J': // long | |||
return new SimpleElementValueGen(PRIMITIVE_LONG,dis.readUnsignedShort(),cpGen); | |||
case 'S': // short | |||
return new SimpleElementValueGen(PRIMITIVE_SHORT,dis.readUnsignedShort(),cpGen); | |||
case 'Z': // boolean | |||
return new SimpleElementValueGen(PRIMITIVE_BOOLEAN,dis.readUnsignedShort(),cpGen); | |||
case 's': // String | |||
return new SimpleElementValueGen(STRING,dis.readUnsignedShort(),cpGen); | |||
case 'e': // Enum constant | |||
return new EnumElementValueGen(dis.readUnsignedShort(),dis.readUnsignedShort(),cpGen); | |||
case 'c': // Class | |||
return new ClassElementValueGen(dis.readUnsignedShort(),cpGen); | |||
// | |||
// case '@': // Annotation | |||
// return new AnnotationElementValueGen(ANNOTATION,Annotation.read(dis,cpGen),cpGen); | |||
// | |||
// case '[': // Array | |||
// int numArrayVals = dis.readUnsignedShort(); | |||
// List arrayVals = new ArrayList(); | |||
// ElementValue[] evalues = new ElementValue[numArrayVals]; | |||
// for (int j=0;j<numArrayVals;j++) { | |||
// evalues[j] = ElementValue.readElementValue(dis,cpGen); | |||
// } | |||
// return new ArrayElementValue(ARRAY,evalues,cpGen); | |||
default: | |||
throw new RuntimeException("Unexpected element value kind in annotation: "+type); | |||
} | |||
} | |||
protected ConstantPoolGen getConstantPool() { | |||
return cpGen; | |||
} | |||
/** | |||
* Creates an (modifiable) ElementValueGen copy of an (immutable) ElementValue - constant pool is assumed correct. | |||
*/ | |||
public static ElementValueGen copy(ElementValue value,ConstantPoolGen cpool) { | |||
switch (value.getElementValueType()) { | |||
case 'B': // byte | |||
case 'C': // char | |||
case 'D': // double | |||
case 'F': // float | |||
case 'I': // int | |||
case 'J': // long | |||
case 'S': // short | |||
case 'Z': // boolean | |||
case 's': // String | |||
return new SimpleElementValueGen((SimpleElementValue)value,cpool); | |||
case 'e': // Enum constant | |||
return new EnumElementValueGen((EnumElementValue)value,cpool); | |||
case '@': // Annotation | |||
return new AnnotationElementValueGen((AnnotationElementValue)value,cpool); | |||
case '[': // Array | |||
return new ArrayElementValueGen((ArrayElementValue)value,cpool); | |||
default: | |||
throw new RuntimeException("Not implemented yet! ("+value.getElementValueType()+")"); | |||
} | |||
} | |||
} |
@@ -0,0 +1,84 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2004 IBM | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Common Public License v1.0 | |||
* which accompanies this distribution and is available at | |||
* http://www.eclipse.org/legal/cpl-v10.html | |||
* | |||
* Contributors: | |||
* Andy Clement - initial implementation {date} | |||
* ******************************************************************/ | |||
package org.aspectj.apache.bcel.generic.annotation; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import org.aspectj.apache.bcel.classfile.ConstantClass; | |||
import org.aspectj.apache.bcel.classfile.ConstantString; | |||
import org.aspectj.apache.bcel.classfile.ConstantUtf8; | |||
import org.aspectj.apache.bcel.classfile.annotation.EnumElementValue; | |||
import org.aspectj.apache.bcel.generic.ConstantPoolGen; | |||
import org.aspectj.apache.bcel.generic.ObjectType; | |||
public class EnumElementValueGen extends ElementValueGen { | |||
// For enum types, these two indices point to the type and value | |||
private int typeIdx; | |||
private int valueIdx; | |||
/** | |||
* This ctor assumes the constant pool already contains the right type and value - | |||
* as indicated by typeIdx and valueIdx. This ctor is used for deserialization | |||
*/ | |||
protected EnumElementValueGen(int typeIdx,int valueIdx,ConstantPoolGen cpool) { | |||
super(ElementValueGen.ENUM_CONSTANT,cpool); | |||
if (type != ENUM_CONSTANT) | |||
throw new RuntimeException("Only element values of type enum can be built with this ctor"); | |||
this.typeIdx = typeIdx; | |||
this.valueIdx= valueIdx; | |||
} | |||
public EnumElementValueGen(ObjectType t,String value,ConstantPoolGen cpool) { | |||
super(ElementValueGen.ENUM_CONSTANT,cpool); | |||
typeIdx = cpool.addClass(t); | |||
valueIdx= cpool.addString(value); | |||
} | |||
public EnumElementValueGen(EnumElementValue value, ConstantPoolGen cpool) { | |||
super(ENUM_CONSTANT,cpool); | |||
typeIdx = value.getTypeIndex(); | |||
valueIdx = value.getValueIndex(); | |||
} | |||
public void dump(DataOutputStream dos) throws IOException { | |||
dos.writeByte(type); // u1 type of value (ENUM_CONSTANT == 'e') | |||
dos.writeShort(typeIdx); // u2 | |||
dos.writeShort(valueIdx); // u2 | |||
} | |||
public String stringifyValue() { | |||
ConstantString cu8 = (ConstantString)getConstantPool().getConstant(valueIdx); | |||
return ((ConstantUtf8)getConstantPool().getConstant(cu8.getStringIndex())).getBytes(); | |||
} | |||
// BCELBUG: Should we need to call utility.signatureToString() on the output here? | |||
public String getEnumTypeString() { | |||
ConstantClass cu8 = (ConstantClass)getConstantPool().getConstant(typeIdx); | |||
return ((ConstantUtf8)getConstantPool().getConstant(cu8.getNameIndex())).getBytes(); | |||
// return Utility.signatureToString(cu8.getBytes()); | |||
} | |||
public String getEnumValueString() { | |||
ConstantString cu8 = (ConstantString)getConstantPool().getConstant(valueIdx); | |||
return ((ConstantUtf8)getConstantPool().getConstant(cu8.getStringIndex())).getBytes(); | |||
} | |||
public int getValueIndex() { return valueIdx;} | |||
public int getTypeIndex() { return typeIdx; } | |||
} |
@@ -0,0 +1,173 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2004 IBM | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Common Public License v1.0 | |||
* which accompanies this distribution and is available at | |||
* http://www.eclipse.org/legal/cpl-v10.html | |||
* | |||
* Contributors: | |||
* Andy Clement - initial implementation {date} | |||
* ******************************************************************/ | |||
package org.aspectj.apache.bcel.generic.annotation; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import org.aspectj.apache.bcel.classfile.ConstantDouble; | |||
import org.aspectj.apache.bcel.classfile.ConstantFloat; | |||
import org.aspectj.apache.bcel.classfile.ConstantInteger; | |||
import org.aspectj.apache.bcel.classfile.ConstantLong; | |||
import org.aspectj.apache.bcel.classfile.ConstantUtf8; | |||
import org.aspectj.apache.bcel.classfile.annotation.SimpleElementValue; | |||
import org.aspectj.apache.bcel.generic.ConstantPoolGen; | |||
public class SimpleElementValueGen extends ElementValueGen { | |||
// For primitive types and string type, this points to the value entry in the cpGen | |||
// For 'class' this points to the class entry in the cpGen | |||
private int idx; | |||
// ctors for each supported type... type could be inferred but for now lets | |||
// force it to be passed | |||
/** | |||
* Protected ctor used for deserialization, doesn't *put* an entry in the constant pool, | |||
* assumes the one at the supplied index is correct. | |||
*/ | |||
protected SimpleElementValueGen(int type,int idx,ConstantPoolGen cpGen) { | |||
super(type,cpGen); | |||
this.idx = idx; | |||
} | |||
public SimpleElementValueGen(int type,ConstantPoolGen cpGen,int value) { | |||
super(type,cpGen); | |||
idx = cpGen.addInteger(value); | |||
} | |||
public SimpleElementValueGen(int type,ConstantPoolGen cpGen,long value) { | |||
super(type,cpGen); | |||
idx = cpGen.addLong(value); | |||
} | |||
public SimpleElementValueGen(int type,ConstantPoolGen cpGen,double value) { | |||
super(type,cpGen); | |||
idx = cpGen.addDouble(value); | |||
} | |||
public SimpleElementValueGen(int type,ConstantPoolGen cpGen,float value) { | |||
super(type,cpGen); | |||
idx = cpGen.addFloat(value); | |||
} | |||
public SimpleElementValueGen(int type,ConstantPoolGen cpGen,short value) { | |||
super(type,cpGen); | |||
idx = cpGen.addInteger(value); | |||
} | |||
public SimpleElementValueGen(int type,ConstantPoolGen cpGen,byte value) { | |||
super(type,cpGen); | |||
idx = cpGen.addInteger(value); | |||
} | |||
public SimpleElementValueGen(int type,ConstantPoolGen cpGen,char value) { | |||
super(type,cpGen); | |||
idx = cpGen.addInteger(value); | |||
} | |||
public SimpleElementValueGen(int type,ConstantPoolGen cpGen,boolean value) { | |||
super(type,cpGen); | |||
if (value) idx = cpGen.addInteger(1); | |||
else idx = cpGen.addInteger(0); | |||
} | |||
public SimpleElementValueGen(int type,ConstantPoolGen cpGen,String value) { | |||
super(type,cpGen); | |||
idx = cpGen.addUtf8(value); | |||
} | |||
public SimpleElementValueGen(SimpleElementValue value,ConstantPoolGen cpool) { | |||
super(value.getElementValueType(),cpool); | |||
// J5ASSERT: Could assert value.stringifyValue() is the same as | |||
// cpool.getConstant(SimpleElementValuevalue.getIndex()) | |||
idx = value.getIndex(); | |||
} | |||
public int getIndex() { | |||
return idx; | |||
} | |||
public String getValueString() { | |||
if (type != STRING) | |||
throw new RuntimeException("Dont call getValueString() on a non STRING ElementValue"); | |||
ConstantUtf8 c = (ConstantUtf8)cpGen.getConstant(idx); | |||
return c.getBytes(); | |||
} | |||
public int getValueInt() { | |||
if (type != PRIMITIVE_INT) | |||
throw new RuntimeException("Dont call getValueString() on a non STRING ElementValue"); | |||
ConstantInteger c = (ConstantInteger)cpGen.getConstant(idx); | |||
return c.getBytes(); | |||
} | |||
// Whatever kind of value it is, return it as a string | |||
public String stringifyValue() { | |||
switch (type) { | |||
case PRIMITIVE_INT: | |||
ConstantInteger c = (ConstantInteger)cpGen.getConstant(idx); | |||
return Integer.toString(c.getBytes()); | |||
case PRIMITIVE_LONG: | |||
ConstantLong j = (ConstantLong)cpGen.getConstant(idx); | |||
return Long.toString(j.getBytes()); | |||
case PRIMITIVE_DOUBLE: | |||
ConstantDouble d = (ConstantDouble)cpGen.getConstant(idx); | |||
return Double.toString(d.getBytes()); | |||
case PRIMITIVE_FLOAT: | |||
ConstantFloat f = (ConstantFloat)cpGen.getConstant(idx); | |||
return Float.toString(f.getBytes()); | |||
case PRIMITIVE_SHORT: | |||
ConstantInteger s = (ConstantInteger)cpGen.getConstant(idx); | |||
return Integer.toString(s.getBytes()); | |||
case PRIMITIVE_BYTE: | |||
ConstantInteger b = (ConstantInteger)cpGen.getConstant(idx); | |||
return Integer.toString(b.getBytes()); | |||
case PRIMITIVE_CHAR: | |||
ConstantInteger ch = (ConstantInteger)cpGen.getConstant(idx); | |||
return Integer.toString(ch.getBytes()); | |||
case PRIMITIVE_BOOLEAN: | |||
ConstantInteger bo = (ConstantInteger)cpGen.getConstant(idx); | |||
if (bo.getBytes() == 0) return "false"; | |||
if (bo.getBytes() != 0) return "true"; | |||
case STRING: | |||
ConstantUtf8 cu8 = (ConstantUtf8)cpGen.getConstant(idx); | |||
return cu8.getBytes(); | |||
default: | |||
throw new RuntimeException("SimpleElementValueGen class does not know how to stringify type "+type); | |||
} | |||
} | |||
public void dump(DataOutputStream dos) throws IOException { | |||
dos.writeByte(type); // u1 kind of value | |||
switch (type) { | |||
case PRIMITIVE_INT: | |||
case PRIMITIVE_BYTE: | |||
case PRIMITIVE_CHAR: | |||
case PRIMITIVE_FLOAT: | |||
case PRIMITIVE_LONG: | |||
case PRIMITIVE_BOOLEAN: | |||
case PRIMITIVE_SHORT: | |||
case PRIMITIVE_DOUBLE: | |||
case STRING: | |||
dos.writeShort(idx); | |||
break; | |||
default: | |||
throw new RuntimeException("SimpleElementValueGen doesnt know how to write out type "+type); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |