Search code examples
javaspringspring-bootaopspring-aop

@Autowire returns null after adding Spring AOP in an abstract base class


I'm using POM in my selenium automation project, so there is an abstract class BasePage extended by a DerivedPage which is used for test method

The method which returns Webdriver works before aop was applied, but keeps returning null after aspect annotation.

From my view, spring aop proxy wrapped the primal instance of DerivedPage, which already init the Webdriver, and overwrite getDriver to get it. But it doesn't work as expected.

I know there are two inheritance: BasePage -> DerivedPage -> AOP Proxy, but can't figure out why it can't get the @Autowired object.

Example Basepage

@Component
@Scope("cucumber-glue")
public abstract class BasePage {
    @Autowired protected WebDriver driver;

    @PostConstruct
    private void postConstruct() {
        PageFactory.initElements(driver, this);
    }

    //driver found after remove this aspect annotation
    @TakeScreenshot
    public WebDriver getDriver() {
        return driver;
    }

Example DerivedPage

@Component
@Scope("cucumber-glue")
public class DerivedPage extends BasePage {
    @FindBy(css = "a[href*=\"member\"]#custom-btn")
    public WebElement memberButton;
}

Example Aspect Class

@Aspect
@Component
public class ScreenshotAspect {
    @Around("@annotation(TakeScreenshot)")
    public void take(){
        ScreenshotUtil.doCaptureFullScreen();
    }
}

Example Test Method

public class SampleSteps {
    @Autowired
    private DerivedPage derivedPage;

    @Test
    public void test() {
        System.out.println(derivedPage.getDriver()); //returns null, but screenshot was taken
    }

}

Edit:

Here I posted a simple MCVE project to reproduce the issue https://github.com/Cordifhyura/Spring-AOP-issue

result:

Testing started at 14:10 ...
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

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

Starting ChromeDriver 100.0.4896.60 (6a5d10861ce8de5fce22564658033b43cb7de047-refs/branch-heads/4896@{#875}) on port 40627
Only local connections are allowed.
Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe.
ChromeDriver was started successfully.
[2022-04-28 14:10:48.832] - 31332 INFO [Forwarding newSession on session null to remote] --- org.openqa.selenium.remote.ProtocolHandshake: Detected dialect: W3C
Starting - enter holo homepage and click member
ChromeDriver: chrome on WINDOWS (898dda5b1132c26741c8f8db732c1dc1) **//direct Webdriver reference in Hooks**
base.PO.HoloPage$$EnhancerBySpringCGLIB$$1308317
simulate screen capture
null **//.getDriver() in pageobject**

1 Scenarios (1 passed)
1 Steps (1 passed)
0m4.255s

As you can see the driver is correctly injected to Hook, so it's nothing with the DI or cucumber. It just missing in the AOP proxy instance.


Solution

  • The ScreenshotAspect is incorrect.

    The @Around advice should have a valid proceed() as explained in the documenation section : Around Advice

    Do read through the information section starting with "If you declare the return type of your around advice method as void, null will always be returned to the caller,.." as well to understand what could have caused the null value to be returned.