Skip to content

Commit 6af53a0

Browse files
refactor: Replace cglib with bytebuddy (#1923)
1 parent f2ac9e5 commit 6af53a0

25 files changed

+355
-394
lines changed

build.gradle

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ dependencies {
5151
}
5252
}
5353
implementation 'com.google.code.gson:gson:2.10.1'
54-
implementation 'cglib:cglib:3.3.0'
5554
implementation 'commons-validator:commons-validator:1.7'
5655
implementation 'org.apache.commons:commons-lang3:3.12.0'
5756
implementation 'commons-io:commons-io:2.12.0'

src/main/java/io/appium/java_client/pagefactory/AppiumElementLocatorFactory.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ public AppiumElementLocatorFactory(SearchContext searchContext, Duration duratio
5353
return this.createLocator((AnnotatedElement) field);
5454
}
5555

56-
@Override public @Nullable CacheableLocator createLocator(AnnotatedElement annotatedElement) {
56+
@Override
57+
@Nullable
58+
public CacheableLocator createLocator(AnnotatedElement annotatedElement) {
5759
Duration customDuration;
5860
if (annotatedElement.isAnnotationPresent(WithTimeout.class)) {
5961
WithTimeout withTimeout = annotatedElement.getAnnotation(WithTimeout.class);

src/main/java/io/appium/java_client/pagefactory/AppiumFieldDecorator.java

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.openqa.selenium.support.pagefactory.ElementLocator;
3333
import org.openqa.selenium.support.pagefactory.FieldDecorator;
3434

35+
import javax.annotation.Nullable;
3536
import java.lang.reflect.Constructor;
3637
import java.lang.reflect.Field;
3738
import java.lang.reflect.ParameterizedType;
@@ -92,17 +93,17 @@ public AppiumFieldDecorator(SearchContext context, Duration duration) {
9293
this.duration = duration;
9394

9495
defaultElementFieldDecoracor = new DefaultFieldDecorator(
95-
new AppiumElementLocatorFactory(context, duration,
96-
new DefaultElementByBuilder(platform, automation))) {
96+
new AppiumElementLocatorFactory(context, duration, new DefaultElementByBuilder(platform, automation))
97+
) {
9798
@Override
9899
protected WebElement proxyForLocator(ClassLoader ignored, ElementLocator locator) {
99100
return proxyForAnElement(locator);
100101
}
101102

102103
@Override
103-
@SuppressWarnings("unchecked")
104104
protected List<WebElement> proxyForListLocator(ClassLoader ignored, ElementLocator locator) {
105105
ElementListInterceptor elementInterceptor = new ElementListInterceptor(locator);
106+
//noinspection unchecked
106107
return getEnhancedProxy(ArrayList.class, elementInterceptor);
107108
}
108109

@@ -121,14 +122,14 @@ protected boolean isDecoratableList(Field field) {
121122
List<Type> bounds = (listType instanceof TypeVariable)
122123
? Arrays.asList(((TypeVariable<?>) listType).getBounds())
123124
: Collections.emptyList();
124-
125125
return availableElementClasses.stream()
126126
.anyMatch((webElClass) -> webElClass.equals(listType) || bounds.contains(webElClass));
127127
}
128128
};
129129

130-
widgetLocatorFactory =
131-
new AppiumElementLocatorFactory(context, duration, new WidgetByBuilder(platform, automation));
130+
widgetLocatorFactory = new AppiumElementLocatorFactory(
131+
context, duration, new WidgetByBuilder(platform, automation)
132+
);
132133
}
133134

134135
public AppiumFieldDecorator(SearchContext context) {
@@ -144,14 +145,10 @@ public AppiumFieldDecorator(SearchContext context) {
144145
*/
145146
public Object decorate(ClassLoader ignored, Field field) {
146147
Object result = defaultElementFieldDecoracor.decorate(ignored, field);
147-
if (result != null) {
148-
return result;
149-
}
150-
151-
return decorateWidget(field);
148+
return result == null ? decorateWidget(field) : result;
152149
}
153150

154-
@SuppressWarnings("unchecked")
151+
@Nullable
155152
private Object decorateWidget(Field field) {
156153
Class<?> type = field.getType();
157154
if (!Widget.class.isAssignableFrom(type) && !List.class.isAssignableFrom(type)) {
@@ -177,30 +174,34 @@ private Object decorateWidget(Field field) {
177174
if (!Widget.class.isAssignableFrom((Class<?>) listType)) {
178175
return null;
179176
}
177+
//noinspection unchecked
180178
widgetType = (Class<? extends Widget>) listType;
181179
} else {
182180
return null;
183181
}
184182

185183
} else {
184+
//noinspection unchecked
186185
widgetType = (Class<? extends Widget>) field.getType();
187186
}
188187

189188
CacheableLocator locator = widgetLocatorFactory.createLocator(field);
190-
Map<ContentType, Constructor<? extends Widget>> map =
191-
OverrideWidgetReader.read(widgetType, field, platform);
189+
Map<ContentType, Constructor<? extends Widget>> map = OverrideWidgetReader.read(widgetType, field, platform);
192190

193191
if (isAlist) {
194-
return getEnhancedProxy(ArrayList.class,
195-
new WidgetListInterceptor(locator, webDriver, map, widgetType,
196-
duration));
192+
return getEnhancedProxy(
193+
ArrayList.class,
194+
new WidgetListInterceptor(locator, webDriver, map, widgetType, duration)
195+
);
197196
}
198197

199-
Constructor<? extends Widget> constructor =
200-
WidgetConstructorUtil.findConvenientConstructor(widgetType);
201-
return getEnhancedProxy(widgetType, new Class[]{constructor.getParameterTypes()[0]},
198+
Constructor<? extends Widget> constructor = WidgetConstructorUtil.findConvenientConstructor(widgetType);
199+
return getEnhancedProxy(
200+
widgetType,
201+
new Class[]{constructor.getParameterTypes()[0]},
202202
new Object[]{proxyForAnElement(locator)},
203-
new WidgetInterceptor(locator, webDriver, null, map, duration));
203+
new WidgetInterceptor(locator, webDriver, null, map, duration)
204+
);
204205
}
205206

206207
private WebElement proxyForAnElement(ElementLocator locator) {

src/main/java/io/appium/java_client/pagefactory/DefaultElementByBuilder.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -206,15 +206,13 @@ public By buildBy() {
206206
String idOrName = ((Field) annotatedElementContainer.getAnnotated()).getName();
207207

208208
if (defaultBy == null && mobileNativeBy == null) {
209-
defaultBy =
210-
new ByIdOrName(((Field) annotatedElementContainer.getAnnotated()).getName());
209+
defaultBy = new ByIdOrName(((Field) annotatedElementContainer.getAnnotated()).getName());
211210
mobileNativeBy = new By.ById(idOrName);
212211
return returnMappedBy(defaultBy, mobileNativeBy);
213212
}
214213

215214
if (defaultBy == null) {
216-
defaultBy =
217-
new ByIdOrName(((Field) annotatedElementContainer.getAnnotated()).getName());
215+
defaultBy = new ByIdOrName(((Field) annotatedElementContainer.getAnnotated()).getName());
218216
return returnMappedBy(defaultBy, mobileNativeBy);
219217
}
220218

src/main/java/io/appium/java_client/pagefactory/ElementInterceptor.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,14 @@
2828
/**
2929
* Intercepts requests to {@link WebElement}.
3030
*/
31-
class ElementInterceptor extends InterceptorOfASingleElement {
31+
public class ElementInterceptor extends InterceptorOfASingleElement {
3232

33-
ElementInterceptor(ElementLocator locator, WebDriver driver) {
33+
public ElementInterceptor(ElementLocator locator, WebDriver driver) {
3434
super(locator, driver);
3535
}
3636

37-
@Override protected Object getObject(WebElement element, Method method, Object[] args)
37+
@Override
38+
protected Object getObject(WebElement element, Method method, Object[] args)
3839
throws Throwable {
3940
try {
4041
return method.invoke(element, args);

src/main/java/io/appium/java_client/pagefactory/ElementListInterceptor.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@
2828
/**
2929
* Intercepts requests to the list of {@link WebElement}.
3030
*/
31-
class ElementListInterceptor extends InterceptorOfAListOfElements {
31+
public class ElementListInterceptor extends InterceptorOfAListOfElements {
3232

33-
ElementListInterceptor(ElementLocator locator) {
33+
public ElementListInterceptor(ElementLocator locator) {
3434
super(locator);
3535
}
3636

37-
@Override protected Object getObject(List<WebElement> elements, Method method, Object[] args)
38-
throws Throwable {
37+
@Override
38+
protected Object getObject(List<WebElement> elements, Method method, Object[] args) throws Throwable {
3939
try {
4040
return method.invoke(elements, args);
4141
} catch (Throwable t) {

src/main/java/io/appium/java_client/pagefactory/ThrowableUtil.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ protected static boolean isInvalidSelectorRootCause(Throwable e) {
3333
return true;
3434
}
3535

36-
if (String.valueOf(e.getMessage()).contains(INVALID_SELECTOR_PATTERN) || String
37-
.valueOf(e.getMessage()).contains("Locator Strategy \\w+ is not supported")) {
36+
if (String.valueOf(e.getMessage()).contains(INVALID_SELECTOR_PATTERN)
37+
|| String.valueOf(e.getMessage()).contains("Locator Strategy \\w+ is not supported")) {
3838
return true;
3939
}
4040

@@ -54,8 +54,8 @@ protected static boolean isStaleElementReferenceException(Throwable e) {
5454
}
5555

5656
protected static Throwable extractReadableException(Throwable e) {
57-
if (!RuntimeException.class.equals(e.getClass()) && !InvocationTargetException.class
58-
.equals(e.getClass())) {
57+
if (!RuntimeException.class.equals(e.getClass())
58+
&& !InvocationTargetException.class.equals(e.getClass())) {
5959
return e;
6060
}
6161

src/main/java/io/appium/java_client/pagefactory/WidgetInterceptor.java

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,55 +19,62 @@
1919
import io.appium.java_client.pagefactory.bys.ContentType;
2020
import io.appium.java_client.pagefactory.interceptors.InterceptorOfASingleElement;
2121
import io.appium.java_client.pagefactory.locator.CacheableLocator;
22-
import net.sf.cglib.proxy.MethodProxy;
2322
import org.openqa.selenium.WebDriver;
2423
import org.openqa.selenium.WebElement;
2524
import org.openqa.selenium.support.PageFactory;
2625

26+
import javax.annotation.Nullable;
2727
import java.lang.reflect.Constructor;
2828
import java.lang.reflect.Method;
2929
import java.lang.reflect.Modifier;
3030
import java.time.Duration;
3131
import java.util.HashMap;
3232
import java.util.Map;
33+
import java.util.concurrent.Callable;
3334

3435
import static io.appium.java_client.pagefactory.ThrowableUtil.extractReadableException;
3536
import static io.appium.java_client.pagefactory.utils.WebDriverUnpackUtility.getCurrentContentType;
3637

37-
class WidgetInterceptor extends InterceptorOfASingleElement {
38+
public class WidgetInterceptor extends InterceptorOfASingleElement {
3839

3940
private final Map<ContentType, Constructor<? extends Widget>> instantiationMap;
4041
private final Map<ContentType, Widget> cachedInstances = new HashMap<>();
4142
private final Duration duration;
4243
private WebElement cachedElement;
4344

44-
WidgetInterceptor(CacheableLocator locator, WebDriver driver, WebElement cachedElement,
45-
Map<ContentType, Constructor<? extends Widget>> instantiationMap,
46-
Duration duration) {
45+
/**
46+
* Proxy interceptor class for widgets.
47+
*/
48+
public WidgetInterceptor(
49+
CacheableLocator locator,
50+
WebDriver driver,
51+
@Nullable
52+
WebElement cachedElement,
53+
Map<ContentType, Constructor<? extends Widget>> instantiationMap,
54+
Duration duration
55+
) {
4756
super(locator, driver);
4857
this.cachedElement = cachedElement;
4958
this.instantiationMap = instantiationMap;
5059
this.duration = duration;
5160
}
5261

53-
54-
@Override protected Object getObject(WebElement element, Method method, Object[] args)
55-
throws Throwable {
62+
@Override
63+
protected Object getObject(WebElement element, Method method, Object[] args) throws Throwable {
5664
ContentType type = getCurrentContentType(element);
5765
if (cachedElement == null
58-
|| (locator != null && !((CacheableLocator) locator)
59-
.isLookUpCached())
60-
|| cachedInstances.size() == 0) {
66+
|| (locator != null && !((CacheableLocator) locator).isLookUpCached())
67+
|| cachedInstances.isEmpty()
68+
) {
6169
cachedElement = element;
6270

6371
Constructor<? extends Widget> constructor = instantiationMap.get(type);
6472
Class<? extends Widget> clazz = constructor.getDeclaringClass();
6573

66-
int modifiers = clazz.getModifiers();
67-
if (Modifier.isAbstract(modifiers)) {
68-
throw new InstantiationException(clazz.getName()
69-
+ " is abstract so "
70-
+ "it can't be instantiated");
74+
if (Modifier.isAbstract(clazz.getModifiers())) {
75+
throw new InstantiationException(
76+
String.format("%s is abstract so it cannot be instantiated", clazz.getName())
77+
);
7178
}
7279

7380
Widget widget = constructor.newInstance(cachedElement);
@@ -82,11 +89,10 @@ class WidgetInterceptor extends InterceptorOfASingleElement {
8289
}
8390
}
8491

85-
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
86-
throws Throwable {
87-
if (locator != null) {
88-
return super.intercept(obj, method, args, proxy);
89-
}
90-
return getObject(cachedElement, method, args);
92+
@Override
93+
public Object call(Object obj, Method method, Object[] args, Callable<?> original) throws Throwable {
94+
return locator == null
95+
? getObject(cachedElement, method, args)
96+
: super.call(obj, method, args, original);
9197
}
9298
}

src/main/java/io/appium/java_client/pagefactory/WidgetListInterceptor.java

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import io.appium.java_client.pagefactory.bys.ContentType;
2020
import io.appium.java_client.pagefactory.interceptors.InterceptorOfAListOfElements;
2121
import io.appium.java_client.pagefactory.locator.CacheableLocator;
22-
import io.appium.java_client.pagefactory.utils.ProxyFactory;
2322
import org.openqa.selenium.WebDriver;
2423
import org.openqa.selenium.WebElement;
2524

@@ -31,19 +30,22 @@
3130
import java.util.Map;
3231

3332
import static io.appium.java_client.pagefactory.ThrowableUtil.extractReadableException;
33+
import static io.appium.java_client.pagefactory.utils.ProxyFactory.getEnhancedProxy;
3434
import static io.appium.java_client.pagefactory.utils.WebDriverUnpackUtility.getCurrentContentType;
3535
import static java.util.Optional.ofNullable;
3636

37-
class WidgetListInterceptor extends InterceptorOfAListOfElements {
38-
37+
public class WidgetListInterceptor extends InterceptorOfAListOfElements {
3938
private final Map<ContentType, Constructor<? extends Widget>> instantiationMap;
4039
private final List<Widget> cachedWidgets = new ArrayList<>();
4140
private final Class<? extends Widget> declaredType;
4241
private final Duration duration;
4342
private final WebDriver driver;
4443
private List<WebElement> cachedElements;
4544

46-
WidgetListInterceptor(CacheableLocator locator, WebDriver driver,
45+
/**
46+
* Proxy interceptor class for lists of widgets.
47+
*/
48+
public WidgetListInterceptor(CacheableLocator locator, WebDriver driver,
4749
Map<ContentType, Constructor<? extends Widget>> instantiationMap,
4850
Class<? extends Widget> declaredType, Duration duration) {
4951
super(locator);
@@ -53,22 +55,22 @@ class WidgetListInterceptor extends InterceptorOfAListOfElements {
5355
this.driver = driver;
5456
}
5557

56-
57-
@Override protected Object getObject(List<WebElement> elements, Method method, Object[] args)
58-
throws Throwable {
59-
if (cachedElements == null || (locator != null && !((CacheableLocator) locator)
60-
.isLookUpCached())) {
58+
@Override
59+
protected Object getObject(List<WebElement> elements, Method method, Object[] args) throws Throwable {
60+
if (cachedElements == null || (locator != null && !((CacheableLocator) locator).isLookUpCached())) {
6161
cachedElements = elements;
6262
cachedWidgets.clear();
6363

6464
ContentType type = null;
6565
for (WebElement element : cachedElements) {
6666
type = ofNullable(type).orElseGet(() -> getCurrentContentType(element));
67-
Class<?>[] params =
68-
new Class<?>[] {instantiationMap.get(type).getParameterTypes()[0]};
69-
cachedWidgets.add(ProxyFactory
70-
.getEnhancedProxy(declaredType, params, new Object[] {element},
71-
new WidgetInterceptor(null, driver, element, instantiationMap, duration)));
67+
Class<?>[] params = new Class<?>[] {instantiationMap.get(type).getParameterTypes()[0]};
68+
cachedWidgets.add(
69+
getEnhancedProxy(
70+
declaredType, params, new Object[] {element},
71+
new WidgetInterceptor(null, driver, element, instantiationMap, duration)
72+
)
73+
);
7274
}
7375
}
7476
try {

0 commit comments

Comments
 (0)