Search code examples
springintellij-ideaaopaspectjspring-aop

Why is it expected ")" if i don't add "+" when programming with Aspectj annotations


package org.example;

@Aspect
@Order(value = 2)
@Component
public class SayAspect {
    @DeclareParents(value = "org.example..*+", defaultImpl = DefaultGoodBye.class)
    private GoodBye goodBye;
    private int count = 0;
}

I want to add an import for all classes in the org.example pakage


Solution

  • You are probably using IntelliJ IDEA and mean ( expected, not ) expected as stated in your subject line.

    IDEA code help

    This is a glitch in IDEA's AspectJ and Spring AOP support. If you just ignore it, the aspect will still work. I tried, it works nicely:

    package org.example;
    
    public interface GoodBye {
      String getGoodBye();
    }
    
    package org.example;
    
    public class DefaultGoodBye implements GoodBye {
      @Override
      public String getGoodBye() {
        return "Farewell";
      }
    }
    
    package org.example;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class MyComponent {
      public void sayHello() {
        System.out.println("Hello");
      }
    
      public void sayGoodBye() {
        System.out.println("Good bye");
      }
    }
    
    package org.example;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.DeclareParents;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    import java.util.Arrays;
    
    @Aspect
    @Order(value = 2)
    @Component
    public class SayAspect {
      @DeclareParents(value = "org.example..*", defaultImpl = DefaultGoodBye.class)
      private GoodBye goodBye;
      private int count = 0;
    
      @Before("execution(* org.example.MyComponent.sayHello())")
      public void beforeHello(JoinPoint joinPoint) {
        System.out.println("Before Hello");
        System.out.println(Arrays.toString(joinPoint.getTarget().getClass().getInterfaces()));
        System.out.println(Arrays.toString(joinPoint.getThis().getClass().getInterfaces()));
      }
    }
    
    package org.example;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.ConfigurableApplicationContext;
    
    @SpringBootApplication
    public class DemoApplication {
      public static void main(String[] args) {
        try (ConfigurableApplicationContext appContext = SpringApplication.run(DemoApplication.class, args)) {
          doStuff(appContext);
        }
      }
    
      private static void doStuff(ConfigurableApplicationContext appContext) {
        MyComponent myComponent = appContext.getBean(MyComponent.class);
        myComponent.sayHello();
        myComponent.sayGoodBye();
        System.out.println(((GoodBye) myComponent).getGoodBye());
      }
    }
    

    The console log says:

    Before Hello
    []
    [interface org.example.GoodBye, interface org.springframework.aop.SpringProxy, interface org.springframework.aop.framework.Advised, interface org.springframework.cglib.proxy.Factory]
    Hello
    Good bye
    Farewell
    

    As you can see,

    • the before advice kicks in,
    • the component proxy implements the GoodBye interface,
    • the proxied component can be cast to GoodBye and
    • calling the component's getGoodBye() method yields the expected result from the default implementation.