Hot questions for Using AspectJ in spring mvc

Question:

Before spring introduce @GetMapping, there only one annotation we care about @RequestMapping, so, this aspect works

@Before("within(aa.bb.*.rest..*) && execution(public * *(..)) && @within(org.springframework.web.bind.annotation.RestController) && @annotation(org.springframework.web.bind.annotation.RequestMapping)")

But after we can use @GetMapping, @PostMapping, this point not works, but these annotations have a meta annotation @RequestMapping.

Is there any way to easily intercept all @RequestMapping/@{Get,Post,Put,Patch,..}Mapping ?


Answer:

I found this syntax here works for me!

@Pointcut("execution(@(@org.springframework.web.bind.annotation.RequestMapping *) * *(..))")
public void requestMappingAnnotations() { }

Also I can list them all

@Pointcut("within(aa.bb.*.rest..*)  && @within(org.springframework.web.bind.annotation.RestController)")
public void restControllers() {}

@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping) " +
    "|| @annotation(org.springframework.web.bind.annotation.GetMapping)" +
    "|| @annotation(org.springframework.web.bind.annotation.PostMapping)" +
    "|| @annotation(org.springframework.web.bind.annotation.PathVariable)" +
    "|| @annotation(org.springframework.web.bind.annotation.PutMapping)" +
    "|| @annotation(org.springframework.web.bind.annotation.DeleteMapping)"
)
public void mappingAnnotations() {}

@Pointcut("execution(@(@org.springframework.web.bind.annotation.RequestMapping *) * *(..))")
public void requestMappingAnnotations() { }

@Before("restControllers() && requestMappingAnnotations()")
public void onExecute(JoinPoint jp) {}

Question:

Trying to invoke the around advice on all request methods (all GET and POST) in a controller package. The advice is not working for the request methods. Below is my controller and the aspect advice method.

Also, I need to print the request mapping parameters like method type (Get or Post) and the Requested URL.

Controller class:

package net.prc.sales.web.controller;

// imports

@SessionAttributes({Dictionary.FORM_DRIVER_INFO})
@Controller
public class CustomerInfoController {
    @RequestMapping(value = Dictionary.URL_QUOTE_CUSTOMER_INFO, method = RequestMethod.GET)
    public ModelAndView viewEsCustInfo(Model model, HttpSession session) throws SessionExpiredException {
        ModelAndView mav = new ModelAndView();
        // ...
    }
    // ...
}

Aspect advice:

@Around("net.prc.sales.web.controller.*.*(..) && " + "@annotation(RequestMapping)")
public void ourAroundAdvice(ProceedingJoinPoint method) {
    System.out.println("Before-Advice Part:This is called before the method exceution.\n");
    try {
        method.proceed();
        System.out.println("After-Returning-Advice Part: This is called after the method returns nomally.\n");
    } catch (Throwable e) {
        System.out.println("After-Throwing-Advice Part: This is called after the method throws exception.\n");
    }
}

Answer:

@AleksiYrttiaho is right insofar as if you want to match subpackages you should use net.prc.sales.web.controller..* instead of net.prc.sales.web.controller.*.*. But that is not your problem here because the sample code shows that class CustomerInfoController is right in that package.

Furthermore you need to

  • specify a return type in your pointcut's method signature,
  • specify a fully qualified class name for the annotation and
  • make sure that your advice's return type matches the intercepted methods' type. Your advice cannot return void if the intercepted method returns something else (in your example ModelAndView).

I would also recommend to re-throw the caught Throwable and not just swallow it.

Try something like this:

@Around("execution(* net.prc.sales.web.controller..*(..)) && @annotation(net.prc.foo.bar.RequestMapping)")
public Object ourAroundAdvice(ProceedingJoinPoint thisJoinPoint) throws Throwable {
    System.out.println("Before " + thisJoinPoint);
    Object result = null;
    try {
        result = thisJoinPoint.proceed();
        System.out.println("After returning " + thisJoinPoint);
        return result;
    } catch (Throwable t) {
        System.out.println("After throwing " + thisJoinPoint);
        throw t;
    }
}

My recommendation is to learn AspectJ basics before doing complicated things. You could use native syntax instead of annotation style because Eclipse gives you great feedback via syntax highlighting and error messages. Then, if you have your pointcut ready, you can still convert it into @AspectJ syntax later.


Update: As for binding the annotation to an advice parameter in order to be able to access its properties, this can also be done, I just read that part of your question. First get the advice executing at all, then continue here (code untested):

@Around("execution(* net.prc.sales.web.controller..*(..)) && @annotation(requestMapping)")
public Object ourAroundAdvice(ProceedingJoinPoint thisJoinPoint, RequestMapping requestMapping) throws Throwable {
    System.out.println("Before " + thisJoinPoint);
    System.out.println("  Request method = " + requestMapping.method());
    System.out.println("  Request value  = " + requestMapping.value());

    Object result = null;
    try {
        result = thisJoinPoint.proceed();
        System.out.println("After returning " + thisJoinPoint);
        return result;
    } catch (Throwable t) {
        System.out.println("After throwing " + thisJoinPoint);
        throw t;
    }
}

Question:

I have a working spring mvc project. I want to log each request through my controllers with using AspectJ. The relevant code:

The Controller: (in package hu.freetime.controller)

@Controller
@RequestMapping("/")
public class BaseControllerImpl {
    @RequestMapping(method = RequestMethod.GET)
    public String index(Model model) {
        return "index";
    }
}

The Aspect:

@Aspect
public class ControllerAspectImpl {
    Logger logger = LoggerFactory.getLogger(ControllerAspectImpl.class);

    @Pointcut("execution(public * hu.freetime.controller.BaseControllerImpl.*(..))")
    public void logController() {
    }


    @Around("logController()")
    public void log(final ProceedingJoinPoint pjp) {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        logger.info("Calling Controller method: " + method.getName() + "()");
        try {
            pjp.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
}

The WebAppInitializer:

public class CashflowWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] { RootConfig.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { WebConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
}

The WebConfig class:

@Configuration
@EnableWebMvc
@EnableAspectJAutoProxy
@ComponentScan(basePackages = { "hu.freetime.controller", "hu.freetime.aspect" })
public class WebConfig extends WebMvcConfigurerAdapter {

    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        resolver.setExposeContextBeansAsAttributes(true);
        return resolver;
    }

    @Bean
    public ControllerAspectImpl getControllerAspect() {
        return new ControllerAspectImpl();
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

The problem is, that only one of the two components is working. If I "turn off" the AOP, the MVC works perfect, but when i "turn on", and I want to go to the main page, I get this error:

HTTP Status 404 - .../WEB-INF/views/.jsp
The requested resource is not available.

The strange thing is that it wants to map the ".jsp" instead of "index.jsp", as I wrote in the Controller's index() method. I debugged at runtime, and it did stop at the controller method.

How can I make it work?


Answer:

Your around advice does not return the result of pjp.proceed(). That is the return value of the advised method and must be returned by the advice! Otherwise you are turning the advised method into a void as well.

public **Object** log(final ProceedingJoinPoint pjp) {
...
    try {
        **return** pjp.proceed(); <<< !
    } catch (Throwable e) {
        e.printStackTrace();
    }    
}

Question:

Currently we are into development phase of our product, and to be frank numerous controllers/services has already been written. We are using Spring MVC, Core, Aspect, Security etc along with Hibernate, JQuery etc.

Now we have a requirement to capture Logged in user activities, such button clicks, menu clicks, hyperlink clicks etc.

One approach is i use Spring Aspect, and create my own annotation or use in built if any in spring. But the issue is, i will have to manually add it to all the controllers in my application.Refer this.

is there something available on the Global level, somewhere around dispatcher servlet, when the request is processed. (Just like @ControllerAdvice with @ExceptionHandler)


Answer:

Pointcuts in Spring AOP or AspectJ cannot only be based on manually added annotations, but also on other common traits of the methods you want to intercept, such as

  • package name patterns,
  • class name patterns,
  • method name patterns,
  • method signatures (certain parameter types),
  • class hierarchies (e.g. macht all subclasses of a certain class or interface)

and any combinations thereof. You can probably get pretty far with that. But in order to give a more concrete answer I would have to know more about your code.


Update: Now that you told me the common denominator, I have an idea for you:

package de.scrum_master.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.web.bind.annotation.RequestMapping;

public aspect RequestMappingInterceptor {
    @Pointcut(
        "within(@org.springframework.stereotype.Controller *) && " +
        "@annotation(requestMapping) && " +
        "execution(* *(..))"
    )
    public void controller(RequestMapping requestMapping) {}

    @Before("controller(requestMapping)")
    public void advice(RequestMapping requestMapping, JoinPoint thisJoinPoint) {
        System.out.println(thisJoinPoint);
        System.out.println("  " + requestMapping);
        System.out.println("  " + requestMapping.method()[0]);
    }
}

This example intercepts all public methods in all controllers and additionally binds the request mapping annotation to a parameter which you can easily evaluate.

Question:

I am new to Spring and AOP. I am trying this simple thing where I have created a custom annotation which when placed before any method should execute some code. This is the annotation I created

    // Declares a custom annotation that validates json
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface JsonSchemaAnnotation {
    }

Next I created the Spring Aspect class which holds the logic

@Aspect
public class UpdateUIMetadataInterceptor {

@Pointcut("execution(public * com.fico.cardinal.cm.*.*(..))")
public void anyPublicMethod() {
    System.out.println("Running");
}

@Before("anyPublicMethod() && @annotation(jsonSchemaAnnotation)")
public void validateJson(ProceedingJoinPoint pjp) throws Throwable {
    System.out.println("Running");  
}

}

And this is my simple test class

public class ValidationTest {

public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("spring/configuration.xml");
    String jsondata = "{\"id\": \"EXPENSE_REPORT\",\"properties\": {\"transactionType\": \"EXPENSE_REPORT\"},\"sections\": []} ]}";
    ValidationTest test = new ValidationTest();
    test.jsonValidationTest("dummy", jsondata);
    ((AbstractApplicationContext) context).close();


}

@JsonSchemaAnnotation
public void jsonValidationTest(String dummy, String jsondata) {
    System.out.println("Success");

}

The problem is my spring aop never gets triggered. I have included a bean in my configuration.xml

<aop:aspectj-autoproxy>
    <aop:include name="UpdateUIMetadataInterceptor" />
</aop:aspectj-autoproxy>
<bean id="updateUI"      class="com.fico.cardinal.cm.interceptor.UpdateUIMetadataInterceptor" />

Can anyone point out what I am missing?


Answer:

You have several problems with your code:

  1. You should create your ValidationTest object as a bean managed by Spring and not using new
  2. <aop:include name="UpdateUIMetadataInterceptor" /> should be <aop:include name="updateUI"/>; you can actually just stick with <aop:aspectj-autoproxy/> for simplicity here
  3. ProceedingJoinPoint is not supported for before aspects, so remove it; you can use JoinPoint instead if you need access to arguments
  4. JsonSchemaAnnotation jsonSchemaAnnotation parameter should be present for validateJson method of your aspect, as pointed out by frant.hartm

Question:

AspectJ's JoinPoint is an interface and ProceedingJoinPoint is also an interface that extends the Joinpoint.

However, when I use them in an aspect, I can use their instances and their methods directly.

@Around("execution(* com.luv2code.aopdemo.dao.service.*.getFortune(..))")
public Object aroundGetFortune(
        ProceedingJoinPoint proceedingJoinPoint) throws Throwable{

    String method = proceedingJoinPoint.getSignature().toShortString();
    System.out.println("\n=======> Executing @Around on method: " + method);

    return null;
}

How is this possible? Isn't the interface supposed to be implemented by some classes to be used?

Or Is it that the casting is done behind the scene in AspectJ?

Thank you,


Answer:

At runtime the Spring framework provides the instance of MethodInvocationProceedingJoinPoint which is an implementation of ProceedingJoinPoint.

From the source code :

public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint, JoinPoint.StaticPart {..}

To answer your question , Yes , the Spring framework has an implementation for the interface.

You may debug an Spring AOP program to observe what happens at runtime.

Question:

I am building a Spring Boot MVC application which requires an authentification check on some Controller methods. For that, I didn't use any Identity management framework provided by Spring because I need to do it myself since it is a school project. So I planned to use Aspect Oriented Programmation with Spring AOP, and create an annotation AuthentificatedOnly like this:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthentificatedOnly {

}

I also created an aspect that should match this annotation, and throw an exception if the user is not authentificated (with a UserManager that I also created, autowired with Spring IOC, and that is fully operationnal since I tested it directly on some controllers, so the problem can't be in the user manager). The aspect looks like this:

@Aspect
@Component
public class AuthentificationCheckAspect {

    @Autowired
    private IUserManager userManager;

    @Around("@target(dgl.dgladmin_rest.model.auth.AuthentificatedOnly)")
    public Object checkAuthentification(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("checking authentification for " + joinPoint.getSignature().toShortString());

        if(!userManager.isConnected())throw new AuthentificationException();
        return joinPoint.proceed();
    }
}

I use my annotation on some controller methods which return a view or a ModelAndView like this:

@Controller
public class UserController{
[...]

@AuthentificatedOnly
    @GetMapping("/users")
    public String userPage(Model model){
        return "users";
    }

[...]
}

When I launch my application, it throws exceptions and stops:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.6.RELEASE)

2018-11-08 16:43:31.193  INFO 4060 --- [  restartedMain] dgl.Application                          : Starting Application on WARREN-LAPTOP with PID 4060 (started by Warren in C:\Users\Warren\Documents\├ęcole\HELMOB3\Archi Log\projet\DGLAdmin_REST)
2018-11-08 16:43:31.199  INFO 4060 --- [  restartedMain] dgl.Application                          : No active profile set, falling back to default profiles: default
2018-11-08 16:43:31.681  INFO 4060 --- [  restartedMain] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@713bc672: startup date [Thu Nov 08 16:43:31 CET 2018]; root of context hierarchy
2018-11-08 16:43:35.317  INFO 4060 --- [  restartedMain] o.s.b.f.s.DefaultListableBeanFactory     : Overriding bean definition for bean 'authentificationCheckAspect' with a different definition: replacing [Generic bean: class [dgl.dgladmin_rest.model.auth.AuthentificationCheckAspect]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [C:\Users\Warren\Documents\├ęcole\HELMOB3\Archi Log\projet\DGLAdmin_REST\target\classes\dgl\dgladmin_rest\model\auth\AuthentificationCheckAspect.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=application; factoryMethodName=authentificationCheckAspect; initMethodName=null; destroyMethodName=(inferred); defined in dgl.Application]
2018-11-08 16:43:36.956  INFO 4060 --- [  restartedMain] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$3cf3c81e] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2018-11-08 16:43:37.134  INFO 4060 --- [  restartedMain] o.s.aop.framework.CglibAopProxy          : Method [void org.springframework.transaction.annotation.AbstractTransactionManagementConfiguration.setConfigurers(java.util.Collection)] is package-visible across different ClassLoaders and cannot get proxied via CGLIB: Declare this method as public or protected if you need to support invocations through the proxy.
2018-11-08 16:43:37.274  INFO 4060 --- [  restartedMain] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.hateoas.config.HateoasConfiguration' of type [org.springframework.hateoas.config.HateoasConfiguration$$EnhancerBySpringCGLIB$$bc741550] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2018-11-08 16:43:37.298  INFO 4060 --- [  restartedMain] o.s.aop.framework.CglibAopProxy          : Method [org.springframework.plugin.core.support.PluginRegistryFactoryBean org.springframework.hateoas.config.HateoasConfiguration.relProviderPluginRegistry()] is package-visible across different ClassLoaders and cannot get proxied via CGLIB: Declare this method as public or protected if you need to support invocations through the proxy.
2018-11-08 16:43:37.298  INFO 4060 --- [  restartedMain] o.s.aop.framework.CglibAopProxy          : Method [org.springframework.hateoas.core.AnnotationRelProvider org.springframework.hateoas.config.HateoasConfiguration.annotationRelProvider()] is package-visible across different ClassLoaders and cannot get proxied via CGLIB: Declare this method as public or protected if you need to support invocations through the proxy.
2018-11-08 16:43:37.298  INFO 4060 --- [  restartedMain] o.s.aop.framework.CglibAopProxy          : Method [org.springframework.hateoas.RelProvider org.springframework.hateoas.config.HateoasConfiguration.defaultRelProvider()] is package-visible across different ClassLoaders and cannot get proxied via CGLIB: Declare this method as public or protected if you need to support invocations through the proxy.
2018-11-08 16:43:37.299  INFO 4060 --- [  restartedMain] o.s.aop.framework.CglibAopProxy          : Method [org.springframework.hateoas.core.DelegatingRelProvider org.springframework.hateoas.config.HateoasConfiguration._relProvider(org.springframework.plugin.core.PluginRegistry)] is package-visible across different ClassLoaders and cannot get proxied via CGLIB: Declare this method as public or protected if you need to support invocations through the proxy.
2018-11-08 16:43:37.299  INFO 4060 --- [  restartedMain] o.s.aop.framework.CglibAopProxy          : Method [org.springframework.hateoas.LinkDiscoverers org.springframework.hateoas.config.HateoasConfiguration.linkDiscoverers(org.springframework.plugin.core.PluginRegistry)] is package-visible across different ClassLoaders and cannot get proxied via CGLIB: Declare this method as public or protected if you need to support invocations through the proxy.
2018-11-08 16:43:37.299  INFO 4060 --- [  restartedMain] o.s.aop.framework.CglibAopProxy          : Method [org.springframework.hateoas.config.ConverterRegisteringBeanPostProcessor org.springframework.hateoas.config.HateoasConfiguration.jackson2ModuleRegisteringBeanPostProcessor(org.springframework.beans.factory.ObjectFactory)] is package-visible across different ClassLoaders and cannot get proxied via CGLIB: Declare this method as public or protected if you need to support invocations through the proxy.
2018-11-08 16:43:37.313  WARN 4060 --- [  restartedMain] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.hateoas.config.HateoasConfiguration': Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class org.springframework.hateoas.config.HateoasConfiguration$$EnhancerBySpringCGLIB$$bc741550: Common causes of this problem include using a final class or a non-visible class; nested exception is org.springframework.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
2018-11-08 16:43:37.328  INFO 4060 --- [  restartedMain] ConditionEvaluationReportLoggingListener : 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2018-11-08 16:43:37.346 ERROR 4060 --- [  restartedMain] o.s.boot.SpringApplication               : Application run failed

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.hateoas.config.HateoasConfiguration': Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class org.springframework.hateoas.config.HateoasConfiguration$$EnhancerBySpringCGLIB$$bc741550: Common causes of this problem include using a final class or a non-visible class; nested exception is org.springframework.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:581) ~[spring-beans-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495) ~[spring-beans-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317) ~[spring-beans-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315) ~[spring-beans-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:373) ~[spring-beans-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1246) ~[spring-beans-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1096) ~[spring-beans-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:535) ~[spring-beans-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495) ~[spring-beans-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317) ~[spring-beans-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315) ~[spring-beans-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) ~[spring-beans-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.context.support.PostProcessorRegistrationDelegate.registerBeanPostProcessors(PostProcessorRegistrationDelegate.java:236) ~[spring-context-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:708) ~[spring-context-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:533) ~[spring-context-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) ~[spring-boot-2.0.6.RELEASE.jar:2.0.6.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) [spring-boot-2.0.6.RELEASE.jar:2.0.6.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:386) [spring-boot-2.0.6.RELEASE.jar:2.0.6.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) [spring-boot-2.0.6.RELEASE.jar:2.0.6.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1242) [spring-boot-2.0.6.RELEASE.jar:2.0.6.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1230) [spring-boot-2.0.6.RELEASE.jar:2.0.6.RELEASE]
    at dgl.Application.main(Application.java:34) [classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_101]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_101]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_101]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_101]
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-2.0.6.RELEASE.jar:2.0.6.RELEASE]
Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class org.springframework.hateoas.config.HateoasConfiguration$$EnhancerBySpringCGLIB$$bc741550: Common causes of this problem include using a final class or a non-visible class; nested exception is org.springframework.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
    at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:208) ~[spring-aop-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:110) ~[spring-aop-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:473) ~[spring-aop-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:355) ~[spring-aop-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:304) ~[spring-aop-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:431) ~[spring-beans-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1698) ~[spring-beans-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:573) ~[spring-beans-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    ... 29 common frames omitted
Caused by: org.springframework.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
    at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:345) ~[spring-core-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.cglib.proxy.Enhancer.generate(Enhancer.java:492) ~[spring-core-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:93) ~[spring-core-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:91) ~[spring-core-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54) ~[spring-core-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_101]
    at org.springframework.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61) ~[spring-core-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.cglib.core.internal.LoadingCache.get(LoadingCache.java:34) ~[spring-core-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:116) ~[spring-core-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:291) ~[spring-core-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:480) ~[spring-core-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.cglib.proxy.Enhancer.createClass(Enhancer.java:337) ~[spring-core-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.aop.framework.ObjenesisCglibAopProxy.createProxyClassAndInstance(ObjenesisCglibAopProxy.java:58) ~[spring-aop-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:205) ~[spring-aop-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    ... 36 common frames omitted
Caused by: java.lang.reflect.InvocationTargetException: null
    at sun.reflect.GeneratedMethodAccessor44.invoke(Unknown Source) ~[na:na]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_101]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_101]
    at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:459) ~[spring-core-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:336) ~[spring-core-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    ... 49 common frames omitted
Caused by: java.lang.IllegalAccessError: class org.springframework.hateoas.config.HateoasConfiguration$$EnhancerBySpringCGLIB$$a0484109 cannot access its superclass org.springframework.hateoas.config.HateoasConfiguration
    at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.0_101]
    at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ~[na:1.8.0_101]
    ... 54 common frames omitted

I believe the problem is in the @Around annotation in my aspect, because the application starts normally if I replace the @Around annotation by a @Pointcut annotation, but then I can call the affected methods and nothing happens (even the System.out.println isn't reached, so I believe the aspect is never used).


Answer:

I found the solution to my problem: Use

@Around("@annotation(dgl.dgladmin_rest.model.auth.AuthentificatedOnly)")

instead of

@Around("@target(dgl.dgladmin_rest.model.auth.AuthentificatedOnly)")

Question:

I have an external jar file which inside only one AspectJ class.

@Aspect
public class SecurityAspect {

   @Pointcut("execution(* *(..)) && @annotation(external.package.Secure)")
 public void doCheck() {}

   @Before("doCheck()")
 public void applyCheck(JoinPoint joinPoint) {
       //sth...
   }

}

I want to trigger that Aspect using the @Secure annotation in a Spring MVC controller

@Secure
@RequestMapping(value = "/test", method = RequestMethod.GET)
public void test() {
  System.out.println("test");
}

The aspects-config.xml has all encessary for considering aspects on my project.

    <aop:aspectj-autoproxy>
     <aop:include name="log" /> (non external)
     <aop:include name="sec" />
    </aop:aspectj-autoproxy>

    <bean id="log"
    class="internal.package.LogAspect"
    factory-method="aspectOf" />

    <bean id="sec"
    class="external.package.SecurityAspect"
    factory-method="aspectOf" />

Eclipse do recognize that something is binded to test() but when I startup the server, Spring cannot find class external.package.SecurityAspect

Caused by: java.lang.ClassNotFoundException: external.package.SecurityAspect

In my application I already have a non external Aspect that makes log for utility and moving the Security Aspect into the Project's package is working fine.

The most comprehensive (for me) questions I came across:

this(1) but I'm not sure that's totally correct since Eclipse do recognize that also in external Jar... but maybe is my misunderstanding;

this(2) It makes sense! I removed my external library from maven, removed any pointers on application-context.xml (right?) imported by that interface, startup and... Error creating bean with name 'log' defined in file [path/to/aspects-config.xml]: No matching factory method found: factory method 'aspectOf()'. Check that a method with the specified name exists and that it is static. (why do complains about log aspect?)

this(3) talking about <context:load-time-weaver /> but it seems not working once added on my application context xml.

THis issue is only if I use EXTERNAL JAR not in the same package.

Can someone better clarify if it is actually not possible (this(3)) or possible make external Aspect to import in projects as a third party library?


Answer:

M. Deinum in comments below noticed that factory-method="aspectOf" usage is not necessary with non aspect types (then for all my @Aspect it is not).

Removed that, startup, no exceptions and now I have a working aspect.