Question

I have defined by advise to be executed for the two methods :

SampleBusinessLogicImpl.updateSample(Sample sample) and SampleBusinessLogicImpl.createSample(Sample sample)

But my advise get executed for the first update() method only. What am I doing wrong here ?

@Aspect
public class SampleDynamicValidationAspect {

    private static final Logger logger = LoggerFactory.getLogger(SampleDynamicValidationAspect.class); 

    /**
    private SampleTblDAO dao; //DAOs can be used inside dynamic validations
    **/


    @Before("execution(public * com.rakuten.gep.sample.businesslogic.impl.SampleBusinessLogicImpl.updateSample(com.rakuten.gep.sample.entity.common.Sample,..)) && args(sample,..) throws *Exception"
            +"|| execution(public * com.rakuten.gep.sample.businesslogic.impl.SampleBusinessLogicImpl.createSample(com.rakuten.gep.sample.entity.common.Sample,..)) && args(sample,..) throws *Exception")
    public void validate(Sample sample) throws SampleException {
        //Dynamic validation here.
        //If some validation is failed, wrapped the appropiate exception in SampleException
        System.out.println("Involking Dynamic Validator");
    }
}

My SampleBusinessLogicImpl class is as follows :

@Service
public class SampleBusinessLogicImpl implements SampleBusinessLogic {

    @Autowired
    @Qualifier(value="proxySampleTblDao")
    private SampleTblDao sampleTblDao;

    @Override
    @Transactional(rollbackFor=Exception.class)
    public Sample createSample(Sample sample) throws SampleException {
        //..
    }


    @Override
    @Transactional(rollbackFor=Exception.class)
    public Sample updateSample(Sample sample) throws SampleException {
      //..

    }
}
Was it helpful?

Solution

When you define the matching method expression in the Pointcut, it should match the actual method on which you would want to advice

This is what your pointcut expression should be

@Before("execution(public * com.rakuten.gep.sample.businesslogic.impl.SampleBusinessLogicImpl.updateSample(com.rakuten.gep.sample.entity.common.Sample,..) throws *Exception) && args(sample,..)"
            +"|| execution(public * com.rakuten.gep.sample.businesslogic.impl.SampleBusinessLogicImpl.createSample(com.rakuten.gep.sample.entity.common.Sample,..) throws *Exception) && args(sample,..)")

Reason:

In your case, the method signature is

public Sample createSample(Sample sample) throws SampleException {
public Sample updateSample(Sample sample) throws SampleException {

But, your pointcut is

@Before("execution(public * com.rakuten.gep.sample.businesslogic.impl.SampleBusinessLogicImpl.updateSample(com.rakuten.gep.sample.entity.common.Sample,..)) && args(sample,..) throws *Exception"
            +"|| execution(public * com.rakuten.gep.sample.businesslogic.impl.SampleBusinessLogicImpl.createSample(com.rakuten.gep.sample.entity.common.Sample,..)) && args(sample,..) throws *Exception")

Notice that the throws *Exception is outside the method declaration in the pointcut expression. And that is why the pointcut expression doesnt match your method declaration. Move the throws *Exception within execution( and it will work. I just tried it.

Clarifying the invocation of only one method.

Yes, actually.. You do not need to specify the throws *Exception. It would suffice with just the method So, if you remove it completely, it would work perfectly fine, with both the method executions. Now, why update works is because, it is declared first in the Pointcut expression. So, the Pointcut matches the method declaration for updateSample() then it encounters the out of place *Exception and the || is applied to *Exception which actually is nothing.

Now, if you just flip the pointcut expression the way it is declared, the erroronous one that is. Only createSample would work because that is what the only one matched in the pointcut expression. Remember, the ) is closed in the execution expression too.

@Before("execution(public * com.rakuten.gep.sample.businesslogic.impl.SampleBusinessLogicImpl.createSample(com.rakuten.gep.sample.entity.common.Sample,..) throws *Exception) && args(sample,..)"
            +"|| execution(public * com.rakuten.gep.sample.businesslogic.impl.SampleBusinessLogicImpl.updateSample(com.rakuten.gep.sample.entity.common.Sample,..) throws *Exception) && args(sample,..)") 

Also, from the Spring AOP documentation

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)

All parts except the returning type pattern (ret-type-pattern in the snippet above), name pattern, and parameters pattern are optional.

Hope, i was able to help with the doubt.

OTHER TIPS

You can define like this

@Before(value="( execution(* com.rakuten.gep.sample.businesslogic.impl.SampleBusinessLogicImpl.updateSample(..))"
    + "|| execution(* com.rakuten.gep.sample.businesslogic.impl.SampleBusinessLogicImpl.createSample(..)))"
    + " && args(sample)")
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top