javaspring-bootaopaspectjpicocli

AspectJ and PicoCLI does not populate properties as expected


I'm creating an annotation to attach an Aspect that would take care of authenticating an user before running a CLI command in my Spring Boot app.

Here are the components:

// The annotation
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Authenticated {}
// The aspec
@Aspect
@Component
@Order(Ordered.LOWEST_PRECEDENCE)
class AuthenticatedAspect {

    @Around("@annotation(com.menighin.picoclijava.annotation.Authenticated)")
    public Object doAuthentication(ProceedingJoinPoint joinPoint) throws Throwable {
        return joinPoint.proceed();
    }
}
// The PicoCLI command
@Component
@Command(name = "testing", description = "Testing command")
public class TestingCommandJava implements Runnable {

    @Option(
        names = {"-ci", "--creator-initials"},
        description = "The initials of the creator",
        required = true
    )
    private String creatorInitials;

    // setters and getters

    @Override
    @Authenticated
    public void run() {
        System.out.println("hi!");
    }
}
// The boot app
@SpringBootApplication
public class PicoclijavaApplication implements CommandLineRunner {

    @Autowired
    private TestingCommandJava testingCommand;

    public static void main(String[] args) {
        SpringApplication.run(PicoclijavaApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        var cmd = new CommandLine(testingCommand);
        cmd.execute(args);
    }
}

Before going further into the implementation itself Im already facing the issue where the creatorInitials are not set when I have the aspect run.

Checking this and this answers by @kriegaex my understanding is this happens because:

So my questions are:

Thanks!


Solution

  • I quickly copied your code and also checked PicoCLI's manual section about Spring Boot. It explicitly warns about the dynamic proxy situation and recommends setter injection:

    enter image description here Your source code mentions, that you have getters and setters anyway, so you can just move the annotation onto the setter:

      @Option(
        names = { "-ci", "--creator-initials" },
        description = "The initials of the creator",
        required = true
      )
      public void setCreatorInitials(String creatorInitials) {
        this.creatorInitials = creatorInitials;
      }
    

    Now, it works flawlessly without any ugly reflection in the aspect.