0

In my Spring 4 application, I have a class like this:

class Address {

   public getAdress(){
      ...
      List<Town> towns = getTowns();
      ...
   }

   @CustomAnnotation
   private List<Town> getTowns(){

   }
}

With AspectJ I can easily intercept the getAdress() call. The problem is with getTowns() that is not intercepted.

There are solutions such as Load-Time Weaving but that is difficult to tune and I don't what to reconfigure my application.

How can I capture any call made to any method annotated with CustomAnnotation without AspectJ ?

Regards

PS: I know that there is a workaround with self-reference but I don't find it very "clean".

Community
  • 1
  • 1
  • Extract some interface with `getAdress`, and create proxy with [ProxyFactoryBean](http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/aop/framework/ProxyFactoryBean.html). Then use the proxy instead of the bean – Eugene Mar 13 '17 at 23:10
  • @Eugene Thank you for your comment. Could you please illustrate your idea through a piece of code ? Is your method "xml-free" because I my app has no XML configuration file and I want to avoid XML as far as I can . – Dinlike Mar 13 '17 at 23:12
  • 2
    You simply cannot that is the limitation of proxy based AOP, the only workaround is self invocation which you don't want (which basically is the only solution). So apart from load time or compile time weaving there are no other solutions. – M. Deinum Mar 14 '17 at 06:24
  • IMO if a method is worth intercepting by a cross-cutting concern implemented as an aspect, it is either important enough to make it public or your class design is broken and the intercepted annotation is in the wrong place. Fix your design, don't look for power tools to avoid that. This is being said from a big AspectJ fan, BTW. So I am not against using AJ. But AOP is neither an excuse for bad design, nor is it a tool to patch up bad code. – kriegaex Mar 14 '17 at 11:50

2 Answers2

0

Extracting interface:

interface TempIfc{
    public getAdress();
}

class Address implements TempIfc{

   @Override
   public getAdress(){
      ...
      List<Town> towns = getTowns();
      ...
   }

   @CustomAnnotation
   private List<Town> getTowns(){

   }
}

Adding config:

<bean id="tgt" class="Address">
    <!-- your bean properties here -->
</bean>

<bean id="proxified" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="proxyInterfaces" value="TempIfc"/>
    <property name="target" ref="tgt"/>
    <property name="interceptorNames">
        <list>
            <value>myInterceptor</value>
        </list>
    </property>
</bean> 

<bean id="myInterceptor" class="MyMethodInterceptor"/>

<!-- Example of usage with some service -->
<bean id="someYourService" class="Service">
     <property name="adress" ref="proxified" />
</bean>

And finally interceptor:

public class MyMethodInterceptor implements  org.aopalliance.intercept.MethodInterceptor{

    public Object invoke(org.aopalliance.intercept.MethodInvocation invocation){

        System.out.println("Before calling any TempIfc method ");

        // Actionally, you may use getMethod, getArguments here to explore details, or modify arguments

        Object result = invocation.proceed(); //also it is not obligatory to call real method

        System.out.println("After calling any TempIfc method ");
        //you may modify result of invocation here

        return result;
    }
}

Here is the docs and javadocs about ProxyFactoryBean.

Eugene
  • 2,336
  • 21
  • 28
  • That still will not work. It still is a proxy and still will not intercept internal method calls unless you do a self invocation. – M. Deinum Mar 14 '17 at 06:25
0

I think we can use ControlFlowPointcut provided by Spring.

ControlFlowPointcut looks at stacktrace and matches the pointcut only if it finds a particular method in the stacktrace. essentially pointcut is matched only when a method is called in a particular context.

In this case, we can create a pointcut like

ControlFlowPointcut cf = new ControlFlowPointcut(MyClass.class, "method1");

now, using ProxyFactory create a proxy on MyClass instance and call method1().

In above case, only method2() will be advised since it is called from method1().

Arjun Patil
  • 101
  • 5