Page factory list element not initialized when parameterized by generic type

Description

Given the following class (We have a base screen class that is used for Android and iOS that each specify T as AndroidElement and IOSElement, respectively, where we want to retain the specific platform element type):

    public class ScreenWithLists<T extends MobileElement> {
        public List<MobileElement> listME;
        public List<T> listT;
    }

and initialization with:

    PageFactory.initElements(new AppiumFieldDecorator(driver),
            new ScreenWithLists<MobileElement>()); // Or AndroidElement or IOSElement

The "listT" field does not get initialized as it fails the isDecoratableList check in AppiumFieldDecorator's DefaultFieldDecorator implementation when checking the list's type is one of "availableElementClasses".

Environment

  • appium java client build version: 6.1.0
  • selenium client build version: 3.12

Details

This generic type may be able to be checked with an additional bounds check in AppiumFieldDecorator's isDecoratableList:

    if ((listType instanceof TypeVariable) &&
            Arrays.asList(((TypeVariable<?>) listType).getBounds())
            .stream().anyMatch(item -> availableElementClasses.contains(item))) {
        return true;
    }

Testing

https://github.com/appium/java-client/blob/master/src/test/java/io/appium/java_client/pagefactory_tests/GenericTest.java
could update the Supplier to:

    TempGenericPage<?> page = new TempGenericPage<>();
    PageFactory
            .initElements(new AppiumFieldDecorator(new MockWebDriver()),
                    page);
    return null != page.getItems();

Related issue:

#368

Code To Reproduce Issue [ Good To Have ]

public class ListParameterReproductionTest {
    public static class ScreenWithLists<T> {
        public List<MobileElement> listME;
        public List<T> listT;
    }

    public static void main(String[] args) {
        SearchContext mockSearchContext = new SearchContext() {
            @Override
            public <T extends WebElement> List<T> findElements(By by) {
                return null;
            }

            @Override
            public <T extends WebElement> T findElement(By by) {
                return null;
            }
        };

        ScreenWithLists<MobileElement> screen = new ScreenWithLists<MobileElement>();
        PageFactory.initElements(new AppiumFieldDecorator(mockSearchContext), screen);
        assertNotNull(screen.listME);
        assertNotNull(screen.listT);
    }
}