1919import io .appium .java_client .pagefactory .bys .ContentMappedBy ;
2020import io .appium .java_client .pagefactory .bys .ContentType ;
2121import io .appium .java_client .pagefactory .bys .builder .AppiumByBuilder ;
22+ import io .appium .java_client .pagefactory .bys .builder .ByChained ;
2223import io .appium .java_client .pagefactory .bys .builder .HowToUseSelectors ;
2324import org .openqa .selenium .By ;
2425import org .openqa .selenium .support .ByIdOrName ;
2526import org .openqa .selenium .support .CacheLookup ;
2627import org .openqa .selenium .support .FindAll ;
2728import org .openqa .selenium .support .FindBy ;
2829import org .openqa .selenium .support .FindBys ;
30+ import org .openqa .selenium .support .pagefactory .ByAll ;
2931
3032import java .lang .annotation .Annotation ;
3133import java .lang .reflect .AnnotatedElement ;
3537import java .util .Comparator ;
3638import java .util .HashMap ;
3739import java .util .Map ;
38- import java .util .Optional ;
40+
41+ import static java .util .Arrays .sort ;
42+ import static java .util .Optional .ofNullable ;
43+ import static org .apache .commons .lang3 .ArrayUtils .add ;
44+ import static org .apache .commons .lang3 .ArrayUtils .addAll ;
3945
4046public class DefaultElementByBuilder extends AppiumByBuilder {
4147
@@ -58,17 +64,16 @@ private static void checkDisallowedAnnotationPairs(Annotation a1, Annotation a2)
5864 }
5965 }
6066
61- private static By buildMobileBy (LocatorGroupStrategy locatorGroupStrategy , Annotation [] annotations ) {
62- if (annotations .length == 1 ) {
63- return createBy (new Annotation [] {annotations [0 ]}, HowToUseSelectors .USE_ONE );
64- } else {
65- LocatorGroupStrategy strategy = Optional .ofNullable (locatorGroupStrategy )
66- .orElse (LocatorGroupStrategy .CHAIN );
67- if (strategy .equals (LocatorGroupStrategy .ALL_POSSIBLE )) {
68- return createBy (annotations , HowToUseSelectors .USE_ANY );
69- }
70- return createBy (annotations , HowToUseSelectors .BUILD_CHAINED );
67+ private static By buildMobileBy (LocatorGroupStrategy locatorGroupStrategy , By [] bys ) {
68+ if (bys .length == 0 ) {
69+ return null ;
7170 }
71+ LocatorGroupStrategy strategy = ofNullable (locatorGroupStrategy )
72+ .orElse (LocatorGroupStrategy .CHAIN );
73+ if (strategy .equals (LocatorGroupStrategy .ALL_POSSIBLE )) {
74+ return new ByAll (bys );
75+ }
76+ return new ByChained (bys );
7277 }
7378
7479 @ Override protected void assertValidAnnotations () {
@@ -105,105 +110,80 @@ private static By buildMobileBy(LocatorGroupStrategy locatorGroupStrategy, Annot
105110 return defaultBy ;
106111 }
107112
108- @ Override protected By buildMobileNativeBy () {
113+ private By [] getBys (Class <? extends Annotation > singleLocator , Class <? extends Annotation > chainedLocator ,
114+ Class <? extends Annotation > allLocator ) {
115+ AnnotationComparator comparator = new AnnotationComparator ();
109116 AnnotatedElement annotatedElement = annotatedElementContainer .getAnnotated ();
110- HowToUseLocators howToUseLocators = annotatedElement .getAnnotation (HowToUseLocators .class );
111117
112- if (isSelendroidAutomation ()) {
113- SelendroidFindBy [] selendroidFindByArray =
114- annotatedElement .getAnnotationsByType (SelendroidFindBy .class );
115- //should be kept for some time
116- SelendroidFindBys selendroidFindBys =
117- annotatedElement .getAnnotation (SelendroidFindBys .class );
118- SelendroidFindAll selendroidFindByAll =
119- annotatedElement .getAnnotation (SelendroidFindAll .class );
120-
121- if (selendroidFindByArray != null && selendroidFindByArray .length == 1 ) {
122- return createBy (new Annotation [] {selendroidFindByArray [0 ]}, HowToUseSelectors .USE_ONE );
123- }
118+ Annotation [] annotations = annotatedElement .getAnnotationsByType (singleLocator );
119+ annotations = addAll (annotations , annotatedElement .getAnnotationsByType (chainedLocator ));
120+ annotations = addAll (annotations , annotatedElement .getAnnotationsByType (allLocator ));
124121
125- if (selendroidFindBys != null ) {
126- return createBy (selendroidFindBys .value (), HowToUseSelectors .BUILD_CHAINED );
127- }
122+ sort (annotations , comparator );
123+ By [] result = new By [] {};
128124
129- if (selendroidFindByAll != null ) {
130- return createBy (selendroidFindByAll .value (), HowToUseSelectors .USE_ANY );
125+ for (Annotation a : annotations ) {
126+ Class <?> annotationClass = a .getClass ().getInterfaces ()[0 ];
127+ if (singleLocator .equals (annotationClass )) {
128+ result = add (result , createBy (new Annotation [] {a }, HowToUseSelectors .USE_ONE ));
129+ continue ;
131130 }
132- ///////////////////////////////////////
133- //code that supposed to be supported
134- if (selendroidFindByArray != null && selendroidFindByArray .length > 0 ) {
135- return buildMobileBy (howToUseLocators != null ? howToUseLocators .selendroidAutomation () : null ,
136- selendroidFindByArray );
137- }
138- }
139131
140- if ( isAndroid ()) {
141- AndroidFindBy [] androidFindByArray = annotatedElement . getAnnotationsByType ( AndroidFindBy . class ) ;
142- //should be kept for some time
143- AndroidFindBys androidFindBys = annotatedElement . getAnnotation ( AndroidFindBys . class );
144- AndroidFindAll androidFindAll = annotatedElement . getAnnotation ( AndroidFindAll . class );
145-
146- if ( androidFindByArray != null && androidFindByArray . length == 1 ) {
147- return createBy ( new Annotation [] { androidFindByArray [ 0 ]}, HowToUseSelectors . USE_ONE );
132+ Method value ;
133+ Annotation [] set ;
134+ try {
135+ value = annotationClass . getMethod ( VALUE , ANNOTATION_ARGUMENTS );
136+ set = ( Annotation []) value . invoke ( a , ANNOTATION_PARAMETERS );
137+ } catch ( NoSuchMethodException | IllegalAccessException | InvocationTargetException e ) {
138+ throw new ClassCastException ( String . format ( "The annotation '%s' has no convenient '%s' method which " +
139+ "returns array of annotations" , annotationClass . getName (), VALUE ) );
148140 }
149141
150- if (androidFindBys != null ) {
151- return createBy (androidFindBys .value (), HowToUseSelectors .BUILD_CHAINED );
142+ sort (set , comparator );
143+ if (chainedLocator .equals (annotationClass )) {
144+ result = add (result , createBy (set , HowToUseSelectors .BUILD_CHAINED ));
145+ continue ;
152146 }
153147
154- if (androidFindAll != null ) {
155- return createBy (androidFindAll .value (), HowToUseSelectors .USE_ANY );
156- }
157- ///////////////////////////////////////
158- //code that supposed to be supported
159- if (androidFindByArray != null && androidFindByArray .length > 0 ) {
160- return buildMobileBy (howToUseLocators != null ? howToUseLocators .androidAutomation () : null ,
161- androidFindByArray );
148+ if (allLocator .equals (annotationClass )) {
149+ result = add (result , createBy (set , HowToUseSelectors .USE_ANY ));
162150 }
163151 }
164152
165- if (isIOSXcuit ()) {
166- iOSXCUITFindBy [] xCuitFindByArray = annotatedElement .getAnnotationsByType (iOSXCUITFindBy .class );
167- if (xCuitFindByArray != null && xCuitFindByArray .length > 0 ) {
168- return buildMobileBy (howToUseLocators != null ? howToUseLocators .iOSXCUITAutomation () : null ,
169- xCuitFindByArray );
170- }
171- }
153+ return result ;
154+ }
172155
173- if (isIOS ()) {
174- iOSFindBy [] iOSFindByArray = annotatedElement .getAnnotationsByType (iOSFindBy .class );
175- //should be kept for some time
176- iOSFindBys iOSFindBys = annotatedElement .getAnnotation (iOSFindBys .class );
177- iOSFindAll iOSFindAll = annotatedElement .getAnnotation (iOSFindAll .class );
156+ @ Override protected By buildMobileNativeBy () {
157+ AnnotatedElement annotatedElement = annotatedElementContainer .getAnnotated ();
158+ HowToUseLocators howToUseLocators = annotatedElement .getAnnotation (HowToUseLocators .class );
178159
179- if (iOSFindByArray != null && iOSFindByArray .length == 1 ) {
180- return createBy (new Annotation [] {iOSFindByArray [0 ]}, HowToUseSelectors .USE_ONE );
181- }
160+ By result = null ;
161+ if (isSelendroidAutomation ()) {
162+ result = buildMobileBy (howToUseLocators != null ? howToUseLocators .selendroidAutomation () : null ,
163+ getBys (SelendroidFindBy .class , SelendroidFindBys .class , SelendroidFindAll .class ));
164+ }
182165
183- if (iOSFindBys != null ) {
184- return createBy (iOSFindBys .value (), HowToUseSelectors .BUILD_CHAINED );
185- }
166+ if (isAndroid () && result == null ) {
167+ result = buildMobileBy (howToUseLocators != null ? howToUseLocators .androidAutomation () : null ,
168+ getBys (AndroidFindBy .class , AndroidFindBys .class , AndroidFindAll .class ));
169+ }
186170
187- if (iOSFindAll != null ) {
188- return createBy (iOSFindAll .value (), HowToUseSelectors .USE_ANY );
189- }
190- ///////////////////////////////////////
191- //code that supposed to be supported
192- if (iOSFindByArray != null && iOSFindByArray .length > 0 ) {
193- return buildMobileBy (howToUseLocators != null ? howToUseLocators .iOSAutomation () : null ,
194- iOSFindByArray );
195- }
171+ if (isIOSXcuit () && result == null ) {
172+ result = buildMobileBy (howToUseLocators != null ? howToUseLocators .iOSXCUITAutomation () : null ,
173+ getBys (iOSXCUITFindBy .class , iOSXCUITFindBys .class , iOSXCUITFindAll .class ));
196174 }
197175
198- if (isWindows ()) {
199- WindowsFindBy [] windowsFindByArray = annotatedElement .getAnnotationsByType (WindowsFindBy .class );
200- if (windowsFindByArray != null && windowsFindByArray .length > 0 ) {
201- return buildMobileBy (howToUseLocators != null ? howToUseLocators .windowsAutomation () : null ,
202- windowsFindByArray );
203- }
176+ if (isIOS () && result == null ) {
177+ result = buildMobileBy (howToUseLocators != null ? howToUseLocators .iOSAutomation () : null ,
178+ getBys (iOSFindBy .class , iOSFindBys .class , iOSFindAll .class ));
179+ }
180+
181+ if (isWindows () && result == null ) {
182+ result = buildMobileBy (howToUseLocators != null ? howToUseLocators .windowsAutomation () : null ,
183+ getBys (WindowsFindBy .class , WindowsFindBys .class , WindowsFindAll .class ));
204184 }
205185
206- return null ;
186+ return ofNullable ( result ). orElse ( null ) ;
207187 }
208188
209189 @ Override public boolean isLookupCached () {
@@ -255,8 +235,8 @@ public int compare(Annotation o1, Annotation o2) {
255235 int priority2 ;
256236 Method priority ;
257237
258- Class <? extends Annotation > c1 = o1 .getClass ();
259- Class <? extends Annotation > c2 = o2 .getClass ();
238+ Class <?> c1 = o1 .getClass (). getInterfaces ()[ 0 ] ;
239+ Class <?> c2 = o2 .getClass (). getInterfaces ()[ 0 ] ;
260240
261241 if (!c1 .equals (c2 )) {
262242 throw new ClassCastException (String .format ("Given annotations have different classes (%s, %s). " +
0 commit comments