Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java.lang.ClassCastException: com.sun.proxy.$Proxy8 cannot be cast to org.openqa.selenium.internal.WrapsDriver

I have following pointcut and the given advice in AspectJ

@Pointcut("(call(* org.openqa.selenium.WebElement.sendKeys(..)))")
    public void onWebElementAction() {
}

@After("onWebElementAction() && target(webelement)")
public void afterWebElementAction(JoinPoint joinPoint, WebElement webelement) {
    System.out.println(webelement.getAttribute("name")); //1
    WebDriver driver = ((WrapsDriver) webelement).getWrappedDriver(); //2
    //DO SOMETHING HERE
}

While the line 1 is executed without any error. It is on line 2 I get error

java.lang.ClassCastException: com.sun.proxy.$Proxy8 cannot be cast to org.openqa.selenium.internal.WrapsDriver

The casting works in other places without issues. Can someone please help?

like image 903
Priyadarshi Kunal Avatar asked Jan 12 '23 15:01

Priyadarshi Kunal


2 Answers

While the answer flagged as correct does point out the issue, it doesn't explain the issue nor suggests a solution which does actually exist. Let me begin with giving a bit more of detail around the underlying issue here which is the way the WebElement could have been instantiated.

On one hand, when a WebElement gets instantiated as the result of a call to WebDriver#findElement, the actual RemoteWebElement object gets constructed at that very moment, however, when a WebElement gets instantiated via PageFactory#initElements, the actual concrete class object (RemoteWebElement) doesn't get created at that point but instead a proxy does.

Here is where the main issue relies. The proxy object does NOT implement the WrapsDriver interface and that is why the cast exception is thrown, which is perfectly fine. However, if you are curious enough to see how the actual proxy creation is done (at least by the default decorator), you will see that the object instantiated as the proxy does instead implement the WrapsElement interface which does offer the method getWrappedElement so, with it, you can extract the underlying WebElement and then with this, extract the underlying WebDriver, just as you are trying.

Now, the key here is that any WebElement instantiated via WebDriver#findElement does not implement WrapsElement because it is the actual element and not a proxy so, before you attempt using WrapsElement#getWrappedElement, you first need to check if the passed WebElement is actually a proxy or not.

You can achieve this with reflection, i.e.

if(WrapsElement.class.isAssignableFrom(element.getClass()))
  webDriver = ((WrapsDriver)((WrapsElement)element).getWrappedElement()).getWrappedDriver();
else
  webDriver = ((WrapsDriver)element).getWrappedDriver();

tl;dr The WebElement instance you are using was instantiated via PageFactory#initElements and you first need to extract the underlying WebElement with WrapsElement#getWrappedElement and then the WebDriver from it.

like image 127
elbaloo Avatar answered Jan 31 '23 19:01

elbaloo


This is a wild guess since I don't see a case where it actually worked. From the exception it seems that the WebElement that is being passed to afterWebElementAction is initialized via PageFactory. My guess is that if you pass WebElement derived from driver.findElement(), to afterWebElementAction, you wouldn't get casting exception. This is how it must be working for you in other cases most likely.

like image 34
nilesh Avatar answered Jan 31 '23 18:01

nilesh