Search code examples
aopaspectjspring-aopaspect

aspectj - AND and OR in the same pointcut


I'd like to do something when getAll(...) or getRec(...) methods are called in com.acme.dao.impl.*DaoImpl classes but exclude the com.acme.dao.impl.*ViewDaoImpl classes.

I can do the 1st requirement with

execution(* com.acme.dao.impl.*DaoImpl.getAll(..)) || execution(* com.acme.dao.impl.*DaoImpl.getNRecs(..))

but not sure how to exclude the *ViewDaoImpl classes.
I presume I should do something like

!execution(* com.acme.dao.impl.*ViewDaoImpl.*(..))

but how to add to the include expression?

Thanks,
V.


Solution

  • You have several options. The one closest to what you already have is:

    (execution(* com.acme.dao.impl.*DaoImpl.getAll(..)) || execution(* com.acme.dao.impl.*DaoImpl.getNRecs(..))) &&
    !execution(* com.acme.dao.impl.*ViewDaoImpl.*(..))
    

    But you can also use this, I think it is a bit more readable:

    within(com.acme.dao.impl.*DaoImpl) && !within(*..*ViewDaoImpl) &&
    (execution(* getAll(..)) || execution(* getNRecs(..)))
    

    Assuming that all DAO classes would implement the same interface as given above, this would also work (Dao+ captures all implementing classes and their subclasses):

    within(com.acme.dao.impl.Dao+) && !within(*..*ViewDaoImpl) &&
    (execution(* getAll(..)) || execution(* getNRecs(..)))
    

    Here is a pure AspectJ example, but it should be just the same aspect code for Spring AOP:

    Sample application classes:

    package com.acme.dao.impl;
    
    import java.util.List;
    
    public interface Dao {
      List getAll();
      List getNRecs();
      void doSomething();
    }
    
    package com.acme.dao.impl;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class FirstDaoImpl implements Dao {
      @Override
      public List getAll() {
        return new ArrayList();
      }
    
      @Override
      public List getNRecs() {
        return new ArrayList();
      }
    
      @Override
      public void doSomething() {}
    }
    
    package com.acme.dao.impl;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class SecondDaoImpl implements Dao {
      @Override
      public List getAll() {
        return new ArrayList();
      }
    
      @Override
      public List getNRecs() {
        return new ArrayList();
      }
    
      @Override
      public void doSomething() {}
    }
    
    package com.acme.dao.impl;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class MyViewDaoImpl implements Dao {
      @Override
      public List getAll() {
        return new ArrayList();
      }
    
      @Override
      public List getNRecs() {
        return new ArrayList();
      }
    
      @Override
      public void doSomething() {}
    }
    

    Driver application:

    package de.scrum_master.app;
    
    import java.util.Arrays;
    
    import com.acme.dao.impl.Dao;
    import com.acme.dao.impl.FirstDaoImpl;
    import com.acme.dao.impl.MyViewDaoImpl;
    import com.acme.dao.impl.SecondDaoImpl;
    
    public class Application {
      public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        for (Class<?> clazz : Arrays.asList(FirstDaoImpl.class, SecondDaoImpl.class, MyViewDaoImpl.class)) {
          Dao dao = (Dao) clazz.newInstance();
          dao.getAll();
          dao.getNRecs();
          dao.doSomething();
        }
      }
    }
    

    Aspect:

    I have added a lot of line breaks and indentation within the pointcut strings, of course you don't need to do that. It is just for clarity here in this Q/A scenario on StackOverflow.

    package de.scrum_master.aspect;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    
    @Aspect
    public class DaoAspect {
      @Before(
        "(" + 
          "execution(* com.acme.dao.impl.*DaoImpl.getAll(..)) || " + 
          "execution(* com.acme.dao.impl.*DaoImpl.getNRecs(..))" + 
        ") && " + 
        "!execution(* com.acme.dao.impl.*ViewDaoImpl.*(..))"
      )
      public void firstVariant(JoinPoint thisJoinPoint) {
        System.out.println("[1] " + thisJoinPoint);
      }
    
      @Before(
        "within(com.acme.dao.impl.*DaoImpl) && " +
        "!within(*..*ViewDaoImpl) && " +
        "(" +
          "execution(* getAll(..)) || " +
          "execution(* getNRecs(..))" +
        ")" 
      )
      public void secondVariant(JoinPoint thisJoinPoint) {
        System.out.println("[2] " + thisJoinPoint);
      }
    
      @Before(
        "within(com.acme.dao.impl.Dao+) && " +
        "!within(*..*ViewDaoImpl) && " +
        "(" +
          "execution(* getAll(..)) || " +
          "execution(* getNRecs(..))" +
        ")" 
      )
      public void thirdVariant(JoinPoint thisJoinPoint) {
        System.out.println("[3] " + thisJoinPoint);
      }
    }
    

    Console log:

    [1] execution(List com.acme.dao.impl.FirstDaoImpl.getAll())
    [2] execution(List com.acme.dao.impl.FirstDaoImpl.getAll())
    [3] execution(List com.acme.dao.impl.FirstDaoImpl.getAll())
    [1] execution(List com.acme.dao.impl.FirstDaoImpl.getNRecs())
    [2] execution(List com.acme.dao.impl.FirstDaoImpl.getNRecs())
    [3] execution(List com.acme.dao.impl.FirstDaoImpl.getNRecs())
    [1] execution(List com.acme.dao.impl.SecondDaoImpl.getAll())
    [2] execution(List com.acme.dao.impl.SecondDaoImpl.getAll())
    [3] execution(List com.acme.dao.impl.SecondDaoImpl.getAll())
    [1] execution(List com.acme.dao.impl.SecondDaoImpl.getNRecs())
    [2] execution(List com.acme.dao.impl.SecondDaoImpl.getNRecs())
    [3] execution(List com.acme.dao.impl.SecondDaoImpl.getNRecs())
    

    As you can see, all three variants do exactly the same. Choose according to your own preference.