mirror of
https://github.com/eclipse-aspectj/aspectj.git
synced 2024-08-12 14:10:43 +02:00
590 lines
25 KiB
Java
590 lines
25 KiB
Java
/*******************************************************************************
|
|
* Copyright (c) 2004 IBM All rights reserved. This program and the accompanying
|
|
* materials are made available under the terms of the Eclipse Public License
|
|
* v1.0 which accompanies this distribution and is available at
|
|
* http://www.eclipse.org/legal/epl-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.ConstantPool;
|
|
import org.aspectj.apache.bcel.classfile.JavaClass;
|
|
import org.aspectj.apache.bcel.classfile.Method;
|
|
import org.aspectj.apache.bcel.classfile.annotation.AnnotationElementValue;
|
|
import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen;
|
|
import org.aspectj.apache.bcel.classfile.annotation.ArrayElementValue;
|
|
import org.aspectj.apache.bcel.classfile.annotation.NameValuePair;
|
|
import org.aspectj.apache.bcel.classfile.annotation.ElementValue;
|
|
import org.aspectj.apache.bcel.classfile.annotation.SimpleElementValue;
|
|
import org.aspectj.apache.bcel.generic.ArrayType;
|
|
import org.aspectj.apache.bcel.generic.ClassGen;
|
|
import org.aspectj.apache.bcel.generic.InstructionBranch;
|
|
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.InstructionLV;
|
|
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.Type;
|
|
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");
|
|
ConstantPool 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];
|
|
AnnotationGen[] 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");
|
|
ConstantPool 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];
|
|
AnnotationGen[] 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);
|
|
ConstantPool 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];
|
|
AnnotationGen[] p1annotations = m.getAnnotationsOnParameter(0);
|
|
AnnotationGen[] 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=LSimpleEnum;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);
|
|
ConstantPool 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];
|
|
AnnotationGen[] p1annotations = m.getAnnotationsOnParameter(0);
|
|
AnnotationGen[] 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=LSimpleEnum;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());
|
|
List<Attribute> as = mg.getAttributes();
|
|
assertTrue("Should be 2 (RIPA and RVPA) but there are "+mg.getAttributes().size(),mg.getAttributes().size()==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().size(),mg.getAttributes().size()==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, ConstantPool 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(InstructionFactory.createASTORE(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(InstructionFactory.createASTORE(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(InstructionFactory.PUSH(cp,"Andy"));
|
|
il.append(InstructionFactory.createASTORE(name));
|
|
|
|
// Upon normal execution we jump behind exception handler, the target
|
|
// address is not known yet.
|
|
|
|
InstructionBranch g = new InstructionBranch(Constants.GOTO);
|
|
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(InstructionFactory.createASTORE(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(InstructionFactory.PUSH(cp, "Hello, "));
|
|
il
|
|
.append(factory.createInvoke("java.lang.StringBuffer",
|
|
"<init>", Type.VOID, new Type[] { Type.STRING },
|
|
Constants.INVOKESPECIAL));
|
|
il.append(new InstructionLV(Constants.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, ConstantPool 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(InstructionFactory.createASTORE(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(InstructionFactory.createASTORE(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(InstructionFactory.PUSH(cp,"Andy"));
|
|
il.append(InstructionFactory.createASTORE(name));
|
|
|
|
// Upon normal execution we jump behind exception handler, the target
|
|
// address is not known yet.
|
|
|
|
InstructionBranch g = new InstructionBranch(Constants.GOTO);
|
|
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(InstructionFactory.createASTORE(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(InstructionFactory.PUSH(cp, "Hello, "));
|
|
il
|
|
.append(factory.createInvoke("java.lang.StringBuffer",
|
|
"<init>", Type.VOID, new Type[] { Type.STRING },
|
|
Constants.INVOKESPECIAL));
|
|
il.append(InstructionFactory.createALOAD(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,ConstantPool 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(ConstantPool cp) {
|
|
SimpleElementValue evg = new SimpleElementValue(
|
|
ElementValue.PRIMITIVE_INT, cp, 4);
|
|
|
|
NameValuePair nvGen = new NameValuePair("id", evg,cp);
|
|
|
|
ObjectType t = new ObjectType("SimpleAnnotation");
|
|
|
|
List<NameValuePair> elements = new ArrayList<NameValuePair>();
|
|
elements.add(nvGen);
|
|
|
|
AnnotationGen a = new AnnotationGen(t, elements,true, cp);
|
|
return a;
|
|
}
|
|
|
|
public AnnotationGen createCombinedAnnotation(ConstantPool cp) {
|
|
// Create an annotation instance
|
|
AnnotationGen a = createSimpleVisibleAnnotation(cp);
|
|
ArrayElementValue array = new ArrayElementValue(cp);
|
|
array.addElement(new AnnotationElementValue(a,cp));
|
|
NameValuePair nvp = new NameValuePair("value",array,cp);
|
|
List<NameValuePair> elements = new ArrayList<NameValuePair>();
|
|
elements.add(nvp);
|
|
return new AnnotationGen(new ObjectType("CombinedAnnotation"),elements,true,cp);
|
|
}
|
|
|
|
public AnnotationGen createSimpleInvisibleAnnotation(ConstantPool cp) {
|
|
SimpleElementValue evg = new SimpleElementValue(
|
|
ElementValue.PRIMITIVE_INT, cp, 4);
|
|
|
|
NameValuePair nvGen = new NameValuePair("id", evg,cp);
|
|
|
|
ObjectType t = new ObjectType("SimpleAnnotation");
|
|
|
|
List<NameValuePair> elements = new ArrayList<NameValuePair>();
|
|
elements.add(nvGen);
|
|
|
|
AnnotationGen a = new AnnotationGen(t, elements,false, cp);
|
|
return a;
|
|
}
|
|
protected void tearDown() throws Exception {
|
|
super.tearDown();
|
|
}
|
|
|
|
} |