Why doesn't my aspect get applied?

Why doesn’t my aspect get applied? Notice the aspect is in the same package as the aspected method’s class so it should work fine

import lib.*;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MyClass {
    public static void main(String args[]) {
        var context = new AnnotationConfigApplicationContext(Config.class);
        SomeBean someBean = context.getBean(SomeBean.class);
        String returnedVal = someBean.someAspectedMethod();
        System.out.println(returnedVal);
        System.out.println(returnedVal.getClass());
    }
}
package lib;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan
@EnableAspectJAutoProxy
public class Config {
}
package lib;

import org.springframework.stereotype.Component;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;

@Aspect
@Component
public class SomeAspect {
    
    @Around("execution(String lib.SomeBean.someAspectedMethod())")
    public Object methodAspect(ProceedingJoinPoint joinPoint) {
        System.out.println("Running methodAspect()..."); // never gets printed
        Object object = joinPoint.proceed();
        return object;
    }
}
package lib;

import org.springframework.stereotype.Component;

@Component
public class SomeBean {
    public String someAspectedMethod() {
        return "some string";
    }
}

Console output:

some string
class java.lang.String

For some reason, Jdoodle made all of my beans lazy. I have no idea why. Here’s how I discovered it

@Component
public class SomeBean {
    public SomeBean() {
        System.out.println("Creating SomeBean..."); // let's see if the bean...
    }

    public String someAspectedMethod() {
        return "some string";
    }
}
@Aspect
@Component
public class SomeAspect {
    
    public SomeAspect() {
        System.out.println("Creating SomeAspect..."); // ...or the aspect is instantiated...
    }
    
    @Around("execution(String lib.SomeBean.someAspectedMethod())")
    public Object methodAdvice(ProceedingJoinPoint joinPoint) {
        System.out.println("Running methodAspect()...");
        Object object = null;
        try {
            object = joinPoint.proceed();
        } catch (Throwable ignored) {}
        return object;
    }
}
public class MyClass {
    public static void main(String args[]) {
        var context = new AnnotationConfigApplicationContext(Config.class); // ...if I only create the context in my main
        // SomeAspect someAspect = context.getBean(SomeAspect.class);
        // SomeBean someBean = context.getBean(SomeBean.class);
        // String returnedVal = someBean.someAspectedMethod();
        // System.out.println(returnedVal);
        // System.out.println(returnedVal.getClass());
    }
}

Console output:


If I call getBean() to force instantiation of both SomeBean and SomeAspect, the aspect is created and is applied

public class MyClass {
    public static void main(String args[]) {
        var context = new AnnotationConfigApplicationContext(Config.class);
        SomeAspect someAspect = context.getBean(SomeAspect.class); // notice this
        SomeBean someBean = context.getBean(SomeBean.class);
        String returnedVal = someBean.someAspectedMethod();
        System.out.println(returnedVal);
        System.out.println(returnedVal.getClass());
    }
}

Console output:

Creating SomeAspect...
Creaeting SomeBean...
Running methodAspect()...
some string
class java.lang.String

Is Jdoodle broken? :thinking:

P.S.: By the way, I made the whole project to see what happens if the advice method’s return type is different from the intercepted method’s. The answer is the proxy will try to cast one to another. How do I know it? I tried returning new Object() to see where a ClassCastException will be thrown

    @Around("execution(String lib.SomeBean.someAspectedMethod())")
    public Object methodAdvice(ProceedingJoinPoint joinPoint) {
        System.out.println("Running methodAspect()...");
        Object object = null;
        try {
            object = joinPoint.proceed();
        } catch (Throwable ignored) {}
        return new Object();
    }

Console output:

Creating SomeAspect...
Creaeting SomeBean...
Running methodAspect()...

Exception in thread "main" java.lang.ClassCastException: class java.lang.Object cannot be cast to class java.lang.String (java.lang.Object and java.lang.String are in module java.base of loader 'bootstrap')
	at lib.SomeBean$$SpringCGLIB$$0.someAspectedMethod(<generated>)
	at MyClass.main(MyClass.java:14)

lib.SomeBean$$SpringCGLIB$$0 is SomeBean’s child generated at runtime by Spring (or rather, the library CGLIB to whom Spring delegates the job) to intercept aspected methods and perform aspect logic