I have following classes and interface
interface abc {
public A do();
}
package x;
public Impl1 implements abc{
public A do(){
}
}
package y;
public Impl2 implements abc{
public A do(){
}
}
I don't have the source code of Impl1 or Impl2. But would like to intercept any call to do() method and use my own implementation. Also based on certain condition may call the actual do() implementation, other cases it will not be delegated to the original implementations.
Could you please let me know whether this is achievable. If yes how to implement this?
I am using Spring 4 and JDK 7.
I will provide a stand-alone AspectJ solution, but in spring AOP it would the same way, only the aspect and your target classes need to be Spring beans/components, so don't forget annotations like @Component
, as shown by Ian Mc.
Helper class + interface + implementations:
package de.scrum_master.app;
public class A {
private String name;
public A(String name) {
this.name = name;
}
@Override
public String toString() {
return "A [name=" + name + "]";
}
}
package de.scrum_master.app;
public interface MyInterface {
public A doSomething();
}
package de.scrum_master.app;
public class FirstImpl implements MyInterface {
@Override
public A doSomething() {
return new A("First");
}
}
package de.scrum_master.app;
public class SecondImpl implements MyInterface {
@Override
public A doSomething() {
return new A("Second");
}
}
Driver application:
package de.scrum_master.app;
public class Application {
private static MyInterface myInterface;
public static void main(String[] args) {
myInterface = new FirstImpl();
for (int i = 0; i < 5; i++) {
System.out.println(myInterface.doSomething());
}
myInterface = new SecondImpl();
for (int i = 0; i < 5; i++) {
System.out.println(myInterface.doSomething());
}
}
}
Console log without aspect:
A [name=First]
A [name=First]
A [name=First]
A [name=First]
A [name=First]
A [name=Second]
A [name=Second]
A [name=Second]
A [name=Second]
A [name=Second]
So far, so boring.
Aspect:
Now let us implement a stupid little aspect randomly deciding about method execution vs. skipping and providing another return value instead (because I do not know the real condition which would cause you to skip method execution):
package de.scrum_master.aspect;
import java.util.Random;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import de.scrum_master.app.A;
@Aspect
public class MyAspect {
private static Random random = new Random();
@Around("execution(A de.scrum_master.app.MyInterface.*(..))")
public A interceptCalls(ProceedingJoinPoint thisJoinPoint) throws Throwable {
if (random.nextBoolean())
return (A) thisJoinPoint.proceed();
else
return new A("Aspect");
}
}
Console log with active aspect:
A [name=Aspect]
A [name=First]
A [name=Aspect]
A [name=Aspect]
A [name=First]
A [name=Aspect]
A [name=Second]
A [name=Second]
A [name=Aspect]
A [name=Second]