spring aop not firing for annotation - spring

I am using an annotation on a method. and whenever that annoation is present I want to intercept it using aop. What am i missing.
<bean id="emailAdvice" class="com.merc.spring.aop.advice.MultiThreadEmailAdvice"/>
<aop:config>
<aop:aspect ref="emailAdvice">
<aop:around
method="fork"
pointcut="execution(* org.springframework.mail.javamail.JavaMailSenderImpl.send(..))"/>
</aop:aspect>
<aop:aspect ref="emailAdvice">
<aop:around method="sendEmailAdvice" pointcut="#annotation(sendMailAnnotation)" arg-names="sendMailAnnotation"/>
</aop:aspect>
</aop:config>
#SendMailAnnotation()
public void testAnnotationEmail() {
System.out.println("send an email");
}
#Aspect
public class MultiThreadEmailAdvice {
public void sendEmailAdvice(ProceedingJoinPoint pjp, SendMailAnnotation sendMailAnnotation) throws Throwable {
System.out.println("before method execution");
pjp.proceed();
System.out.println("after method execution");
System.out.println(sendMailAnnotation.from());
}
}

Try to change
#annotation(sendMailAnnotation)
To
#annotation(<package>.SendMailAnnotation).
in your bean definition.
Ex
<aop:around method="sendEmailAdvice" pointcut="#annotation(com.merc.spring.aop.advice.SendMailAnnotation)" arg-names="sendMailAnnotation"/>

It turned out that the service class that call the annotated method was not spring managed. Once making in spring managed, it worked fine

Related

Replace Private Method of Spring Bean

i have requirement to replace private method of spring bean, can i achieve through spring replace.
My Code :
Replacer Class :
public class PrivateCarRep extends Car implements MethodReplacer{
#Override
public Object reimplement(Object obj, Method method, Object[] args) throws
Throwable {
// new property of Car.breaks() method.
System.out.println("New privateBreaksIs Done from Shiv");
return obj;
}
}
Car.java
package org.websparrow.beans;
public class Car {
private void privateBreaks() {
System.out.println("Old car break. privateBreaks");
}
}
My Spring Configuration:
<bean id="PrivateCarRep" class="org.websparrow.beans.PrivateCarRep"/>
<bean id="car" class="org.websparrow.beans.Car">
<replaced-method name="privateBreaks" replacer="PrivateCarRep" />
</bean>
Dear All,
i already know that i can't replace private method through spring replacer but is there any workaround for this in spring..
You need to define PrivateCarRep as a bean:
<bean id="privateCarReplacer" class="com.xx.yy.zz.PrivateCarRep" />
<bean id="car" class="org.websparrow.beans.Car">
<replaced-method name="privateBreaks" replacer="privateCarReplacer" />
</bean>
I'm afraid you can't do that,I thing the method should be be protected or public.

#Transactional AspectJ Advice

I added my custom #Around advice to bean's method. Bean is transactional. How can I make by advice to run within the transaction?
I use AspectJ to add advices.
Advice code:
#Aspect
#Order(200)
public class MyAdvice {
#Around
public Object wrap(final ProceedingJoinPoint pjp) throws Throwable {
Object ret = pjp.proceed();
// some processing that requires a transaction
return ret;
}
}
Bean code:
public class MyBean {
// method is wrapped by MyAdvice.wrap
#Transactional
public Object someBusinessMethod() {
// ...
}
}
Spring configuration:
<tx:annotation-driven transaction-manager="transactionManager" order="100" mode="proxy" />
<aop:aspectj-autoproxy />
I need the MyAdvice.wrap to run within the same transaction as MyBean.someBusinessMethod.

Upgrading to spring-3.1 seems to break my CustomWebArgumentResolver

I'm trying to upgrade a spring MVC app from 3.0.6 to 3.1.2 and some controllers that used to work don't seem to work anymore. I've read the spring docs, but I'm confused about what's compatible with what.
We've got a CustomWebArgumentResolver that looks for any request parameter named "asOf" and coverts its value to a date. We call it, unimaginatively, the "AsOfDateConverter." When upgrading to spring-3.1.2, I took advantage of the new namespace functionality and added this to my applicationContext:
<mvc:annotation-driven conversion-service="conversionService">
<mvc:argument-resolvers>
<bean id="customWebArgumentResolver" class="my.converters.CustomWebArgumentResolver">
</bean>
</mvc:argument-resolvers>
</mvc:annotation-driven>
The CustomWebArgumentResolver is straightforward:
public class CustomWebArgumentResolver implements WebArgumentResolver {
private AsOfDateConverter asOfDateConverter;
#Override
public Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) throws Exception {
if (isAsOfDateParameter(methodParameter)) {
return asOfDateConverter.convert(webRequest.getParameter("asOf"));
}
return UNRESOLVED;
}
Then an example controller might look something like this:
#Controller
#Secured({BaseController.ROLE_LOGGED_IN})
#org.springframework.transaction.annotation.Transactional
public class DashboardController extends BaseController {
public static final String URL = "/dashboard";
#RequestMapping(value=URL, method=RequestMethod.GET)
public ModelAndView get(#RequestParam(required=false) String requestedMeterType, #AsOf Date asOf) {
debug(log, "Rendering dashboard asOf %s", asOf);
etc etc
The "asOf" parameter is coming in null, and I'm sure I'm missing something obvious. If anyone out there neck deep in the latest MVC 3.1 stuff could point me in the right direction I'd be grateful.
Thanks!
Tom
EDIT:
The AsOf annotation:
#Target(ElementType.PARAMETER)
#Retention(RetentionPolicy.RUNTIME)
public #interface AsOf {
}
More of my applicationContext:
<mvc:annotation-driven conversion-service="conversionService">
<mvc:argument-resolvers>
<bean class="[blah].AsOfDateHandlerMethodArgumentResolver">
<property name="asOfDateConverter">
<bean class="[blah].AsOfDateConverter"/>
</property>
</bean>
</mvc:argument-resolvers>
</mvc:annotation-driven>
<!-- Added to re-support #Controller annotation scanning after upgrading to spring-3.1. -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="[blah].converters.CustomerConverter"/>
<bean class="[blah].converters.AccountConverter"/>
<bean class="[blah].converters.DateConverter"/>
<bean class="[blah].converters.CustomerCommunicationInstanceConverter"/>
<bean class="[blah].converters.MeterTypeConverter"/>
<bean class="[blah].converters.AreaAmountConverter" p:precision="0"/>
<bean class="[blah].converters.LengthAmountConverter" p:precision="1"/>
</set>
</property>
</bean>
The API has changed with Spring 3.1 - the interface to implement to resolve a controller argument is HandlerMethodArgumentResolver. You can continue to use CustomWebArgumentResolver, by adapting it to a HandlerMethodArgumentResolver
However changing the code to use HandlerMethodArgumentResolver also will be easy:
public class CustomWebArgumentResolver implements HandlerMethodArgumentResolver {
private AsOfDateConverter asOfDateConverter;
#Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
if (isAsOfDateParameter(methodParameter)) {
return asOfDateConverter.convert(webRequest.getParameter("asOf"));
}
return UNRESOLVED;
}
#Override
public boolean supportsParameter(MethodParameter parameter) {
return (methodParameter.getParameterAnnotation(AsOf.class)!=null)
}
Edit
After looking through your comments, I think I have an idea about what could be going wrong. Can you please check your #AsOf annotation, you probably have not declared the retention of Runtime, which could be the reason why the the WebArgumentResolver is not taking effect:
#Retention(RetentionPolicy.RUNTIME)
public #interface AsOf {
}
Anyway here is a gist with a full working test along the same lines:
https://gist.github.com/3703430

#Transactional on aspect advice possible?

Can I apply the #Transactional tag to an aspect advice? I'm trying to wrap all calls to the service layer (com.mycompany.app.myapp.service.*) in a transaction using aspects. My aspect is properly intercepting the calls to the service layer, but I can't figure out how to start a transaction. I thought I could apply the #Transactional tag and because I've got the tag, it'd pick it up and begin the transaction. What am I missing?
XML configuration:
<bean id="systemArchitectureAspect" class="com.mycompany.app.myapp.aspect.SystemArchitecture"/>
<bean id="transactionAspect" class="com.mycompany.app.myapp.aspect.MyAspect"/>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="AtomikosTransactionManager" />
<property name="userTransaction" ref="AtomikosUserTransaction" />
</bean>
<bean id="AtomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close">
<property name="forceShutdown" value="false" />
</bean>
<bean id="AtomikosUserTransaction"
class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout" value="10" />
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
Aspect w/pointcuts:
package com.mycompany.app.myapp.aspect;
#Aspect
public class SystemArchitecture {
#Pointcut( "execution(* com.mycompany.app.myapp.service..*.*(..))" )
public void inServiceLayer() {};
#Pointcut( "execution(* com.mycompany.data..*.*(..))" )
public void inDataAccessLayer() {};
}
The advice I'm trying to apply to my pointcuts:
package com.mycompany.app.myapp.aspect;
#Aspect
public class TransactionAspect {
#Transactional
#Around( "com.mycompany.app.myapp.aspect.SystemArchitecture.inServiceLayer()" )
public Object interceptServiceLayer( ProceedingJoinPoint pjp ) throws Throwable
{
return pjp.proceed();
}
}
Below I have an example that shows how you can use #Transactional together with your inServiceLayer() Pointcut. I have chosen to separate the normal flow from the exception flow. That is why I do not use the #Around advice.
#Aspect
public class TransactionAspect {
private TransactionService transactionService = new TransactionServiceNull();
#Pointcut( "execution(* com.mycompany.app.myapp.service..*.*(..))" )
public void inServiceLayer() {};
#Pointcut("execution(#org.springframework.transaction.annotation
.Transactional * *(..))")
public void transactionalMethod() {}
#Before("transactionalMethod() && inServiceLayer()")
public void beforeTransactionalMethod(JoinPoint joinPoint) {
transactionService.beginTransaction();
}
#AfterReturning("transactionalMethod() && inServiceLayer()")
public void afterTransactionalMethod(JoinPoint joinPoint) {
transactionService.commit();
}
#AfterThrowing(pointcut = "transactionalMethod() && inServiceLayer()",
throwing = "e")
public void afterThrowingFromTransactionalMethod(JoinPoint joinPoint,
RuntimeException e) {
transactionService.rollback();
}
public void setTransactionService(
final TransactionService transactionService) {
this.transactionService = transactionService;
}
}
After a quick look on your code I have to ask why you have annotated your Pointcut with #Transactional? You should only mark your business methods that you want to be executed in a transaction with that.
I hope this helps!
As #Espen said you should apply #Transactionalon your business methods directly as the Annotation itself causes Spring to create an Aspect that applies transactions to your method. So there is no need to create an aspect manually.
However, if you want to apply transactions to all you service methods and whatever else you selected with those pointcuts you should do use the xml configuration to create the transactions. Look for declarative transaction management in the documentation
Also I don't think you can apply #Transactional to an Advice. At least it is not working for me.
Spring transaction annotation at run time creates a proxy object. So if you apply transactional annotation on an advice which is advicing the service then the transaction will be for the advice and not for the service since the advice works on a proxy object of the service and your transactional annotation would work on a proxy object of the advice and not the main method of the advice. Ideally you should not be having an advice which is an extension of the functionality of the service. This defeats the purpose of the proxy pattern.
robgmills
#Transactional
#Around( "com.mycompany.app.myapp.aspect.SystemArchitecture.inServiceLayer()" )
public Object interceptServiceLayer( ProceedingJoinPoint pjp ) throws Throwable
{
return pjp.proceed();
}
You can use above Around advice but need to do couple of small changes.
Add (propagation = Propagation.REQUIRES_NEW) to #Transactional
in above.
Add #Transactional annotation to the service method for which you have added the pointcut inServiceLayer().

How to programmatically get transaction manager in a thread?

I have a wicket page , which contains two Spring-managed beans , one is DAO , another is Service Object :
public class MergeAccountsPage extends WebPage
{
#SpringBean
private MergeEmailDao mergeEmailDao;
#SpringBean
private MergingService mergingService;
}
The MergingService's implementation's methods are mostly annotated with #Transactional , so every action involving MergingService works fine.
But the problem comes here :
Link<Void> link = new Link<Void>("cancelLink") {
#Override
public void onClick() {
ma.setNewEmail(null);
ma.setNewEmailClicked(null);
ma.setNewEmailSentTime(null);
mergeAccoungDao.update(ma); //not written to DB
setResponsePage(...);
}
};
The link will call mergeAccoungDao.update(ma) to update a row in DB.
But the data is not updated to DB , I think it is because the DAO is not wrapped in #Transaction nor tx:advice and aop tags.
I wonder is there a way to programmatically get the transaction manager , and manually open/close the transaction ?
Note: I can solve the problem by adding this code in spring's XML :
<tx:advice id="txAdviceApp" transaction-manager="transactionManagerApp">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="*" propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="methods" expression="execution(* destiny.utils.AbstractDao+.*(..))"/>
<aop:advisor advice-ref="txAdviceApp" pointcut-ref="methods"/>
</aop:config>
So that the DAO's save/update/delete will work like a charm.
But I'd not like to add this config . Because in fact , the DAO extends an AbstractDao , and there are other DB/DAOs extend this AbstractDao :
public interface AbstractDao<T> {
public T get(Serializable id);
public T save(T t);
public T update(T t);
public void delete(T t);
}
public abstract class AbstractDaoJpaImpl<T> implements AbstractDao<T>
public interface MergeAccountDao extends AbstractDao<MergeAccount>
#Repository
public class MergeAccountDaoImpl extends AbstractDaoJpaImpl<MergeAccount> implements MergeAccountDao
Therefore , if this AbstractDAO's CRUD is "adviced" by this transactionManagerApp , other DAOs may have problem , because other DAOs may depend on txManagerForum , txManagerBank , txManagerUser ...etc.
Back to the problem , is there a way to programmatically get txManager ? Such as :
TransactionManager txManager = TxManagerThreadLocal.get();
txManager.begin();
ma.setNewEmailSentTime(null);
mergeAccoungDao.update(ma);
txManager.commit();
Or is there any better way to wrap a transaction to the DAO ?
Thanks a lot.
You have to inject the transaction manager in the class you want to use it. You can use constructor or property based injection for it or use autowiring.
One you get the transaction manger, you can use the programmatic transaction support in Spring to start and commit the transaction. Here is the sample code from Spring reference 2.5:
public class SimpleService implements Service {
// single TransactionTemplate shared amongst all methods in this instance
private final TransactionTemplate transactionTemplate;
// use constructor-injection to supply the PlatformTransactionManager
public SimpleService(PlatformTransactionManager transactionManager) {
Assert.notNull(transactionManager, "The 'transactionManager' argument must not be null.");
this.transactionTemplate = new TransactionTemplate(transactionManager);
}
public Object someServiceMethod() {
return transactionTemplate.execute(new TransactionCallback() {
// the code in this method executes in a transactional context
public Object doInTransaction(TransactionStatus status) {
updateOperation1();
return resultOfUpdateOperation2();
}
});
}
}
See the reference for more details.

Resources