I'm setting up and @Around
aspect to run a method on a background thread, it looks like this
@Aspect
public class ThreadAspect {
@Around("call(@Background void *(..))")
public void runInBackground(final ProceedingJoinPoint jp) throws Throwable {
new Thread(new JPRunner(jp)).start();
}
private static class JPRunner implements Runnable {
...
@Override
public void run() {
try {
jp.proceed();
} catch (Throwable e) {
Log.e("TEST", "ThreadAspect", e);
}
}
}
}
I applied the @Background
annotation on a method that takes a String
but it fails with a ClassCastException
on the line with jp.proceed()
E/TEST (20943): java.lang.ClassCastException: java.lang.String cannot be cast to org.aspectj.lang.JoinPoint
Funnily enough, if I did not use a thread, the call seems to make it through just fine. How can I make it run on a thread?
If it matters, I'm using aspectj on android with this plugin.
EDIT: this is the failing code
// Background.java
package com.github.larvyde.ex.aspect;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Background {}
// MainActivity.java
package com.github.larvyde.ex.aspect;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends android.support.v7.app.AppCompatActivity {
@Override
public void onCreate(Bundle saved) {
super.onCreate(saved);
Log.v("TEST", "calling runInBackground");
runInBackground("run #1");
Log.v("TEST", "calling runInBackground again");
runInBackground("run #2");
}
@Background
public void runInBackground(String str) {
Log.v("TEST", str);
}
}
// ThreadAspect.java
package com.github.larvyde.ex.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import android.util.Log;
@Aspect
public class ThreadAspect {
@Around("call(@Background void *(..))")
public void runInBackground(ProceedingJoinPoint jp) throws Throwable {
new Thread(new JPRunner(jp)).start();
}
private static class JPRunner implements Runnable {
private final ProceedingJoinPoint jp;
public JPRunner(ProceedingJoinPoint jp) {
this.jp = jp;
}
@Override
public void run() {
try {
jp.proceed();
} catch (Throwable e) {
Log.e("TEST", "ThreadAspect", e);
}
}
}
}
the logs
$ adb logcat | egrep 'TEST|AndroidRuntime'
V/TEST (21315): calling runInBackground
V/TEST (21315): calling runInBackground again
E/TEST (21315): ThreadAspect
E/TEST (21315): java.lang.ClassCastException: java.lang.String cannot be cast to org.aspectj.lang.JoinPoint
E/TEST (21315): at com.github.larvyde.ex.aspect.MainActivity$AjcClosure1.run(MainActivity.java:1)
E/TEST (21315): at org.aspectj.runtime.reflect.JoinPointImpl.proceed(JoinPointImpl.java:149)
E/TEST (21315): at com.github.larvyde.ex.aspect.ThreadAspect$JPRunner.run(ThreadAspect.java:25)
E/TEST (21315): at java.lang.Thread.run(Thread.java:818)
E/TEST (21315): ThreadAspect
E/TEST (21315): java.lang.ClassCastException: java.lang.String cannot be cast to org.aspectj.lang.JoinPoint
E/TEST (21315): at com.github.larvyde.ex.aspect.MainActivity$AjcClosure3.run(MainActivity.java:1)
E/TEST (21315): at org.aspectj.runtime.reflect.JoinPointImpl.proceed(JoinPointImpl.java:149)
E/TEST (21315): at com.github.larvyde.ex.aspect.ThreadAspect$JPRunner.run(ThreadAspect.java:25)
E/TEST (21315): at java.lang.Thread.run(Thread.java:818)
For me this works nicely, maybe your actual code is different from the one you posted here or you omitted som important information. Look at my stand-alone example:
Marker annotation:
Driver application:
As you can see, one method is marked by the annotation and another one is not.
Console output without AspectJ:
As you can see, the methods are logged in the order in which they are called and all with the same timestamp.
Aspect running marked methods asynchronously in their own threads:
This is pretty much your aspect code, but I inserted a waiting time of 2 seconds in order to demonstrate the
@Background
effect.Console output with AspectJ:
As you can see here, both asynchronous calls (backgound tasks) are printed 2 seconds after the synchronous ones.