IllegalArgumentException when calling PageFactory.initElements(new AppiumFieldDecorator(androidDriver), this)
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 1.3k
- Forks
- 752
- Avg merge
- 6d 21h
- Merged PRs (30d)
- 8
Description
The problem
When trying to init PageObjects classes with annotations like AndroidFindBy, i am unable to get past the PageFactory.initElements(new AppiumFieldDecorator(androidDriver), this). Test will fail with illegal argument exception and not much details as to which argument is invalid and why.
Environment
appium version: 1.10.1
appium java client: 7.0.0
node ver: v9.10.1
android im: pixel 2 xl api 27
desktop: mac (latest)
Link to Appium logs
Appium log: https://gist.github.com/bill2605/583f868e59f7852f4aebfc42f942c6cd
Code To Reproduce Issue
Note that i am using Spring for my framework. That being said below is the code to initialize an AndroidDriver to be used by the pageObjects.
`@Service
@Profile("android")
public class AndroidDriverLoader {
private final Logger logger = LoggerFactory.getLogger(AndroidDriverLoader.class);
@Resource
protected ConfigProperty configProperty;
public AndroidDriver<AndroidElement> driver;
private AppiumDriverLocalService appiumDriverLocalService;
@PostConstruct
public void androidDriverLoaderInit() {
loadDriver();
}
/**
* load the specific android driver based on reference
*/
private void loadDriver() {
final DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
if (Objects.equals(configProperty.getMobileType(), "emulator")) {
desiredCapabilities.setCapability(AndroidMobileCapabilityType.AVD, configProperty.getAndroidAvd());
desiredCapabilities.setCapability(MobileCapabilityType.APP, configProperty.getAndroidApp());
appiumDriverLocalService = getDefaultAppiumLocalService();
appiumDriverLocalService.start();
driver = new AndroidDriver<>(appiumDriverLocalService, getDefaultAndroidCapabilities().merge(desiredCapabilities));
}
}
private DesiredCapabilities getDefaultAndroidCapabilities() {
final DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
desiredCapabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, AutomationName.ANDROID_UIAUTOMATOR2);
desiredCapabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, Platform.ANDROID);
desiredCapabilities.setCapability(MobileCapabilityType.DEVICE_NAME, configProperty.getAndroidDeviceName());
desiredCapabilities.setCapability(AndroidMobileCapabilityType.NO_SIGN, true);
desiredCapabilities.setCapability(MobileCapabilityType.FULL_RESET, false);
desiredCapabilities.setCapability(MobileCapabilityType.NO_RESET, true);
desiredCapabilities
.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, Integer.parseInt(configProperty.getCommandTimeOut()));
return desiredCapabilities;
}
/**
* return default appium local service
*
* @return {@link AppiumDriverLocalService}
*/
private AppiumDriverLocalService getDefaultAppiumLocalService() {
return new AppiumServiceBuilder()
.usingDriverExecutable(Paths.get(configProperty.getAppiumDriverExecutable()).toFile())
.withAppiumJS(Paths.get(configProperty.getAppiumJs()).toFile())
.withIPAddress(configProperty.getServiceIPAddress())
.usingPort(Integer.parseInt(configProperty.getAppiumPort()))
.withArgument(GeneralServerFlag.LOCAL_TIMEZONE)
.build();
}
public AndroidDriver<AndroidElement> getDriver() {
return driver;
}`
Each PageObject extends AndroidAbstractView
which holds the following information:
`@Service
@Profile("android")
public abstract class AndroidAbstractView implements RemoteElementUtils {
private final Logger logger = LoggerFactory.getLogger(AndroidAbstractView.class);
@Resource
protected AndroidDriverLoader androidDriverLoader;
@Resource
protected ConfigProperty configProperty;
protected static AppiumDriver androidDriver;
private String iconLoadingId = "item_loading_view";
private String loadingViewRefreshXpath = "//android.view.ViewGroup[contains(@resource-id, 'id/swipe_refresh_layout')]/android.widget.ImageView";
@PostConstruct
protected abstract void init();
Note that RemoteElementUtils is just an interface for all findElementby, waitForVisibible to be implemented for Web, Android and IOS (nothing fancy there)
PageObject is as follow:
`@Service
@Profile("android")
public class LoginView extends AndroidAbstractView {
@AndroidFindBy(xpath = "//*[contains(@resource-id, 'login_username_auto_complete_text_view')]")
protected AndroidElement inputUserName;
@AndroidFindBy(xpath = "//*[contains(@resource-id, 'login_next_button')]")
protected AndroidElement buttonContinue;
@AndroidFindBy(xpath = "//*[contains(@resource-id, 'login_password_edit_text')]")
protected AndroidElement inputPassword;
@AndroidFindBy(xpath = "//*[contains(@resource-id, 'login_password_log_in_button')]")
protected AndroidElement buttonLogin;
@AndroidFindBy(id = "login_username_dev_stuff_button")
protected AndroidElement buttonDevStuff;
@AndroidFindBy(id = "def_stuff_api_base_url_edit_text")
protected AndroidElement inputApiEndPointUrl;
@AndroidFindBy(id = "def_stuff_api_base_url_button")
protected AndroidElement buttonApply;
@PostConstruct
public void init()
{
this.androidDriver = androidDriverLoader.getDriver();
PageFactory.initElements(new AppiumFieldDecorator(androidDriver), this);
}
public void login(final String userName, final String password) {...}`
When running a test for android, using debugger i see that the driver is created and ready to be used. but whenever it reaches PageFactory.initElements(new AppiumFieldDecorator(androidDriver), this);
the following error is returned:
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'loginView': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException
Exception in thread "main" java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
at cucumber.runtime.java.spring.CucumberTestContextManager.getContext(SpringFactory.java:247)
at cucumber.runtime.java.spring.CucumberTestContextManager.<init>(SpringFactory.java:239)
at cucumber.runtime.java.spring.SpringFactory.start(SpringFactory.java:132)
at cucumber.runtime.java.JavaBackend.buildWorld(JavaBackend.java:114)
at cucumber.runner.Runner.buildBackendWorlds(Runner.java:120)
at cucumber.runner.Runner.runPickle(Runner.java:38)
at cucumber.runtime.Runtime$1.run(Runtime.java:84)
at cucumber.runtime.Runtime$SameThreadExecutorService.execute(Runtime.java:220)
at cucumber.runtime.Runtime.run(Runtime.java:81)
at cucumber.api.cli.Main.run(Main.java:26)
at cucumber.api.cli.Main.main(Main.java:8)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'loginView': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:139)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:419)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1736)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:576)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:848)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:865)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:548)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:128)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:108)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:251)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
... 12 more
Caused by: java.lang.IllegalArgumentException
at net.sf.cglib.asm.ClassReader.<init>(Unknown Source)
at net.sf.cglib.asm.ClassReader.<init>(Unknown Source)
at net.sf.cglib.asm.ClassReader.<init>(Unknown Source)
at net.sf.cglib.proxy.BridgeMethodResolver.resolveAll(BridgeMethodResolver.java:61)
at net.sf.cglib.proxy.Enhancer.emitMethods(Enhancer.java:911)
at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:498)
at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:304)
at io.appium.java_client.pagefactory.utils.ProxyFactory.getEnhancedProxy(ProxyFactory.java:55)
at io.appium.java_client.pagefactory.utils.ProxyFactory.getEnhancedProxy(ProxyFactory.java:33)
at io.appium.java_client.pagefactory.AppiumFieldDecorator.proxyForAnElement(AppiumFieldDecorator.java:217)
at io.appium.java_client.pagefactory.AppiumFieldDecorator.access$0(AppiumFieldDecorator.java:215)
at io.appium.java_client.pagefactory.AppiumFieldDecorator$1.proxyForLocator(AppiumFieldDecorator.java:107)
at org.openqa.selenium.support.pagefactory.DefaultFieldDecorator.decorate(DefaultFieldDecorator.java:62)
at io.appium.java_client.pagefactory.AppiumFieldDecorator.decorate(AppiumFieldDecorator.java:155)
at org.openqa.selenium.support.PageFactory.proxyFields(PageFactory.java:113)
at org.openqa.selenium.support.PageFactory.initElements(PageFactory.java:105)
at com.workjam.platform.frontend.android.view.LoginView.init(LoginView.java:35)
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 org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:363)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:307)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:136)
... 29 more
When attempting to debug code i made it all the way to method from io.appium.java_client.pagefactory.utils.ProxyFactory;
public static <T> T getEnhancedProxy(Class<T> requiredClazz, Class<?>[] params, Object[] values,
MethodInterceptor interceptor) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(requiredClazz);
enhancer.setCallback(interceptor);
return (T) enhancer.create(params, values);
}
and crash occurs at return (T) enhancer.create(params, values);
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at LoginView.init(), where PageFactory.initElements(new AppiumFieldDecorator(androidDriver), this) triggers the failure, then trace AppiumFieldDecorator.proxyForAnElement and ProxyFactory.getEnhancedProxy in the stack trace. Reproduce the Android page-object initialization and inspect the reported cglib ClassReader exception; done means initialization completes without the IllegalArgumentException.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- mobile-dev, testing-qa
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100