appium / appium/java-client

IllegalArgumentException when calling PageFactory.initElements(new AppiumFieldDecorator(androidDriver), this)

Open
#1,100 12 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.