Hi, > What I managed to do so far is load Foo.class from disk into a byte[] and > manually weave it with ApplicationHackerAspect. The advice is triggered, so > far so good. I can use > before or after, but when I use around I can only do > that when I skip proceed(). As soon as I call proceed() I am running into
> java.lang.reflect.InvocationTargetException > (...) > Caused by: java.lang.NoSuchMethodError: > de.scrum_master.aop.ltw_dynamic.Foo.getText_aroundBody0()Ljava/lang/String; > at de.scrum_master.aop.ltw_dynamic.Foo$AjcClosure1.run(Foo.java:1) > at > com.vendor3.ApplicationHackerAspect.ajc$around$com_vendor3_ApplicationHackerAspect$1$30d0d5e4proceed(ApplicationHackerAspect.aj:8) > at > com.vendor3.ApplicationHackerAspect.ajc$around$com_vendor3_ApplicationHackerAspect$1$30d0d5e4(ApplicationHackerAspect.aj:9) > at de.scrum_master.aop.ltw_dynamic.Foo.getText(Foo.java:4) These can be tricky to diagnose. I feel like I've seen this before but can't recall precisely why. Can you confirm the Foo that you define actually has that method in? If you dump out the bytes you received from the weaver to disk you can run javap on it to check the contents. Or post define you could query the class object that you get back to see if it is there. > Somehow there seems to be a class-loading issue. Probably this is because I > don't know sh** about class-loading and LTW, weaving adapters and the JDK's > instrumentation > interface. Furthermore, I have no idea how to manually redefine/replace the > original class Foo because mi woven version exists in a separate classloader, > i.e. also somehow > in isolation. Replacement via classloader: I don't think this is what you really want to do, but: If your Foo is in a separate classloader, you can create another new classloader and load a new Foo into it, then use that version instead of the one you are using, but you need to break all ties with the original classloader and that original loaded Foo - so that doesn't just mean instances, you'll need to break your link to Foo.class. (if you don't orphan it you'll leak permgen). Then you will be creating new instances of the new Foo and plugging them in. Having an interface can help you here where the interface is loaded by some parent loader and the implementation is loaded by a child classloader. If your code works through the interface it can be easier to plugin new implementations behind the scenes. This can be fiddly to get right. OSGi offers this kind of facility. Using the 'debugging' hotswap scheme: If the JVM is running in the right mode you can replace a class on the fly but with some limitations. You can change method bodies but not the shape of a class (cant add/remove fields/methods/etc). This is OK for before/after advice but not for around advice as you get those new helper methods sometimes. Take a look on google for JVMTI class redefinition and replacement. Using a reloading agent: This is an agent (different to the weaving agent) that allows for class replacement like jrebel or springloaded. With these you can easily plug new versions of classes in adding/removing fields/methods. There are restrictions but they are less serious. There is usually a trade off cost here for the flexibility at runtime - typically higher memory usage and somewhat slower code execution. > I would be glad to get any new hints about what my class-loading issue with > proceed() could be (and how to solve it) and what I need to do to really > replace my wonderfully > woven Foo class (later maybe even the Application class) in the main > application context instead of creating a clone. Getting past the proceed problem should be easily doable. The replacement is trickier. What I've found with AspectJ is that is can be easier just to always weave in your changes but include a suitable guard on a boolean in the pointcut that is very cheap to test. e.g. pointcut(): whatever() && if(Globals.isEnabled) {} private static boolean isEnabled; just switch the global to switch the behaviour on/off. This is common practice for logging aspects. Some tools like Spring Insight do the configuration in aop.xml - so at loadtime the decision is made what to weave in and then it is fixed until the next restart. cheers, Andy On 4 September 2012 12:13, Alexander Kriegisch <alexan...@kriegisch.name> wrote: > Hi Andy! > > Usually when I try to help people who do not clearly describe their problem, > I tell them to share more information or just ask smarter. Thank you for not > lecturing me on that (even though probably you should have) but trying > instead to make educated guesses about my assumed problems and goals. Maybe I > can do better this time. :-) > >>>> If you add "-Xbootclasspath/p:<path_to_aspects.jar>" JVM option, then you >>>> can instrument inside the JDKs and also instrument already loaded classes. >> >> Not sure that statement is quite correct. You cannot just do that to >> instrument already loaded classes > > Actually I do not use the command line option, I just quoted the full > sentence. I am only interested in instrumenting already loaded classes. So > here is my situation: > > I have written a little playground application: > > Eclipse project "main" (AspectJ): > - class Application > - interface Plugin > - aspect ApplicationAccessorAspect > - aspect PluginMonitorAspect > > Eclipse project "plugin 1" (Java): > - class MyPlugin1 implements Plugin > Eclipse project "plugin 2" (Java): > - class MyPlugin2 implements Plugin > Eclipse project "plugin 2b" (Java): > - class MyPlugin2 implements Plugin > > ApplicationAccessorAspect monitors calls (not executions!) to getters/setters > in Application. > > PluginMonitorAspect monitors executions (yes, this time) of two Plugin+ > methods. > > I successfully tested the whole setup with a WeavingURLClassLoader which > weaves all plugins upon class-loading. Log output shows that all my > intercepted calls and executions in both the main application and the plugins > are triggered perfectly. I even verified that MyPlugin2 (same class & package > name in two projects "2" and "2b", just slightly different log output so I > can differentiate them) are loaded separately because I am creating a new > WeavingURLClassLoader instance each time I load a plugin. Thus, the plugins > run in isolation from one another. I have basically created mini containers. > > Wonderful! Piece of cake! :-) But... > > But now I was getting ambitious with my next project: > > Eclipse project "plugin 3" (AspectJ): > - class HackyPlugin implements Plugin > - class AspectJLTW (basically the class I quoted in my previous mail with > slight changes) > - aspect ApplicationHackerAspect > > Okay, you see where I am going. I am trying to write a plugin which > manipulates (advises, in AOP terms) its container's classes. For that purpose > I need to be able to redefine an already loaded class. Because a plugin > cannot just start a Java agent, I tried to do that manually utilising my > version of AspectJLTW. Actually I want to redefine class Application, but > because the loaded plugin is being advised by both PluginMonitorAspect and > ApplicationAccessorAspect, plus the Application itself is also being advised > by ApplicationAccessorAspect, I thought that for the first try I should > rather advise another sibling class of the main project. So I added class Foo > to the main project. It just has one static method returning a String, and I > want to intercept its execution and manipulate the return value. (Are you > still following?) > > What I managed to do so far is load Foo.class from disk into a byte[] and > manually weave it with ApplicationHackerAspect. The advice is triggered, so > far so good. I can use before or after, but when I use around I can only do > that when I skip proceed(). As soon as I call proceed() I am running into > > java.lang.reflect.InvocationTargetException > (...) > Caused by: java.lang.NoSuchMethodError: > de.scrum_master.aop.ltw_dynamic.Foo.getText_aroundBody0()Ljava/lang/String; > at de.scrum_master.aop.ltw_dynamic.Foo$AjcClosure1.run(Foo.java:1) > at > com.vendor3.ApplicationHackerAspect.ajc$around$com_vendor3_ApplicationHackerAspect$1$30d0d5e4proceed(ApplicationHackerAspect.aj:8) > at > com.vendor3.ApplicationHackerAspect.ajc$around$com_vendor3_ApplicationHackerAspect$1$30d0d5e4(ApplicationHackerAspect.aj:9) > at de.scrum_master.aop.ltw_dynamic.Foo.getText(Foo.java:4) > > Somehow there seems to be a class-loading issue. Probably this is because I > don't know sh** about class-loading and LTW, weaving adapters and the JDK's > instrumentation interface. Furthermore, I have no idea how to manually > redefine/replace the original class Foo because mi woven version exists in a > separate classloader, i.e. also somehow in isolation. > > Maybe I should have zipped up my Eclipse projects and attached them here, but > I thought I should give it a try and explain in prose what I have > accomplished and what remains to be achieved. My whole purpose is not to hack > a server or anything, but to see how far I can push the limits of LTW and - > foremost - to learn. > > I would be glad to get any new hints about what my class-loading issue with > proceed() could be (and how to solve it) and what I need to do to really > replace my wonderfully woven Foo class (later maybe even the Application > class) in the main application context instead of creating a clone. In Star > Trek TNG speak: I want to improve Data's programming, not replace him by his > evil twin Lore. ;-) > > Cheers > -- > Alexander Kriegisch > _______________________________________________ > aspectj-users mailing list > aspectj-users@eclipse.org > https://dev.eclipse.org/mailman/listinfo/aspectj-users _______________________________________________ aspectj-users mailing list aspectj-users@eclipse.org https://dev.eclipse.org/mailman/listinfo/aspectj-users