Okay, I think I figured it out. It is not per se a problem
with the 3rd party code, I can reproduce it with or without Thrift.
The core problem is that the inner class you want to instrument in
the library is non-public. To be exact, it is a private, non-static
inner class. But what really matters is that it is anything but
public/protected, static or not is not so important.
To Andy Clement: Maybe this is a shortcoming in AspectJ
and we need a Bugzilla ticket for it, but first I am going to post
some sample code here:
package de.scrum_master.app;
public class Application {
private static class InnerStaticRunnable implements Runnable {
@Override
public void run() {
System.out.println("Running inner static runnable");
}
}
private class InnerRunnable implements Runnable {
@Override
public void run() {
System.out.println("Running inner runnable");
}
}
public void doSomething() {
new InnerRunnable().run();
}
public static void main(String[] args) {
new SomeRunnable().run();
new Application.InnerStaticRunnable().run();
new Application().doSomething();
}
}
package de.scrum_master.aspect;
privileged aspect MyRunnables {
public interface InstrumentedRunnable {}
private long InstrumentedRunnable.myid = -1;
public long InstrumentedRunnable.getMyid() { return myid; }
public void InstrumentedRunnable.setMyid(long id) { myid = id; }
declare parents : Runnable+ implements InstrumentedRunnable;
after() returning(InstrumentedRunnable r) : call(java.lang.Runnable+.new(..)) {
System.out.println(thisJoinPoint);
System.out.println(" Runnable: " + r);
System.out.println(" Has aspect: " + PerRunnable.hasAspect(r.getClass()));
long id = PerRunnable.aspectOf(r.getClass()).getCounter();
r.setMyid(id);
PerRunnable.aspectOf(r.getClass()).incrementCounter();
}
}
package de.scrum_master.aspect;
privileged aspect PerRunnable pertypewithin(java.lang.Runnable+) {
public long counter = 0;
public long getCounter() { return counter; }
public void incrementCounter() { counter++; }
after() : staticinitialization(*) {
System.out.println("getWithinTypeName() = " + getWithinTypeName());
}
}
Now let's run the code after Ajc compilation and check the
console log:
getWithinTypeName() = de.scrum_master.app.SomeRunnable
call(de.scrum_master.app.SomeRunnable())
Runnable: de.scrum_master.app.SomeRunnable@5674cd4d
Has aspect: true
Running some runnable
getWithinTypeName() = de.scrum_master.app.Application$InnerStaticRunnable
call(de.scrum_master.app.Application.InnerStaticRunnable(Application.InnerStaticRunnable))
Runnable: de.scrum_master.app.Application$InnerStaticRunnable@65b54208
Has aspect: false
Exception in thread "main" org.aspectj.lang.NoAspectBoundException
at de.scrum_master.aspect.PerRunnable.aspectOf(PerRunnable.aj:1)
at de.scrum_master.aspect.MyRunnables.ajc$afterReturning$de_scrum_master_aspect_MyRunnables$1$8a935d86(MyRunnables.aj:15)
at de.scrum_master.app.Application.main(Application.java:24)
Please note "Has aspect: false" right before the
exception. Now change the inner classes to public or protected and
the code works:
getWithinTypeName() = de.scrum_master.app.SomeRunnable
call(de.scrum_master.app.SomeRunnable())
Runnable: de.scrum_master.app.SomeRunnable@5674cd4d
Has aspect: true
Running some runnable
getWithinTypeName() = de.scrum_master.app.Application$InnerStaticRunnable
call(de.scrum_master.app.Application.InnerStaticRunnable())
Runnable: de.scrum_master.app.Application$InnerStaticRunnable@65b54208
Has aspect: true
Running inner static runnable
getWithinTypeName() = de.scrum_master.app.Application$InnerRunnable
call(de.scrum_master.app.Application.InnerRunnable(Application))
Runnable: de.scrum_master.app.Application$InnerRunnable@6b884d57
Has aspect: true
Running inner runnable
Any comments, Andy?
--
Alexander Kriegisch
https://scrum-master.de
Yongle Zhang schrieb am 18.05.2018 04:03:
- The part of the code that’s causing the exception - this
is decompiled from the woven .class file:
public class TThreadPoolServer {
public void serve() {
. . .
TThreadPoolServer.WorkerProcess var13;
TThreadPoolServer.WorkerProcess var10000 = var13 = new
TThreadPoolServer.WorkerProcess(client, (<undefinedtype>)var10);
// The exception says here afterReturning throws the exception
EpredRunnablesCallables.aspectOf().ajc$afterReturning$EpredRunnablesCallables$1$8a935d86(var13);
. . .
}
// inner class
private class WorkerProcess implements Runnable, InstrumentedRunnableCallable {
public long myid; // inserted by aspectj
. . .
}
}
- Question: how does pertypewithin() work? what’s its
scope?
For example, pertypewithin(Runnable+) - does it work every
class in the classpath, even including those in rt.jar? When does
it create instance for every class that implements Runnable (after
class loading, on demand, …)?
Thank you!
On May 17, 2018 at 4:36:23 PM, Yongle
Zhang (ynglzh@xxxxxxxxx)
wrote:
Hi,
Problem
I have some aspects trying to insert an ID for every class
that implements Runnable.
My aspects (provided below) works fine for a simple test
in which 1) I wrote my own MyRunnable class implementing Runnable,
2) I have a simple main function that creates and runs a thread
using MyRunnable.
However, when I use it to instrument apache thrift
library, it gives me
org.aspectj.lang.NoAspectBoundException
exception.
I use compile-time weaving. The compile-time weaving
finishes successfully, and the instrumented .class code shows the
aspects was woven. However, running the instrumented apache thrift
lib gives this excetpion:
(MyServer is my simple server implementation using thrift.
TThreadPoolServer is the server class in apache thrift
lib.)
org.aspectj.lang.NoAspectBoundException
at EpredPerRunnable.aspectOf(EpredPerRunnable.aj:1)
at EpredRunnablesCallables.ajc$afterReturning$EpredRunnablesCallables$1$8a935d86(EpredRunnablesCallables.aj:55)
at org.apache.thrift.server.TThreadPoolServer.serve(TThreadPoolServer.java:168)
at MyServer.StartsimpleServer(MyServer.java:21)
at MyServer.main(MyServer.java:28)
My Aspects
Here are the aspects I wrote:
1) I have a counter for each class implements Runnable
using pertypewithin.
privileged aspect PerRunnable
pertypewithin(java.lang.Runnable+)
{
public long counter = 0;
public long getCounter() {
return counter;
}
public void incrementCounter() {
counter++;
}
}
2) I insert an id into each class that implements Runnable
using interface.
privileged aspect MyRunnables {
public interface InstrumentedRunnable {}
private long InstrumentedRunnable.myid = -1;
public long InstrumentedRunnable.getMyid() {
return myid;
}
public void InstrumentedRunnable.setMyid(long id) {
myid = id;
}
declare parents: (Runnable)+ implements InstrumentedRunnable;
after() returning(InstrumentedRunnable r):
call(java.lang.Runnable+.new(..)) {
long id = PerRunnable.aspectOf(r.getClass()).getCounter();
r.setMyid(id);
PerRunnable.aspectOf(r.getClass()).incrementCounter();
}
}
3) Part of my scripts that only instruments
thrift:
CLASSPATH=$CLASSPATH:~/aspectj1.9/lib/aspectjtools.jar
CLASSPATH=$CLASSPATH:~/aspectj1.9/lib/aspectjrt.jar
AJC=~/aspectj1.9/bin/ajc
echo "Compiling Aspects ..."
$AJC -classpath $CLASSPATH:./lib/libthrift-0.11.0.jar -source 1.8 asp/*.aj
echo "Weaving aspect into thrift lib..."
$AJC -classpath $CLASSPATH:./lib/servlet-api-2.5.jar:./lib/httpcore-4.4.1.jar:./lib/slf4j-api-1.7.12.jar:./lib/httpclient-4.4.1.jar -source 1.8 -inpath ./lib/libthrift-0.11.0.jar -aspectpath ./asp/ -outjar ./my-libthrift-0.11.0.jar
4) Part of my scripts that starts the thrift
server:
CLASSPATH=$CLASSPATH:~/aspectj1.9/lib/aspectjtools.jar
CLASSPATH=$CLASSPATH:~/aspectj1.9/lib/aspectjrt.jar
java -cp $CLASSPATH:./asp:./my-add-server.jar:./my-libthrift-0.11.0.jar:./lib/slf4j-api-1.7.12.jar MyServer
Need Help
- Has anyone met such problem before? Any guess? Note that
these aspects works for my own Runnable but not for thrift lib. (I
can send more code needed including my test classes and my scripts,
but they don’t fit within an email…)
- Is there a way to get all aspect instances and what they
are matched to at runtime?
- Does aspectj has this feature: given 1) a pointcut, 2)
the signature of a target (class/method) I want the pointcut to
match, tell me whether they matched, and if not why.
Thank you for your time
and help!
_______________________________________________
aspectj-users mailing list
aspectj-users@xxxxxxxxxxx
To change your delivery options, retrieve your password, or
unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/aspectj-users