IllegalArgumentException when calling PageFactory.initElements(new AppiumFieldDecorator(androidDriver), this)
See original GitHub issueThe 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<AndroidElement> {
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);
Issue Analytics
- State:
- Created 5 years ago
- Comments:12 (1 by maintainers)
Top GitHub Comments
I encountered a similar issue as well on version 6.1.0 of the java-client. I spent some time looking into the root cause, and it seems as though this particular use of the AppiumFieldDecorator with
@AndroidFindBy
or@iOSFindBy
may have been broken as of this dependency change: #832I was unable to get the cglib Enhancer class to instantiate on line 52 of the
ProxyFactory
class.Enhancer enhancer = new Enhancer();
java.lang.NoClassDefFoundError: Could not initialize class net.sf.cglib.proxy.Enhancer
A work-around for now is to exclude the cglib version from the appium java-client dependency in favor of specifying an older version.
I’m not sure if this will resolve the exact issue that @bill2605 is seeing, but it fixed my issue. Is there a specific reason why the java-client relies on cglib 3.2.5+?
Still facing this issue in appium java client and 7.5.1. Any plan to fix this?
Although excluding cglib from java client and manually adding cglib 3.2.5 solved the issue.