-
1. Re: cannot access added Field in some cases. Please help.
jaikiran Feb 4, 2010 2:55 AM (in response to megalodon)Can you please post the entire exception stacktrace and more of your relevant code? And which version of Javassist are you using?
-
2. Re: cannot access added Field in some cases. Please help.
megalodon Feb 4, 2010 3:50 AM (in response to jaikiran)Hello Jaikiran,
Thanks for your prompt response. Here are the first 3 lines of the stack trace (after which the part of my code where I access the myInt variable forms the next stack trace element):
javassist.CannotCompileException: [source error] no such field: myInt javassist.CtBehavior.insertBefore(CtBehavior.java:721) javassist.CtBehavior.insertBefore(CtBehavior.java:681)
Javassist version is 3.11.GAOne more thing I'd like to add is that I am getting all the fields in the CtClass using CtClass.getFields() and displaying them sometime before adding the new field and soon after adding the new field and I do see the new integer field 'myInt' added after CtClass.addField() call. However, the next statement is an 'CtMethod.insertBefore()' which throws the above exception. Thanks.
-Arvind
-
3. Re: cannot access added Field in some cases. Please help.
megalodon Feb 4, 2010 4:28 AM (in response to megalodon)I just want to add that I tried rebuilding the class file soon after I add the new CtField to the CtClass object and before I call CtClass.toBytecode() but that did not help.
This post has a similar issue http://spiritandopportunity.com/list/44/41185.html but it wasn't very helpful to me.
I saw a similar discussion with Mr. Chiba in 2004 here -> http://www.mail-archive.com/search?q=abount&l=jboss-development@lists.sourceforge.net
Don't know if its been resolved. I don't see it in the bug tracker.
any help is greatly appreciated. thanks
-
4. Re: cannot access added Field in some cases. Please help.
jaikiran Feb 5, 2010 1:25 AM (in response to megalodon)1 of 1 people found this helpfulYou haven't posted your complete code nor the complete exception stacktrace (i reason i keep insisting on these is because they can contain vital information). Anyway, i just gave a quick try against 3.11.0.GA version javassist:
public class NewFieldTestCase extends TestCase { public void testNewFieldAddition() throws Exception { CtClass dummyClass = ClassPool.getDefault().get("org.myapp.test.javassist.Dummy"); CtField newIntField = new CtField(CtClass.intType,"myInt",dummyClass); dummyClass.addField(newIntField); CtMethod dummyMethod = dummyClass.getDeclaredMethod("dummyMethod"); dummyMethod.insertBefore("myInt = 10;"); byte[] modifiedDummyClassBytes = dummyClass.toBytecode(); assertTrue("Empty bytes", modifiedDummyClassBytes.length > 0); } }
Works fine. Test case passes, no exceptions thrown.
-
5. Re: cannot access added Field in some cases. Please help.
megalodon Feb 5, 2010 1:24 AM (in response to jaikiran)Ok..Jaikiran. Thanks for checking it out. Here is the complete stacktrace for two such exceptions (separated by the line). Another weird thing is that, it works for some classes but throws an exception for others.
javassist.CannotCompileException: [source error] no such field: abc
javassist.CtBehavior.insertBefore(CtBehavior.java:721)
javassist.CtBehavior.insertBefore(CtBehavior.java:681)
mypkg1.SimpleInstrumenter.prefixMethod(SimpleInstrumenter.java:288)
mypkg1.SimpleInstrumenter.instrument(SimpleInstrumenter.java:195)
mypkg1.Instrument$Logger.transform(Instrument.java:77)
sun.instrument.TransformerManager.transform(TransformerManager.java:122)
sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:155)
java.lang.ClassLoader.defineClass1(Native Method)
java.lang.ClassLoader.defineClass(ClassLoader.java:620)
java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
java.net.URLClassLoader.access$100(URLClassLoader.java:56)
java.net.URLClassLoader$1.run(URLClassLoader.java:195)
java.security.AccessController.doPrivileged(Native Method)
java.net.URLClassLoader.findClass(URLClassLoader.java:188)
java.lang.ClassLoader.loadClass(ClassLoader.java:306)
sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:268)
java.lang.ClassLoader.loadClass(ClassLoader.java:251)
org.apache.catalina.loader.StandardClassLoader.loadClass(StandardClassLoader.java:941)
org.apache.catalina.loader.StandardClassLoader.loadClass(StandardClassLoader.java:857)
org.apache.catalina.loader.StandardClassLoader.loadClass(StandardClassLoader.java:941)
org.apache.catalina.loader.StandardClassLoader.loadClass(StandardClassLoader.java:857)
org.apache.catalina.core.StandardWrapper.isContainerProvidedServlet(StandardWrapper.java:1274)
org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:875)
org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:668)
org.apache.catalina.servlets.InvokerServlet.serveRequest(InvokerServlet.java:416)
org.apache.catalina.servlets.InvokerServlet.doPost(InvokerServlet.java:216)
javax.servlet.http.HttpServlet.service(HttpServlet.java:760)
javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:247)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:193)
com.mypkg2.AccessFilter.doFilter(AccessFilter.java:43)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:213)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:193)
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:256)
org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
org.apache.catalina.core.StandardContext.invoke(StandardContext.java:2422)
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:180)
org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
org.apache.catalina.valves.ErrorDispatcherValve.invoke(ErrorDispatcherValve.java:171)
org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:163)
org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:174)
org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
org.apache.coyote.tomcat4.CoyoteAdapter.service(CoyoteAdapter.java:199)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:828)
org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:700)
org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:584)
org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:683)
java.lang.Thread.run(Thread.java:595)
Caused by: compile error: no such field: abc
at javassist.compiler.MemberResolver.lookupField(MemberResolver.java:322)
at javassist.compiler.MemberResolver.lookupFieldByJvmName(MemberResolver.java:308)
at javassist.compiler.TypeChecker.fieldAccess(TypeChecker.java:843)
at javassist.compiler.TypeChecker.atFieldRead(TypeChecker.java:770)
at javassist.compiler.TypeChecker.atExpr(TypeChecker.java:571)
at javassist.compiler.ast.Expr.accept(Expr.java:67)
at javassist.compiler.TypeChecker.atPlusExpr(TypeChecker.java:370)
at javassist.compiler.TypeChecker.atBinExpr(TypeChecker.java:311)
at javassist.compiler.ast.BinExpr.accept(BinExpr.java:40)
at javassist.compiler.JvstTypeChecker.atMethodArgs(JvstTypeChecker.java:220)
at javassist.compiler.TypeChecker.atMethodCallCore(TypeChecker.java:702)
at javassist.compiler.TypeChecker.atCallExpr(TypeChecker.java:681)
at javassist.compiler.JvstTypeChecker.atCallExpr(JvstTypeChecker.java:156)
at javassist.compiler.ast.CallExpr.accept(CallExpr.java:45)
at javassist.compiler.CodeGen.doTypeCheck(CodeGen.java:241)
at javassist.compiler.CodeGen.atStmnt(CodeGen.java:329)
at javassist.compiler.ast.Stmnt.accept(Stmnt.java:49)
at javassist.compiler.Javac.compileStmnt(Javac.java:568)
at javassist.CtBehavior.insertBefore(CtBehavior.java:701)
... 84 more---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
javassist.CannotCompileException: [source error] no such field: abc
javassist.CtBehavior.insertBefore(CtBehavior.java:721)
javassist.CtBehavior.insertBefore(CtBehavior.java:681)
mypkg1.SimpleInstrumenter.prefixMethod(SimpleInstrumenter.java:288)
mypkg1.SimpleInstrumenter.instrument(SimpleInstrumenter.java:195)
mypkg1.Instrument$Logger.transform(Instrument.java:77)
sun.instrument.TransformerManager.transform(TransformerManager.java:122)
sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:155)
java.lang.ClassLoader.defineClass1(Native Method)
java.lang.ClassLoader.defineClass(ClassLoader.java:620)
java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
java.net.URLClassLoader.access$100(URLClassLoader.java:56)
java.net.URLClassLoader$1.run(URLClassLoader.java:195)
java.security.AccessController.doPrivileged(Native Method)
java.net.URLClassLoader.findClass(URLClassLoader.java:188)
java.lang.ClassLoader.loadClass(ClassLoader.java:306)
sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:268)
java.lang.ClassLoader.loadClass(ClassLoader.java:251)
java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
com.mypkg2.TimeoutThread.run(TimeoutThread.java:106)
Message was edited by: Arvind K
-
6. Re: cannot access added Field in some cases. Please help.
jaikiran Feb 5, 2010 1:34 AM (in response to megalodon)I have a suspicion that for the class that fails, the class has already been loaded by the classloader, before you do any of this changes through Javassist. But i can't say for sure, because i don't know the details about your runtime environment. For that matter, i don't even know the complete code which you are using to do this. I know that it's not always possible to post the code for various reasons. If that's the case why you haven't yet posted your code, then just speak up
Anyway, here's what i think would be relevant about classloaders http://www.csg.is.titech.ac.jp/~chiba/javassist/tutorial/tutorial.html#load
-
7. Re: cannot access added Field in some cases. Please help.
megalodon Feb 5, 2010 5:36 AM (in response to jaikiran)Hello Jaikiran,
I do not think that the class with the issue has already been loaded. In my first post, I mentioned that I am using java.lang.instrument API to do the loading and transformation initiation for me. The ClassFileTransformer hands me the bytecode of the class and I convert that into a CtClass object using CtClass.makeClassIfNew() and perform my transformations. I then hand over the modified bytecode back to the classfiletransformer to complete the loading process.
You are right that I am not in a position to post all of my code as-is mainly because I do not know where the issue(s) lies and that it might be voluminous if I post everything and of course I do not own it to post it but I would be happy to provice snippets of some main parts for clarity. Here is the method in question where I do my simple modifications. I call this method for every method of the class I am instrumenting but add the int field 'abc' to the class while instrumenting the first method only.
protected void prefixMethod(CtMethod myCtM, String methodName) { try { if (fieldsAdded == false) { CtField tempCtF = new CtField(CtClass.intType, "abc",this.CtC); //myCtM is a method in this.CtC tempCtF.setModifiers(Modifier.PUBLIC); this.CtC.addField(tempCtF,"10"); displayFields(false); // displays all the fields in this.CtC. Field 'abc' shows up here always. Log2File.write("Added Fields"); // this.CtC.rebuildClassFile(); // i thought this function might solve the issue but it did not tempCtF = this.CtC.getField("abc"); // just a precaution } myCtM.insertBefore("System.out.println(\"In " + this.className + "." + methodName + ". abc is \" + this.abc);"); } catch (CannotCompileException cce) { System.out.println("prefixMethod for " + className + " method name " + methodName + ". Exception: " + cce); cce.printStackTrace(); Log2File.writeErr(cce,"prefixMethod for " + className); } catch (NotFoundException ntfnde) { System.out.println("prefixMethod for " + className + " method name " + methodName + ". Exception: " + ntfnde); ntfnde.printStackTrace(); Log2File.writeErr(ntfnde,"prefixMethod for " + className); } }
Another twist is that, it works for a few methods in a class but not others in the same class. I do not know what made the difference there. I have a suspision that it works for non-empty methods and not empty ones but I am not sure. I tried skipping the empty ones with CtMethod.isEmpty() but I couldn't seem to skip them.
Appreciate your help so far.
-Arvind
-
8. Re: cannot access added Field in some cases. Please help.
megalodon Feb 5, 2010 8:32 AM (in response to megalodon)part of the issue was, I was futilely trying to access an instance variable from an inherited protected method. Now, I think I am getting less exceptions than before but the issue is not solved. -
9. Re: cannot access added Field in some cases. Please help.
jaikiran Feb 6, 2010 8:15 AM (in response to megalodon)This is very specific to your application. You will have to attach a debugger and step through your code and the Javassist code to see what's going wrong.
-
10. Re: cannot access added Field in some cases. Please help.
megalodon Feb 7, 2010 9:34 AM (in response to jaikiran)Is it true that one cannot access fields added to a class using Javassist from methods inherited by the class?