Skip to content

Commit 3550ba7

Browse files
refactor: Add more nice functional stuff into pagefactory helpers (#1584)
1 parent 21d92f0 commit 3550ba7

File tree

6 files changed

+64
-76
lines changed

6 files changed

+64
-76
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public class DefaultElementByBuilder extends AppiumByBuilder {
5050

5151
private static final String PRIORITY = "priority";
5252
private static final String VALUE = "value";
53-
private static final Class[] ANNOTATION_ARGUMENTS = new Class[]{};
53+
private static final Class<?>[] ANNOTATION_ARGUMENTS = new Class[]{};
5454
private static final Object[] ANNOTATION_PARAMETERS = new Object[]{};
5555

5656
public DefaultElementByBuilder(String platform, String automation) {
@@ -155,7 +155,7 @@ private By[] getBys(Class<? extends Annotation> singleLocator, Class<? extends A
155155
}
156156
}
157157

158-
return result.toArray(new By[result.size()]);
158+
return result.toArray(new By[0]);
159159
}
160160

161161
@Override

src/main/java/io/appium/java_client/pagefactory/bys/ContentType.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,5 @@
1717
package io.appium.java_client.pagefactory.bys;
1818

1919
public enum ContentType {
20-
HTML_OR_DEFAULT,
21-
NATIVE_MOBILE_SPECIFIC;
20+
HTML_OR_DEFAULT, NATIVE_MOBILE_SPECIFIC
2221
}

src/main/java/io/appium/java_client/pagefactory/bys/builder/AppiumByBuilder.java

Lines changed: 53 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.openqa.selenium.By;
2626
import org.openqa.selenium.support.pagefactory.AbstractAnnotations;
2727

28+
import javax.annotation.Nullable;
2829
import java.lang.annotation.Annotation;
2930
import java.lang.reflect.AnnotatedElement;
3031
import java.lang.reflect.Constructor;
@@ -33,6 +34,7 @@
3334
import java.lang.reflect.Proxy;
3435
import java.util.ArrayList;
3536
import java.util.List;
37+
import java.util.stream.Collectors;
3638
import java.util.stream.Stream;
3739

3840
/**
@@ -42,18 +44,19 @@
4244
* - https://code.google.com/p/selenium/wiki/PageFactory
4345
*/
4446
public abstract class AppiumByBuilder extends AbstractAnnotations {
45-
protected static final Class<?>[] DEFAULT_ANNOTATION_METHOD_ARGUMENTS = new Class<?>[] {};
47+
protected static final Class<?>[] DEFAULT_ANNOTATION_METHOD_ARGUMENTS = new Class<?>[]{};
4648

47-
private static final List<String> METHODS_TO_BE_EXCLUDED_WHEN_ANNOTATION_IS_READ =
48-
new ArrayList<String>() {
49-
private static final long serialVersionUID = 1L; {
50-
Stream.of(Object.class, Annotation.class, Proxy.class)
49+
private static final List<String> METHODS_TO_BE_EXCLUDED_WHEN_ANNOTATION_IS_READ = new ArrayList<String>() {
50+
private static final long serialVersionUID = 1L;
51+
52+
{
53+
Stream.of(Object.class, Annotation.class, Proxy.class)
5154
.map(Class::getDeclaredMethods)
5255
.map(AppiumByBuilder::getMethodNames)
5356
.flatMap(List::stream)
5457
.forEach(this::add);
55-
}
56-
};
58+
}
59+
};
5760
protected final AnnotatedElementContainer annotatedElementContainer;
5861
protected final String platform;
5962
protected final String automation;
@@ -65,79 +68,68 @@ protected AppiumByBuilder(String platform, String automation) {
6568
}
6669

6770
private static List<String> getMethodNames(Method[] methods) {
68-
List<String> names = new ArrayList<>();
69-
for (Method m : methods) {
70-
names.add(m.getName());
71-
}
72-
return names;
71+
return Stream.of(methods).map(Method::getName).collect(Collectors.toList());
7372
}
7473

7574
private static Method[] prepareAnnotationMethods(Class<? extends Annotation> annotation) {
76-
List<String> targetAnnotationMethodNamesList =
77-
getMethodNames(annotation.getDeclaredMethods());
75+
List<String> targetAnnotationMethodNamesList = getMethodNames(annotation.getDeclaredMethods());
7876
targetAnnotationMethodNamesList.removeAll(METHODS_TO_BE_EXCLUDED_WHEN_ANNOTATION_IS_READ);
79-
Method[] result = new Method[targetAnnotationMethodNamesList.size()];
80-
for (String methodName : targetAnnotationMethodNamesList) {
81-
try {
82-
result[targetAnnotationMethodNamesList.indexOf(methodName)] =
83-
annotation.getMethod(methodName, DEFAULT_ANNOTATION_METHOD_ARGUMENTS);
84-
} catch (NoSuchMethodException | SecurityException e) {
85-
throw new RuntimeException(e);
86-
}
87-
}
88-
return result;
77+
return targetAnnotationMethodNamesList.stream()
78+
.map((methodName) -> {
79+
try {
80+
return annotation.getMethod(methodName, DEFAULT_ANNOTATION_METHOD_ARGUMENTS);
81+
} catch (NoSuchMethodException | SecurityException e) {
82+
throw new RuntimeException(e);
83+
}
84+
}).toArray(Method[]::new);
8985
}
9086

9187
private static String getFilledValue(Annotation mobileBy) {
92-
Method[] values = prepareAnnotationMethods(mobileBy.getClass());
93-
for (Method value : values) {
94-
if (!String.class.equals(value.getReturnType())) {
95-
continue;
96-
}
97-
98-
try {
99-
String strategyParameter = value.invoke(mobileBy).toString();
100-
if (!strategyParameter.isEmpty()) {
101-
return value.getName();
102-
}
103-
} catch (IllegalAccessException
104-
| IllegalArgumentException
105-
| InvocationTargetException e) {
106-
throw new RuntimeException(e);
107-
}
108-
}
109-
throw new IllegalArgumentException(
110-
"@" + mobileBy.getClass().getSimpleName() + ": one of " + Strategies.strategiesNames()
111-
.toString() + " should be filled");
88+
return Stream.of(prepareAnnotationMethods(mobileBy.getClass()))
89+
.filter((method) -> String.class == method.getReturnType())
90+
.filter((method) -> {
91+
try {
92+
Object strategyParameter = method.invoke(mobileBy);
93+
return strategyParameter != null && !String.valueOf(strategyParameter).isEmpty();
94+
} catch (IllegalAccessException | IllegalArgumentException
95+
| InvocationTargetException e) {
96+
throw new RuntimeException(e);
97+
}
98+
})
99+
.findFirst()
100+
.map(Method::getName)
101+
.orElseThrow(() -> new IllegalArgumentException(
102+
String.format("@%s: one of %s should be filled",
103+
mobileBy.getClass().getSimpleName(), Strategies.strategiesNames())
104+
));
112105
}
113106

114107
private static By getMobileBy(Annotation annotation, String valueName) {
115-
Strategies[] strategies = Strategies.values();
116-
for (Strategies strategy : strategies) {
117-
if (strategy.returnValueName().equals(valueName)) {
118-
return strategy.getBy(annotation);
119-
}
120-
}
121-
throw new IllegalArgumentException(
122-
"@" + annotation.getClass().getSimpleName() + ": There is an unknown strategy "
123-
+ valueName);
108+
return Stream.of(Strategies.values())
109+
.filter((strategy) -> strategy.returnValueName().equals(valueName))
110+
.findFirst()
111+
.map((strategy) -> strategy.getBy(annotation))
112+
.orElseThrow(() -> new IllegalArgumentException(
113+
String.format("@%s: There is an unknown strategy %s",
114+
annotation.getClass().getSimpleName(), valueName)
115+
));
124116
}
125117

126-
private static <T extends By> T getComplexMobileBy(Annotation[] annotations,
127-
Class<T> requiredByClass) {
128-
By[] byArray = new By[annotations.length];
129-
for (int i = 0; i < annotations.length; i++) {
130-
byArray[i] = getMobileBy(annotations[i], getFilledValue(annotations[i]));
131-
}
118+
private static <T extends By> T getComplexMobileBy(Annotation[] annotations, Class<T> requiredByClass) {
119+
By[] byArray = Stream.of(annotations)
120+
.map((annotation) -> getMobileBy(annotation, getFilledValue(annotation)))
121+
.toArray(By[]::new);
132122
try {
133123
Constructor<T> c = requiredByClass.getConstructor(By[].class);
134-
Object[] values = new Object[] {byArray};
124+
Object[] values = new Object[]{byArray};
135125
return c.newInstance(values);
136-
} catch (Exception e) {
126+
} catch (InvocationTargetException | NoSuchMethodException | InstantiationException
127+
| IllegalAccessException e) {
137128
throw new RuntimeException(e);
138129
}
139130
}
140131

132+
@Nullable
141133
protected static By createBy(Annotation[] annotations, HowToUseSelectors howToUseLocators) {
142134
if (annotations == null || annotations.length == 0) {
143135
return null;

src/main/java/io/appium/java_client/pagefactory/bys/builder/ByChained.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ public class ByChained extends org.openqa.selenium.support.pagefactory.ByChained
3535
private static AppiumFunction<SearchContext, WebElement> getSearchingFunction(By by) {
3636
return input -> {
3737
try {
38+
if (input == null) {
39+
return null;
40+
}
3841
return input.findElement(by);
3942
} catch (NoSuchElementException e) {
4043
return null;
@@ -71,7 +74,7 @@ public WebElement findElement(SearchContext context) {
7174
checkNotNull(searchingFunction);
7275
return waiting.until(searchingFunction);
7376
} catch (TimeoutException e) {
74-
throw new NoSuchElementException("Cannot locate an element using " + toString());
77+
throw new NoSuchElementException("Cannot locate an element using " + this);
7578
}
7679
}
7780
}

src/main/java/io/appium/java_client/pagefactory/bys/builder/HowToUseSelectors.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,5 @@
1717
package io.appium.java_client.pagefactory.bys.builder;
1818

1919
public enum HowToUseSelectors {
20-
USE_ONE,
21-
BUILD_CHAINED,
22-
USE_ANY;
20+
USE_ONE, BUILD_CHAINED, USE_ANY
2321
}

src/main/java/io/appium/java_client/pagefactory/bys/builder/Strategies.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@
1919
import java.lang.annotation.Annotation;
2020
import java.lang.reflect.InvocationTargetException;
2121
import java.lang.reflect.Method;
22-
import java.util.ArrayList;
2322
import java.util.List;
23+
import java.util.stream.Collectors;
24+
import java.util.stream.Stream;
2425

2526
import org.openqa.selenium.By;
2627

@@ -127,12 +128,7 @@ enum Strategies {
127128
}
128129

129130
static List<String> strategiesNames() {
130-
Strategies[] strategies = values();
131-
List<String> result = new ArrayList<>();
132-
for (Strategies strategy : strategies) {
133-
result.add(strategy.valueName);
134-
}
135-
return result;
131+
return Stream.of(values()).map((s) -> s.valueName).collect(Collectors.toList());
136132
}
137133

138134
private static String getValue(Annotation annotation, Strategies strategy) {

0 commit comments

Comments
 (0)