Problem with AOP/AspectJ not executing on criterion - spring

Does anyone know why the following AOP/AspectJ doesn't work in Examples 2,3 ?
Note: Example 1 works.
My goal is to intercept the firing of Hibernate Query's executeUpdate(), which occurs throughout the application. Hibernate Query is an interface, and I see in the code that the implementing class I get back is QueryImpl. So that is the class I want to target, although I've tried generic filters too.
XML
<aop:config>
<aop:aspect id="myAspect" ref="aspectBean">
<!-- EXAMPLE 1: SIMPLE TEST: WORKS OK.
I intercept all methods in all my custom classes in "dao" package. -->
<aop:pointcut id="test1" expression="execution(* myapp.dao.*.*(..))" />
<aop:before pointcut-ref="test1" method="doTest1" />
<!-- EXAMPLE 2: DOESN'T WORK.
Target everything in Hibernate's Impl package with executeUpdate() function -->
<aop:pointcut id="executeUpdate2" expression="execution(* org.hibernate.impl..*..executeUpdate(..))" />
<aop:before pointcut-ref="executeUpdate2" method="handleExecuteUpdate" />
<!-- EXAMPLE 3: DOESN'T WORK.
Target QueryImpl specifically -->
<aop:pointcut id="executeUpdate3" expression="execution(* org.hibernate.impl.QueryImpl.executeUpdate(..))" />
<aop:before pointcut-ref="executeUpdate3" method="handleExecuteUpdate" />
</aop:aspect>
</aop:config>
<bean id="aspectBean" class="myapp.util.AOPAspect">
</bean>
I know for a fact the Hibernate hierarchy is correct. Example #1 works great so I know the AOP/AspectJ is wired properly. Is there something about external library traversal that doesn't support AOP/AspectJ?

I found out it doesn't work because I'm dealing with an external JAR (in this case, Hibernate). Example 1 works because I'm within my own code.
No easy solutions for external JAR pointcuts, only Load-Time Weaving is possible (but I haven't tried it),
Aspectj: intercept method from external jar

Related

Can we replace Springframework annotations (#CacheConfig, #Cacheable, #CachePut) in the XMl file?

I am implementing a module with Spring Cache mechanism. The module is generic and can cache different type of entities. So I don't want to change the Java code and want the user to configure the applicationcontext.xml file accordingly. He can put the name of the different types of entities within the applicationcontext.xml and the code should work. For e.g. -
<context:annotation-config/>
<cache:annotation-driven cache-manager="cacheManager"/>
<context:component-scan base-package="com.nokia.oss.sure.adapter"/>
<bean id="NetworkEntityService" class="com.nokia.oss.sure.adapter.cache.NetworkEntityServiceImpl"/>
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" name="NetworkEntity"/>
</set>
</property>
</bean>
He may change NetworkEntity to ServiceEntity and so on.
So in the Java code I need to mention -
#CacheConfig(cacheNames={"NetworkEntity"})
Or I can put the same for every method -
#CachePut(cacheNames="NetworkEntity", key="#entity.sureName")
public Entity addEntity(Entity entity) {
return entity;
}
But as I stated earlier, I don't want to put the cache name "NetworkEntity" in the Java code, but want to put the same in the applicationcontext.xml file. Is it possible?
Furthermore is it possible to omit all the annotations in the Java file? If I just use AbstractApplicationContext context = new GenericXmlApplicationContext("applicationContext.xml"); is it possible to mention in the applicationContext.xml file what are the methods where I want to apply the #Cacheable annotation for e.g.
I searched a lot, couldn't find it anywhere.
Thanks
Nirmalya
I found out the answer. We can put the following in the applicationContext.xml -
<!-- define caching behavior -->
<cache:advice id="cacheAdviceInterface" cache-manager="cacheManager">
<cache:caching cache="NetworkEntity">
<cache:cacheable method="getEntity"/>
<cache:cache-put method="putEntity"/>
</cache:caching>
</cache:advice>
In that case we don't need to put the #CacheConfig, #CachePut etc annotations within the Java file.

#Async annotations being ignored

I'm annotating methods with #Async but they seem to be ignored.
Here's my context file:
<task:annotation-driven executor="taskExecutor" />
<task:executor id="taskExecutor" pool-size="5-25"
queue-capacity="100" rejection-policy="CALLER_RUNS" />
<bean id="taskExecutor"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="10" />
<property name="queueCapacity" value="25" />
</bean>
When I create a runnable and auto wire taskExecutor, then call taskExecutor.execute(runnableThing) it works as expected.
However, Spring promises that if we just put #Async on a method it will functionally do the same thing. This is not happening for me (or at least the performance is nowhere near as good so I'm assuming it's not happening now that I think about it).
The method is very simple, here's some pseudo code:
import org.springframework.scheduling.annotation.Async;
#Controller
public class MyClass{
//some auto wired stuff for db persistence
#Async
void doStuff(MyObject object){
//does some stuff with object
//write object to database
//send email
}
}
Any feedback on where else to look - I imagine this is some config thing but I can't figure it out
Try <task:annotation-driven executor="taskExecutor" proxy-target-class="true" /> and add CGLIB as a dependency to the project
I am not so sure however that should be adding #Async to a controller's method. Best you add it on a service method that is called from the controller
I'm not exactly sure what your problem is, but maybe this will help.
An #Async annotated method is meant to be run asynchronously. However, you still need to invoke it. It won't just run on its own. If you need it to run on its own, use #Scheduled with an appropriate configuration.
With #Async, get a reference to the bean that contains it and invoke the method on that bean. (Because of how proxying works, you won't be able to get this behavior by calling the method from within other methods of the same object.)
Bean yourBean = ...; // get it
yourBean.asyncMethod();

Spring data jpa add filter/interceptor

I have used hibernate before, and have successfully added a filter that would intercept saves and entities who implemented a certain interface would have something logged.
Is it possible to do something similar in the new Spring Data, I have just started out using it.
Yes you can always add filters/interceptors with spring data
Following is an example:
<bean id="customizableTraceInterceptor" class="
org.springframework.aop.interceptor.CustomizableTraceInterceptor">
<property name="enterMessage" value="Entering $[methodName]($[arguments])"/>
<property name="exitMessage" value="Leaving $[methodName](): $[returnValue]"/>
</bean>
<aop:config>
<aop:advisor advice-ref="customizableTraceInterceptor"
pointcut="execution(public * org.springframework.data.jpa.repository.JpaRepository+.*(..))"/>
</aop:config>
reference: http://static.springsource.org/spring-data/data-jpa/docs/current/reference/html/

Make a check on AOP pointcut expression

I need to make a check in my pointcut expression like.
I have this bean:
<bean id="logConfig"
class="com.celfocus.ufe.base.logging.domains.LoggingConfiguration">
<property name="logDetails" value="STANDARD" />
<property name="logLvl" value="COMPLETE" />
</bean>
In my aop pointcut expression i need to make a check to verify the value of bean property "logLvl".
<aop:config>
<aop:aspect ref="ufeLogger">
<aop:pointcut id="complete" expression="execution(* *.*(..)) and bean(logConfig)==COMPLETE" />
<aop:before pointcut-ref="complete" method="logBefore" />
</aop:aspect>
</aop:config>
My expression isn't working... what I can change to make this check?
What makes you think that and bean(logConfig)==COMPLETE is a valid pointcut? Spring AOP uses AspectJ pointcut syntax, no Spring additions. Also you are not even referencing logLvl property, so has is this suppose to work?
Unfortunately to achieve this you must implement check manually. This isn't so intrusive though: simply inject logConfig into ufeLogger aspect and add a simple condition in logBefore() method.
This is the most relevant question, for solution below. I write aspect expressions from time to time. And expression might not work. You need to write right expression, which will be matched with your target method. I found a simple decision to check that everything is clear:
#Around(value="execution(* *.find(..))")
public Entity filterEntity(ProceedingJoinPoint pjp) throws Throwable {
Entity entity = (Entity) pjp.proceed(); // put breakpoint here
}
In Debug mode you can check target method real signature that is used for match with expression, in path pjp.methodInvocation.method
I hope this answer will save your time to find an error.
P.S If there are exists better decision to check expressions, glad to see it

Tiles ViewPreparer defined in Spring not found by Tiles

EDIT: I believe it is the SpringBeanPreparerFactory property of tilesConfigurer that is responsible for making sure the preparers are available for tiles ... but it appears that it may not be working. The default for tilesConfigurer is "BasicPreparerFactory", and I see a reference to that in the server logs, I'm thinking that maybe somehow that property is not being set correctly and it's using the default, BasicPreparerFactor instead.
I'm at a complete loss with this one... ANY thoughts or advice would be appreciated.
I am simply trying to use a Tiles ViewPreparer which is defined in my Spring configuration ... that's it! But for whatever reason, the "execute" method of my ViewPreparer is just never called. The ViewPreparer IS being constructed by Spring, and my tile is being rendered, but the preparer never executes. It's like there is a broken link between Tiles and Spring that should be there ... I say I'm using "testPreparer" in tiles.xml, which is a bean defined in "applicationContext.xml", but tiles is behaving like I didn't define a preparer at all. Here's a good description of what I'm essentially trying to do.
/WEB-INF/tiles.xml:
<tiles-definitions>
<definition name="test.tile" template="testtile.jsp" preparer="testPreparer">
</definition>
</tiles-definitions>
applicationContext.xml
<bean id="tilesConfigurer"
class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/tiles.xml</value>
</list>
</property>
<property name="preparerFactoryClass"
value="org.springframework.web.servlet.view.tiles2.SpringBeanPreparerFactory" />
</bean>
<bean id="testPreparer" class="TestPreparer"></bean>
TestPreparer.java
import org.apache.tiles.AttributeContext;
import org.apache.tiles.context.TilesRequestContext;
import org.apache.tiles.preparer.PreparerException;
import org.apache.tiles.preparer.ViewPreparer;
public class TestPreparer implements ViewPreparer {
public void execute(TilesRequestContext arg0, AttributeContext arg1)
throws PreparerException {
System.out.println("I executed");
}
}
struts.xml:
<package name="apps-default" extends="struts-default"
abstract="true">
<result-types>
<result-type name="tiles"
class="org.apache.struts2.views.tiles.TilesResult" />
</result-types>
<interceptors>
...
</interceptors>
<default-interceptor-ref name="defaultAppStack"/>
<package name="testPackage" extends="apps-default" namespace="/test">
<action name="create" class="testAction" method="create">
<result type="tiles">test.tile</result>
</action>
</package>
OK, problem solved. As it turns out, it was because I had the following entry in my web.xml:
<listener>
<listener-class>org.apache.struts2.tiles.StrutsTilesListener</listener-class>
</listener>
For whatever reason, that was essentially breaking/interfering with what I defined in applicationContext.xml. I'd have to do more investigation to figure out what exactly the conflict was, but needless to say removing that entry solved the issue.
Sorry, I spent the last 2 days trying to figure this out, and I guess writing my problem on here helped me think through it. Oh well, at least this will be documented out here on S.O. in case anyone else every runs into the same issue!

Resources