When class hierarchy is not linear, aspect is not triggered when defined on base interface.
The most interesting: when adding delegating implementation (see last code block) to the parent class of the implementation, the test becomes Green (Aspect is triggered as expected).
Question: Why doesn't it work as described in example and why does it work with delegating implementation?
Example (sorry, no shorter example found):
Test:
@Autowired
private TheInterface underTest;
private static boolean aspectCalled;
private static boolean implementationCalled;
@Test
public void aspectTest() throws Exception {
aspectCalled = false;
implementationCalled = false;
underTest.doSomething();
assertTrue("Implementation not called!", implementationCalled);
assertTrue("Aspect not called!", aspectCalled);
}
Aspect:
@Aspect
@Component
public static class MyAspect {
@Before("execution(* *..SpecializedInterface+.doSomething())")
public void applyAspect() {
aspectCalled = true;
}
}
Interfaces:
public static interface TheInterface {
void doSomething();
}
public static interface SpecializedInterface extends TheInterface {
// inherits doSomething
// defines some other methods
}
Abstract implementations (Template pattern):
public static abstract class BaseTemplate implements TheInterface {
abstract void doOneStep();
@Override
public void doSomething() {
// do some stuff and
doOneStep();
}
}
public static abstract class SpecializedTemplate extends BaseTemplate implements SpecializedInterface {
// some other methods
}
Implementing bean:
@Component
public static class TemplateImplementation extends SpecializedTemplate {
@Override
void doOneStep() {
implementationCalled = true;
}
}
(If you are interested: test setup:)
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = MyConfig.class)
public class AopTest {
@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackageClasses = AopTest.class)
public static class MyConfig {
}
...
Ugly workaround: add this snippet to SpecializedTemplate
@Override
public void doSomething() {
super.doSomething();
}
So, why is this workaround necessary?