OverrideWidget annotation does not work due to InstantiationException with error "SomeClass is abstract so it can't be instantiated"
truebit opened this issue · 5 comments
Description
Use a abstract widget class and two subclass to implement android and iOS widgets in Page Objects. But it would fail to init the PageObjects with exception: java.lang.IllegalArgumentException: java.lang.InstantiationException: com.foobar.uitest.widgets.TheAbastractCellWidget is abstract so it can't be instantiated
Environment
- java client build version or git revision if you use some shapshot: 1.8.0_77
- Appium server version or git revision if you use some shapshot: 1.5.2
- Desktop OS/version used to run Appium if necessary: n/a
- Node.js version (unless using Appium.app|exe) or Appium CLI or Appium.app|exe: 6.0
- Mobile platform/version under test: Android
- Real device or emulator/simulator: real
Details
@iOSFindBy(uiAutomator = ".tableViews()[0].cells()\")")
@AndroidFindBy(id ="com.foobar:id/main_content")
@OverrideWidget(androidUIAutomator = AndroidCellWidget.class,iOSUIAutomation = IOSCellWidget.class)
@WithTimeout(time = 30,unit = TimeUnit.SECONDS)
public List<TheAbastractCellWidget> cells;
Scenario: TheAbastractCellWidget
is the abstract Widget class, AndroidCellWidget
is the Android implementation of it and IOSCellWidget
is the iOS implementation.
This code is put in a page object class FooPage
I debugged the code, it seems that buildDefaultBy()
method in class WidgetByBuilder
started WhatIsNeeded.DEFAULT_OR_HTML
type widget initialization before OverrideWidget mechanism and then it threw exeception.
Code To Reproduce Issue [ Good To Have ]
n/a
Ecxeption stacktraces
java.lang.IllegalArgumentException: java.lang.InstantiationException: com.foobar.uitest.widgets.MyChangbaPageFeedWorkCell is abstract so it can't be instantiated
at io.appium.java_client.pagefactory.OverrideWidgetReader.getConvenientClass(OverrideWidgetReader.java:64)
at io.appium.java_client.pagefactory.OverrideWidgetReader.getDefaultOrHTMLWidgetClass(OverrideWidgetReader.java:75)
at io.appium.java_client.pagefactory.WidgetByBuilder.getByFromDeclaredClass(WidgetByBuilder.java:67)
at io.appium.java_client.pagefactory.WidgetByBuilder.buildDefaultBy(WidgetByBuilder.java:98)
at io.appium.java_client.pagefactory.DefaultElementByBuilder.buildBy(DefaultElementByBuilder.java:185)
at io.appium.java_client.pagefactory.AppiumElementLocatorFactory.createLocator(AppiumElementLocatorFactory.java:57)
at io.appium.java_client.pagefactory.AppiumElementLocatorFactory.createLocator(AppiumElementLocatorFactory.java:44)
at io.appium.java_client.pagefactory.AppiumFieldDecorator.decorateWidget(AppiumFieldDecorator.java:193)
at io.appium.java_client.pagefactory.AppiumFieldDecorator.decorate(AppiumFieldDecorator.java:160)
at org.openqa.selenium.support.PageFactory.proxyFields(PageFactory.java:113)
at org.openqa.selenium.support.PageFactory.initElements(PageFactory.java:105)
at com.foobar.uitest.pages.FooPage.(BasePage.java:32)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:86)
at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:514)
at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:215)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:589)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:820)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1128)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:129)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:112)
at org.testng.TestRunner.privateRun(TestRunner.java:782)
at org.testng.TestRunner.run(TestRunner.java:632)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:366)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:361)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:319)
at org.testng.SuiteRunner.run(SuiteRunner.java:268)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1244)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1169)
at org.testng.TestNG.run(TestNG.java:1064)
at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:74)
at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:121)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.lang.InstantiationException: com.foobar.uitest.widgets.TheAbastractCellWidget is abstract so it can't be instantiated
at io.appium.java_client.pagefactory.OverrideWidgetReader.getConvenientClass(OverrideWidgetReader.java:65)
... 45 more
Link to Appium logs
no need
According to this page-object doc section "what-if-interaction-with-a-widget-has-special-details-for-each-used-platform-but-the-same-at-high-level". It seems that it's the restriction of OverrideWidget
After I followed the instruction in section what-if-interaction-with-a-widget-has-special-details-for-each-used-platform-but-the-same-at-high-level":
I moved iOSFindBy
and AndroidFindBy
annotations to the implementation class, the exception still exists. reopen.
I do not know the WidgetBuilder
design. According to my trace of the code execution flow, OverrideWidget
annotation element calls WidgetByBuilder
's method to execute buildDefaultBy()
first; which would got to getByFromDeclaredClass(WhatIsNeeded.DEFAULT_OR_HTML)
. This method would require the Wigdet class who must be not abstract.
According to the document mentioned above, an abstract widget class should be the correct way to use OverrideWidget
. So I think this should be bug in the design
After several trace, I think I know the root cause:
OverrideWidget
annotation must be specified with html
argument. My case only contains androidUIAutomator
and iOSUIAutomation
.
If I assign html
with any class in andorid or ios. it works...
IMO, OverrideWidget
should support annotation without html
assignment
Yes. I was apble to reproduce that issue. I'm going to fix it ASAP.