I'm trying to instrument an existing class with code that uses a generated
class. I've prepared a small example to demonstrate what I mean and show you
where I got stuck.
Assume the following class exists :
| public class InstrumentMe {
|
| public InstrumentMe() {
| super();
| }
|
| public void printHelloWorld() {
| System.out.println("HelloWorld");
| }
| }
|
The main-method in the class below generates a new class 'DynamicallyGenerated'
on-the-fly and tries to instrument InstrumentMe#printHelloWorld() with a simple
statement 'System.out.println(DynamicallyGenerated.class);'
| import javassist.CannotCompileException;
| import javassist.ClassPool;
| import javassist.CtClass;
| import javassist.CtMethod;
| import javassist.CtNewClass;
| import javassist.NotFoundException;
|
| public final class AttemptGeneration {
|
| private AttemptGeneration() {
| super();
| }
|
| public static void main (String[] ignore) throws NotFoundException,
CannotCompileException {
| ClassPool pool=ClassPool.getDefault();
|
| // step 1 : generate a new class
| String generatedName="DynamicallyGenerated";
| CtClass superclass=pool.get("java.lang.Object");
| CtNewClass generated = new CtNewClass(generatedName, pool, false,
superclass);
| generated.toClass();
| // (*) see below : CtClass
generatedClassAgain=pool.get(generatedName);
|
| // step 2 : try to load the generated class
| try {
| Class c = Class.forName(generatedName);
| System.out.println("class "+c.getName()+" loaded.");
| } catch (ClassNotFoundException e) {
| System.out.println("class "+generatedName+" not found");
| System.exit(1);
| }
|
| // step 3 : instrument an existing class to use the generated class
| CtClass instrumented = pool.get("InstrumentMe");
| CtMethod printHelloWorld =
instrumented.getDeclaredMethod("printHelloWorld");
| String instrumentation =
"System.out.println("+generatedName+".class);";
|
| // .. the line below causes a CannotCompileException
| printHelloWorld.insertAfter(instrumentation);
| }
| }
|
The call to CtBehavior#insertAfter(String) in the last statement causes a
CannotCompileException with the following stack trace :
| Exception in thread "main" javassist.CannotCompileException: [source error]
no such class: DynamicallyGenerated
| at javassist.CtBehavior.insertAfter(CtBehavior.java:613)
| at javassist.CtBehavior.insertAfter(CtBehavior.java:538)
| at AttemptGeneration.main(AttemptGeneration.java:40)
| Caused by: compile error: no such class: DynamicallyGenerated
| at
javassist.compiler.MemberResolver.searchImports(MemberResolver.java:406)
| at
javassist.compiler.MemberResolver.lookupClass(MemberResolver.java:382)
| at
javassist.compiler.MemberResolver.lookupClassByJvmName(MemberResolver.java:310)
| at
javassist.compiler.MemberResolver.resolveJvmClassName(MemberResolver.java:450)
| at
javassist.compiler.MemberCodeGen.resolveClassName(MemberCodeGen.java:1064)
| at javassist.compiler.CodeGen.atClassObject(CodeGen.java:1546)
| at javassist.compiler.CodeGen.atExpr(CodeGen.java:1441)
| at javassist.compiler.ast.Expr.accept(Expr.java:67)
| at javassist.compiler.JvstCodeGen.atMethodArgs(JvstCodeGen.java:357)
| at
javassist.compiler.MemberCodeGen.atMethodCallCore(MemberCodeGen.java:486)
| at javassist.compiler.MemberCodeGen.atCallExpr(MemberCodeGen.java:454)
| at javassist.compiler.JvstCodeGen.atCallExpr(JvstCodeGen.java:243)
| at javassist.compiler.ast.CallExpr.accept(CallExpr.java:45)
| at javassist.compiler.CodeGen.atStmnt(CodeGen.java:331)
| at javassist.compiler.ast.Stmnt.accept(Stmnt.java:49)
| at javassist.compiler.Javac.compileStmnt(Javac.java:558)
| at javassist.CtBehavior.insertAfter(CtBehavior.java:581)
| ... 2 more
|
Note that before the exception occurs, the output 'class DynamicallyGenerated
loaded.' appears, which means that the generated class can be loaded by
Class#forName(String).
I've stepped through some of the Javassist classes involved and noticed that
the ClassPool doesn't seem to know the generated class. For example, when the
statement marked with (*) is uncommented, it causes a NotFoundException with
the following stack trace :
| Exception in thread "main" javassist.NotFoundException: DynamicallyGenerated
| at javassist.ClassPool.get(ClassPool.java:389)
| at AttemptGeneration.main(AttemptGeneration.java:31)
|
The fact that the ClassPool doesn't know the generated class is a bit
surprising, as its documentation mentions "...ClassPool objects hold all the
CtClasses that have been created so that the consistency among modified classes
can be guaranteed...".
The javassist tutorial states "...A ClassPool object is a container of CtClass
objects. Once a CtClass object is created, it is recorded in a ClassPool for
ever. This is because a compiler may need to access the CtClass object later
when it compiles source code that refers to the class represented by that
CtClass....
So my question is why the above example doesn't work and how it can be made to
work.
Thanks in advance for any help!
View the original post :
http://www.jboss.com/index.html?module=bb&op=viewtopic&p=3944068#3944068
Reply to the post :
http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=3944068
-------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
JBoss-user mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/jboss-user