Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 52 additions & 83 deletions java/src/org/openqa/selenium/support/AbstractFindByBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,105 +17,74 @@

package org.openqa.selenium.support;

import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.openqa.selenium.By;

public abstract class AbstractFindByBuilder<T> {

public abstract By buildIt(T annotation, Field field);
/**
* Compatibility adapter that delegates to {@link
* org.openqa.selenium.support.pagefactory.AbstractFindByBuilder}.
*
* @deprecated Use {@link org.openqa.selenium.support.pagefactory.AbstractFindByBuilder} instead.
*/
@Deprecated(forRemoval = false)
public abstract class AbstractFindByBuilder<T>
extends org.openqa.selenium.support.pagefactory.AbstractFindByBuilder<T> {

protected By buildByFromFindBy(FindBy findBy) {
assertValidFindBy(findBy);

By ans = buildByFromShortFindBy(findBy);
if (ans == null) {
ans = buildByFromLongFindBy(findBy);
}

return ans;
}

protected By buildByFromShortFindBy(FindBy findBy) {
if (!"".equals(findBy.className())) {
return By.className(findBy.className());
}

if (!"".equals(findBy.css())) {
return By.cssSelector(findBy.css());
}

if (!"".equals(findBy.id())) {
return By.id(findBy.id());
}

if (!"".equals(findBy.linkText())) {
return By.linkText(findBy.linkText());
}

if (!"".equals(findBy.name())) {
return By.name(findBy.name());
}

if (!"".equals(findBy.partialLinkText())) {
return By.partialLinkText(findBy.partialLinkText());
}

if (!"".equals(findBy.tagName())) {
return By.tagName(findBy.tagName());
}

if (!"".equals(findBy.xpath())) {
return By.xpath(findBy.xpath());
}

// Fall through
return null;
}

protected By buildByFromLongFindBy(FindBy findBy) {
return findBy.how().buildBy(findBy.using());
return super.buildByFromFindBy(adapt(findBy));
}

protected void assertValidFindBys(FindBys findBys) {
for (FindBy findBy : findBys.value()) {
assertValidFindBy(findBy);
super.assertValidFindBy(adapt(findBy));
}
}

protected void assertValidFindBy(FindBy findBy) {
if (findBy.how() != null) {
if (findBy.using() == null) {
throw new IllegalArgumentException(
"If you set the 'how' property, you must also set 'using'");
}
}

Set<String> finders = new HashSet<>();
if (!"".equals(findBy.using())) finders.add("how: " + findBy.using());
if (!"".equals(findBy.className())) finders.add("class name:" + findBy.className());
if (!"".equals(findBy.css())) finders.add("css:" + findBy.css());
if (!"".equals(findBy.id())) finders.add("id: " + findBy.id());
if (!"".equals(findBy.linkText())) finders.add("link text: " + findBy.linkText());
if (!"".equals(findBy.name())) finders.add("name: " + findBy.name());
if (!"".equals(findBy.partialLinkText()))
finders.add("partial link text: " + findBy.partialLinkText());
if (!"".equals(findBy.tagName())) finders.add("tag name: " + findBy.tagName());
if (!"".equals(findBy.xpath())) finders.add("xpath: " + findBy.xpath());

// A zero count is okay: it means to look by name or id.
if (finders.size() > 1) {
throw new IllegalArgumentException(
String.format(
"You must specify at most one location strategy. Number found: %d (%s)",
finders.size(), finders));
}
super.assertValidFindBy(adapt(findBy));
}

protected void assertValidFindAll(FindAll findBys) {
for (FindBy findBy : findBys.value()) {
assertValidFindBy(findBy);
super.assertValidFindBy(adapt(findBy));
}
}

private org.openqa.selenium.support.pagefactory.FindBy adapt(final FindBy findBy) {
return (org.openqa.selenium.support.pagefactory.FindBy)
Proxy.newProxyInstance(
org.openqa.selenium.support.pagefactory.FindBy.class.getClassLoader(),
new Class[] {org.openqa.selenium.support.pagefactory.FindBy.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("how".equals(method.getName())) {
return org.openqa.selenium.support.pagefactory.How.valueOf(findBy.how().name());
}
if ("annotationType".equals(method.getName())) {
return org.openqa.selenium.support.pagefactory.FindBy.class;
}
// For all other methods (id, name, etc.), they return String and match exactly.
// We delegate to the 'findBy' instance.
try {
return findBy.annotationType().getMethod(method.getName()).invoke(findBy);
} catch (NoSuchMethodException e) {
// Handle equals/hashCode/toString if necessary, though usually not called in
// builder logic
if ("equals".equals(method.getName())) {
return proxy == args[0];
}
if ("hashCode".equals(method.getName())) {
return System.identityHashCode(proxy);
}
if ("toString".equals(method.getName())) {
return "Proxy for " + findBy.toString();
}
throw e;
}
}
});
}
}
6 changes: 2 additions & 4 deletions java/src/org/openqa/selenium/support/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,10 @@ java_library(
"How.java",
"PageFactory.java",
"PageFactoryFinder.java",
] + glob([
"pagefactory/*.java",
"pagefactory/internal/*.java",
]),
],
deps = [
"//java/src/org/openqa/selenium:core",
"//java/src/org/openqa/selenium/support/pagefactory",
"//java/src/org/openqa/selenium/support/ui:components",
artifact("org.jspecify:jspecify"),
],
Expand Down
49 changes: 7 additions & 42 deletions java/src/org/openqa/selenium/support/ByIdOrName.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,54 +18,19 @@
package org.openqa.selenium.support;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.jspecify.annotations.NullMarked;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebElement;

/**
* @deprecated Use {@link org.openqa.selenium.support.pagefactory.ByIdOrName} instead.
*/
@Deprecated(forRemoval = false)
@NullMarked
public class ByIdOrName extends By implements Serializable {
public class ByIdOrName extends org.openqa.selenium.support.pagefactory.ByIdOrName
implements Serializable {

private static final long serialVersionUID = 3986638402799576701L;

private final By idFinder;
private final By nameFinder;
private final String idOrName;

public ByIdOrName(String idOrName) {
this.idOrName = idOrName;
idFinder = By.id(idOrName);
nameFinder = By.name(idOrName);
}

@Override
public WebElement findElement(SearchContext context) {
try {
// First, try to locate by id
return idFinder.findElement(context);
} catch (NoSuchElementException e) {
// Then by name
return nameFinder.findElement(context);
}
}

@Override
public List<WebElement> findElements(SearchContext context) {
List<WebElement> elements = new ArrayList<>();

// First: Find by id ...
elements.addAll(idFinder.findElements(context));
// Second: Find by name ...
elements.addAll(nameFinder.findElements(context));

return elements;
}

@Override
public String toString() {
return "by id or name \"" + idOrName + '"';
super(idOrName);
}
}
3 changes: 3 additions & 0 deletions java/src/org/openqa/selenium/support/CacheLookup.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@
/**
* Marker annotation to be applied to WebElements to indicate that it never changes (that is, that
* the same instance in the DOM will always be used)
*
* @deprecated Use {@link org.openqa.selenium.support.pagefactory.CacheLookup} instead.
*/
@Deprecated(forRemoval = false)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface CacheLookup {}
5 changes: 4 additions & 1 deletion java/src/org/openqa/selenium/support/FindAll.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,13 @@
* &#64;FindAll({&#64;FindBy(how = How.ID, using = "foo"),
* &#64;FindBy(className = "bar")})
* </pre>
*
* @deprecated Use {@link org.openqa.selenium.support.pagefactory.FindAll} instead.
*/
@Deprecated(forRemoval = false)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
@PageFactoryFinder(FindAll.FindByBuilder.class)
@org.openqa.selenium.support.pagefactory.PageFactoryFinder(FindAll.FindByBuilder.class)
public @interface FindAll {
FindBy[] value();

Expand Down
13 changes: 5 additions & 8 deletions java/src/org/openqa/selenium/support/FindBy.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,13 @@
* &#64;FindBy(tagName = "a") List&lt;WebElement&gt; links;
* &#64;FindBy(how = How.TAG_NAME, using = "a") List&lt;WebElement&gt; links;
* </pre>
*
* @deprecated Use {@link org.openqa.selenium.support.pagefactory.FindBy} instead.
*/
@Deprecated(forRemoval = false)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
@PageFactoryFinder(FindBy.FindByBuilder.class)
@org.openqa.selenium.support.pagefactory.PageFactoryFinder(FindBy.FindByBuilder.class)
public @interface FindBy {
How how() default How.UNSET;

Expand All @@ -78,13 +81,7 @@ class FindByBuilder extends AbstractFindByBuilder<FindBy> {
@Override
public By buildIt(FindBy findBy, Field field) {
assertValidFindBy(findBy);

By ans = buildByFromShortFindBy(findBy);
if (ans == null) {
ans = buildByFromLongFindBy(findBy);
}

return ans;
return buildByFromFindBy(findBy);
}
}
}
5 changes: 4 additions & 1 deletion java/src/org/openqa/selenium/support/FindBys.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,13 @@
* &#64;FindBys({&#64;FindBy(id = "foo"),
* &#64;FindBy(className = "bar")})
* </pre>
*
* @deprecated Use {@link org.openqa.selenium.support.pagefactory.FindBys} instead.
*/
@Deprecated(forRemoval = false)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
@PageFactoryFinder(FindBys.FindByBuilder.class)
@org.openqa.selenium.support.pagefactory.PageFactoryFinder(FindBys.FindByBuilder.class)
public @interface FindBys {
FindBy[] value();

Expand Down
79 changes: 23 additions & 56 deletions java/src/org/openqa/selenium/support/How.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,67 +19,34 @@

import org.openqa.selenium.By;

/**
* @deprecated Use {@link org.openqa.selenium.support.pagefactory.How} instead.
*/
@Deprecated(forRemoval = false)
public enum How {
CLASS_NAME {
@Override
public By buildBy(String value) {
return By.className(value);
}
},
CSS {
@Override
public By buildBy(String value) {
return By.cssSelector(value);
}
},
ID {
@Override
public By buildBy(String value) {
return By.id(value);
}
},
ID_OR_NAME {
CLASS_NAME(org.openqa.selenium.support.pagefactory.How.CLASS_NAME),
CSS(org.openqa.selenium.support.pagefactory.How.CSS),
ID(org.openqa.selenium.support.pagefactory.How.ID),
ID_OR_NAME(org.openqa.selenium.support.pagefactory.How.ID_OR_NAME) {
@Override
public By buildBy(String value) {
return new ByIdOrName(value);
}
},
LINK_TEXT {
@Override
public By buildBy(String value) {
return By.linkText(value);
}
},
NAME {
@Override
public By buildBy(String value) {
return By.name(value);
}
},
PARTIAL_LINK_TEXT {
@Override
public By buildBy(String value) {
return By.partialLinkText(value);
}
},
TAG_NAME {
@Override
public By buildBy(String value) {
return By.tagName(value);
}
},
XPATH {
@Override
public By buildBy(String value) {
return By.xpath(value);
}
},
UNSET {
@Override
public By buildBy(String value) {
return ID.buildBy(value);
}
};
LINK_TEXT(org.openqa.selenium.support.pagefactory.How.LINK_TEXT),
NAME(org.openqa.selenium.support.pagefactory.How.NAME),
PARTIAL_LINK_TEXT(org.openqa.selenium.support.pagefactory.How.PARTIAL_LINK_TEXT),
TAG_NAME(org.openqa.selenium.support.pagefactory.How.TAG_NAME),
XPATH(org.openqa.selenium.support.pagefactory.How.XPATH),
UNSET(org.openqa.selenium.support.pagefactory.How.UNSET);

private final org.openqa.selenium.support.pagefactory.How delegate;

How(org.openqa.selenium.support.pagefactory.How delegate) {
this.delegate = delegate;
}

public abstract By buildBy(String value);
public By buildBy(String value) {
return delegate.buildBy(value);
}
}
Loading
Loading