diff --git a/pom.xml b/pom.xml
index f49af5bfe..8ecbafa05 100644
--- a/pom.xml
+++ b/pom.xml
@@ -31,6 +31,12 @@
org.seleniumhq.selenium
selenium-java
2.53.0
+
+
+ cglib
+ cglib-nodep
+
+
junit
@@ -48,11 +54,6 @@
guava
19.0
-
- cglib
- cglib
- 3.2.1
-
commons-validator
commons-validator
@@ -63,6 +64,11 @@
commons-lang3
3.4
+
+ cglib
+ cglib-nodep
+ 3.2.3
+
jar
java-client
diff --git a/src/main/java/io/appium/java_client/pagefactory/OverrideWidgetReader.java b/src/main/java/io/appium/java_client/pagefactory/OverrideWidgetReader.java
index 3f22d2892..52227732e 100644
--- a/src/main/java/io/appium/java_client/pagefactory/OverrideWidgetReader.java
+++ b/src/main/java/io/appium/java_client/pagefactory/OverrideWidgetReader.java
@@ -26,7 +26,6 @@
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
@@ -61,14 +60,6 @@ private static Class extends Widget> getConvenientClass(Class extends Widget
+ convenientClass.getName()));
}
- int modifiers = convenientClass.getModifiers();
- if (Modifier.isAbstract(modifiers)) {
- throw new IllegalArgumentException(
- new InstantiationException(convenientClass.getName()
- + " is abstract so "
- + "it can't be instantiated"));
- }
-
return convenientClass;
}
diff --git a/src/main/java/io/appium/java_client/pagefactory/WidgetInterceptor.java b/src/main/java/io/appium/java_client/pagefactory/WidgetInterceptor.java
index 864448389..76823a5c5 100644
--- a/src/main/java/io/appium/java_client/pagefactory/WidgetInterceptor.java
+++ b/src/main/java/io/appium/java_client/pagefactory/WidgetInterceptor.java
@@ -28,6 +28,7 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
@@ -56,7 +57,18 @@ class WidgetInterceptor extends InterceptorOfASingleElement {
.isLookUpCached())
|| cachedInstances.size() == 0) {
cachedElement = element;
- Widget widget = instantiationMap.get(type).newInstance(cachedElement);
+
+ Constructor extends Widget> constructor = instantiationMap.get(type);
+ Class extends Widget> clazz = constructor.getDeclaringClass();
+
+ int modifiers = clazz.getModifiers();
+ if (Modifier.isAbstract(modifiers)) {
+ throw new InstantiationException(clazz.getName()
+ + " is abstract so "
+ + "it can't be instantiated");
+ }
+
+ Widget widget = constructor.newInstance(cachedElement);
cachedInstances.put(type, widget);
PageFactory.initElements(new AppiumFieldDecorator(widget, duration), widget);
}
diff --git a/src/test/java/io/appium/java_client/pagefactory_tests/widgets/PartiallyOverrideNegativeWidgetTest.java b/src/test/java/io/appium/java_client/pagefactory_tests/widgets/PartiallyOverrideNegativeWidgetTest.java
new file mode 100644
index 000000000..25f9e48ee
--- /dev/null
+++ b/src/test/java/io/appium/java_client/pagefactory_tests/widgets/PartiallyOverrideNegativeWidgetTest.java
@@ -0,0 +1,63 @@
+package io.appium.java_client.pagefactory_tests.widgets;
+
+
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.pagefactory.AppiumFieldDecorator;
+import io.appium.java_client.pagefactory.TimeOutDuration;
+import io.appium.java_client.remote.MobileCapabilityType;
+import io.appium.java_client.service.local.AppiumDriverLocalService;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openqa.selenium.remote.DesiredCapabilities;
+import org.openqa.selenium.support.PageFactory;
+
+import java.io.File;
+import java.util.concurrent.TimeUnit;
+
+public class PartiallyOverrideNegativeWidgetTest {
+
+ private static AndroidDriver> driver;
+ private static AppiumDriverLocalService service;
+ private static PartiallyOverrideRottenTomatoes rottenTomatoes;
+
+ /**
+ * initialization.
+ */
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ service = AppiumDriverLocalService.buildDefaultService();
+ service.start();
+
+ File appDir = new File("src/test/java/io/appium/java_client");
+ File app = new File(appDir, "android-rottentomatoes-demo-debug.apk");
+ DesiredCapabilities capabilities = new DesiredCapabilities();
+ capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
+ capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
+ driver = new AndroidDriver<>(service.getUrl(), capabilities);
+
+ rottenTomatoes = new PartiallyOverrideRottenTomatoes();
+ PageFactory.initElements(
+ new AppiumFieldDecorator(driver, new TimeOutDuration(5, TimeUnit.SECONDS)),
+ rottenTomatoes);
+ }
+
+ /**
+ * finishing.
+ */
+ @AfterClass
+ public static void afterClass() throws Exception {
+ if (driver != null) {
+ driver.quit();
+ }
+
+ if (service != null) {
+ service.stop();
+ }
+ }
+
+ @Test(expected = InstantiationException.class)
+ public void gettingOfAnElement() {
+ rottenTomatoes.checkSimpleReview();
+ }
+}
diff --git a/src/test/java/io/appium/java_client/pagefactory_tests/widgets/PartiallyOverrideRottenTomatoes.java b/src/test/java/io/appium/java_client/pagefactory_tests/widgets/PartiallyOverrideRottenTomatoes.java
new file mode 100644
index 000000000..c5ff17455
--- /dev/null
+++ b/src/test/java/io/appium/java_client/pagefactory_tests/widgets/PartiallyOverrideRottenTomatoes.java
@@ -0,0 +1,143 @@
+package io.appium.java_client.pagefactory_tests.widgets;
+
+import static org.junit.Assert.assertTrue;
+
+import io.appium.java_client.pagefactory.AndroidFindBy;
+import io.appium.java_client.pagefactory.AndroidFindBys;
+import io.appium.java_client.pagefactory.OverrideWidget;
+import io.appium.java_client.pagefactory_tests.widgets.html.annotated.AnnotatedHtmlMovies;
+import io.appium.java_client.pagefactory_tests.widgets.html.annotated.AnnotatedHtmlReview;
+import io.appium.java_client.pagefactory_tests.widgets.html.extended.ExtendedHtmlMovies;
+import io.appium.java_client.pagefactory_tests.widgets.html.extended.ExtendedHtmlReview;
+import io.appium.java_client.pagefactory_tests.widgets.html.simple.HtmlMovies;
+import io.appium.java_client.pagefactory_tests.widgets.html.simple.HtmlReview;
+import org.apache.commons.lang3.StringUtils;
+import org.openqa.selenium.support.FindBy;
+
+public class PartiallyOverrideRottenTomatoes implements RottenTomatoesAbstractApp {
+
+ @AndroidFindBy(id = "com.codepath.example.rottentomatoes:id/lvMovies")
+ @FindBy(id = "movies-collection")
+ @OverrideWidget(html = HtmlMovies.class)
+ private Movies simpleMovies;
+
+ @FindBy(id = "main_container")
+ @AndroidFindBys({@AndroidFindBy(id = "android:id/content"),
+ @AndroidFindBy(className = "android.widget.RelativeLayout")})
+ @OverrideWidget(html = HtmlReview.class)
+ private Review simpleReview;
+
+ @OverrideWidget(html = AnnotatedHtmlMovies.class)
+ private Movies annotatedMovies;
+
+ @OverrideWidget(html = AnnotatedHtmlReview.class)
+ private Review annotatedReview;
+
+ @OverrideWidget(html = ExtendedHtmlMovies.class)
+ private Movies extendedMovies;
+
+ @OverrideWidget(html = ExtendedHtmlReview.class)
+ private Review extendedReview;
+
+
+ @FindBy(id = "Fake_ID_For_All_Platforms")
+ @OverrideWidget(html = ExtendedHtmlMovies.class)
+ private Movies fakeMovies;
+
+ @FindBy(id = "Fake_ID_For_All_Platforms")
+ @OverrideWidget(html = ExtendedHtmlReview.class)
+ private Review fakeReview;
+
+ /**
+ * It gets movie count.
+ */
+ public int getSimpleMovieCount() {
+ return simpleMovies.getMovieCount();
+ }
+
+ /**
+ * @param index is the desired index.
+ * @return a movie.
+ */
+ public Movie getASimpleMovie(int index) {
+ return simpleMovies.getMovie(index);
+ }
+
+ /**
+ * It reads a review.
+ */
+ public void checkSimpleReview() {
+ assertTrue(!StringUtils.isBlank(simpleReview.title()));
+ assertTrue(!StringUtils.isBlank(simpleReview.score()));
+ assertTrue(!StringUtils.isBlank(simpleReview.info()));
+ assertTrue(simpleReview.getPoster() != null);
+ }
+
+ /**
+ * It gets movie count.
+ */
+ public int getAnnotatedMovieCount() {
+ return annotatedMovies.getMovieCount();
+ }
+
+ /**
+ * @param index is the desired index.
+ * @return a movie.
+ */
+ public Movie getAnAnnotatedMovie(int index) {
+ return annotatedMovies.getMovie(index);
+ }
+
+ /**
+ * It reads a review.
+ */
+ public void checkAnnotatedReview() {
+ assertTrue(!StringUtils.isBlank(annotatedReview.title()));
+ assertTrue(!StringUtils.isBlank(annotatedReview.score()));
+ assertTrue(!StringUtils.isBlank(annotatedReview.info()));
+ assertTrue(annotatedReview.getPoster() != null);
+ }
+
+ /**
+ * It gets movie count.
+ */
+ public int getExtendeddMovieCount() {
+ return extendedMovies.getMovieCount();
+ }
+
+ /**
+ * @param index is the desired index.
+ * @return a movie.
+ */
+ public Movie getAnExtendedMovie(int index) {
+ return extendedMovies.getMovie(index);
+ }
+
+ /**
+ * It reads a review.
+ */
+ public void checkExtendedReview() {
+ assertTrue(!StringUtils.isBlank(extendedReview.title()));
+ assertTrue(!StringUtils.isBlank(extendedReview.score()));
+ assertTrue(!StringUtils.isBlank(extendedReview.info()));
+ assertTrue(extendedReview.getPoster() != null);
+ }
+
+ /**
+ * It gets movie count.
+ */
+ public int getFakedMovieCount() {
+ return fakeMovies.getMovieCount();
+ }
+
+ /**
+ * It reads a review.
+ */
+ public void checkFakeReview() {
+ assertTrue(!StringUtils.isBlank(fakeReview.title()));
+ assertTrue(!StringUtils.isBlank(fakeReview.score()));
+ assertTrue(!StringUtils.isBlank(fakeReview.info()));
+ assertTrue(fakeReview.getPoster() != null);
+ }
+
+}
diff --git a/src/test/java/io/appium/java_client/pagefactory_tests/widgets/PartiallyOverrideWidgetTest.java b/src/test/java/io/appium/java_client/pagefactory_tests/widgets/PartiallyOverrideWidgetTest.java
new file mode 100644
index 000000000..76207879c
--- /dev/null
+++ b/src/test/java/io/appium/java_client/pagefactory_tests/widgets/PartiallyOverrideWidgetTest.java
@@ -0,0 +1,140 @@
+package io.appium.java_client.pagefactory_tests.widgets;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import io.appium.java_client.pagefactory.AppiumFieldDecorator;
+import io.appium.java_client.pagefactory.TimeOutDuration;
+import io.appium.java_client.pagefactory_tests.widgets.html.annotated.AnnotatedHtmlMovie;
+import io.appium.java_client.pagefactory_tests.widgets.html.simple.HtmlMovie;
+import org.apache.commons.lang3.StringUtils;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.Platform;
+import org.openqa.selenium.chrome.ChromeDriver;
+import org.openqa.selenium.chrome.ChromeDriverService;
+import org.openqa.selenium.support.PageFactory;
+
+import java.io.File;
+import java.util.concurrent.TimeUnit;
+
+public class PartiallyOverrideWidgetTest implements WidgetTest {
+
+ private static ChromeDriver driver;
+ private static PartiallyOverrideRottenTomatoes rottenTomatoes;
+
+ /**
+ * initialization.
+ */
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+
+ if (Platform.getCurrent().is(Platform.WINDOWS)) {
+ System.setProperty(ChromeDriverService.CHROME_DRIVER_EXE_PROPERTY,
+ "src/test/java/io/appium/java_client/pagefactory_tests/chromedriver.exe");
+ } else {
+ System.setProperty(ChromeDriverService.CHROME_DRIVER_EXE_PROPERTY,
+ "src/test/java/io/appium/java_client/pagefactory_tests/chromedriver");
+ }
+
+ driver = new ChromeDriver();
+ driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);
+ rottenTomatoes = new PartiallyOverrideRottenTomatoes();
+ PageFactory.initElements(
+ new AppiumFieldDecorator(driver, new TimeOutDuration(5, TimeUnit.SECONDS)),
+ rottenTomatoes);
+ }
+
+ /**
+ * finishing.
+ */
+ @AfterClass
+ public static void afterClass() throws Exception {
+ if (driver != null) {
+ driver.quit();
+ }
+ }
+
+ /**
+ * The setting up.
+ */
+ @Before
+ public void setUp() throws Exception {
+ if (driver != null) {
+ driver.get(
+ new File("src/test/java/io/appium/java_client/RottenTomatoesSnapshot.html")
+ .toURI().toString());
+ }
+ }
+
+ @Test
+ @Override
+ public void checkACommonWidget() {
+ assertTrue(rottenTomatoes.getSimpleMovieCount() >= 1);
+ Movie movie = rottenTomatoes.getASimpleMovie(0);
+ assertTrue(!StringUtils.isBlank(movie.title()));
+ assertTrue(!StringUtils.isBlank(movie.score()));
+ assertNotNull(movie.getPoster());
+ movie.goToReview();
+
+ rottenTomatoes.checkSimpleReview();
+ assertTrue(movie.getSelfReference().getClass().equals(HtmlMovie.class));
+ }
+
+ @Override
+ @Test
+ public void checkAnAnnotatedWidget() {
+ assertTrue(rottenTomatoes.getAnnotatedMovieCount() >= 1);
+ Movie movie = rottenTomatoes.getAnAnnotatedMovie(0);
+ assertTrue(!StringUtils.isBlank(movie.title()));
+ assertTrue(!StringUtils.isBlank(movie.score()));
+ assertNotNull(movie.getPoster());
+ movie.goToReview();
+
+ rottenTomatoes.checkAnnotatedReview();
+ assertTrue(movie.getSelfReference().getClass().equals(AnnotatedHtmlMovie.class));
+ }
+
+
+ @Override
+ @Test
+ public void checkAnExtendedWidget() {
+ assertTrue(rottenTomatoes.getExtendeddMovieCount() >= 1);
+ Movie movie = rottenTomatoes.getAnExtendedMovie(0);
+ assertTrue(!StringUtils.isBlank(movie.title()));
+ assertTrue(!StringUtils.isBlank(movie.score()));
+ assertNotNull(movie.getPoster());
+ movie.goToReview();
+
+ rottenTomatoes.checkExtendedReview();
+ assertTrue(movie.getSelfReference().getClass().equals(AnnotatedHtmlMovie.class));
+ }
+
+ @Override
+ @Test
+ public void checkTheLocatorOverridingOnAWidget() {
+ try {
+ assertTrue(rottenTomatoes.getFakedMovieCount() == 0);
+ } catch (Exception e) {
+ if (!NoSuchElementException.class.isAssignableFrom(e.getClass())) {
+ throw e;
+ }
+ }
+
+ rottenTomatoes.getASimpleMovie(0).goToReview();
+
+ try {
+ rottenTomatoes.checkFakeReview();
+ } catch (Exception e) {
+ if (NoSuchElementException.class.isAssignableFrom(e.getClass())) {
+ return;
+ } else {
+ throw e;
+ }
+ }
+ throw new RuntimeException("Any exception was expected");
+ }
+}