Implementation:SeleniumHQ Selenium FindBy Annotation Suite
| Knowledge Sources | |
|---|---|
| Domains | Test_Design, Design_Patterns, Browser_Automation |
| Last Updated | 2026-02-11 00:00 GMT |
Overview
Concrete tool for declaring element locators via Java annotations provided by the Selenium Support library.
Description
The @FindBy annotation supports two forms: shorthand (@FindBy(id = "foo")) and long form (@FindBy(how = How.ID, using = "foo")). Both delegate to the matching By factory methods. @FindAll takes an array of @FindBy with OR semantics, producing a ByAll locator that returns elements matching any of the criteria. @FindBys takes an array with AND/chaining semantics, producing a ByChained locator that applies locators sequentially. The How enum provides: CLASS_NAME, CSS, ID, ID_OR_NAME, LINK_TEXT, NAME, PARTIAL_LINK_TEXT, TAG_NAME, XPATH, UNSET. Each enum constant implements the buildBy(String value) method to produce the corresponding By object. All three annotations use @PageFactoryFinder to declare their respective inner FindByBuilder class, which extends AbstractFindByBuilder.
Usage
Annotate WebElement or List<WebElement> fields in Page Object classes. Fields are populated by PageFactory.initElements() at runtime. For a single locator, use @FindBy with either shorthand or long form. For multiple locators with OR semantics, use @FindAll. For chained locators with AND semantics, use @FindBys.
Code Reference
Source Location
- Repository: Selenium
- File: java/src/org/openqa/selenium/support/FindBy.java (L53-90)
- File: java/src/org/openqa/selenium/support/FindAll.java (L42-62)
- File: java/src/org/openqa/selenium/support/FindBys.java (L41-61)
- File: java/src/org/openqa/selenium/support/How.java (L22-85)
Signature
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
@PageFactoryFinder(FindBy.FindByBuilder.class)
public @interface FindBy {
How how() default How.UNSET;
String using() default "";
String id() default "";
String name() default "";
String className() default "";
String css() default "";
String tagName() default "";
String linkText() default "";
String partialLinkText() default "";
String xpath() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
@PageFactoryFinder(FindAll.FindByBuilder.class)
public @interface FindAll {
FindBy[] value(); // OR semantics via ByAll
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
@PageFactoryFinder(FindBys.FindByBuilder.class)
public @interface FindBys {
FindBy[] value(); // AND/chaining semantics via ByChained
}
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 {
@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); }
};
public abstract By buildBy(String value);
}
Import
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.FindAll;
import org.openqa.selenium.support.FindBys;
import org.openqa.selenium.support.How;
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| how | How | No | Locator strategy enum (long form); defaults to How.UNSET |
| using | String | No | Locator value (long form); defaults to empty string |
| id | String | No | Shorthand for How.ID |
| name | String | No | Shorthand for How.NAME |
| className | String | No | Shorthand for How.CLASS_NAME |
| css | String | No | Shorthand for How.CSS |
| tagName | String | No | Shorthand for How.TAG_NAME |
| linkText | String | No | Shorthand for How.LINK_TEXT |
| partialLinkText | String | No | Shorthand for How.PARTIAL_LINK_TEXT |
| xpath | String | No | Shorthand for How.XPATH |
Outputs
| Name | Type | Description |
|---|---|---|
| annotation metadata | Annotation | Runtime-retained locator metadata for PageFactory processing |
Validation
AbstractFindByBuilder.assertValidFindBy() enforces that at most one location strategy is specified per @FindBy annotation. If multiple shorthand attributes or both shorthand and long-form are set, an IllegalArgumentException is thrown with a message indicating the conflicting finders.
Usage Examples
Basic @FindBy
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
public class LoginPage {
@FindBy(id = "username")
private WebElement usernameField;
@FindBy(css = "input[type='password']")
private WebElement passwordField;
@FindBy(xpath = "//button[@type='submit']")
private WebElement loginButton;
// Long form equivalent
@FindBy(how = How.ID, using = "username")
private WebElement usernameFieldLongForm;
}
@FindAll (OR) and @FindBys (AND)
import org.openqa.selenium.support.FindAll;
import org.openqa.selenium.support.FindBys;
import org.openqa.selenium.support.FindBy;
import java.util.List;
public class SearchPage {
// OR: matches elements found by ANY of these locators (uses ByAll internally)
@FindAll({
@FindBy(css = ".result-item"),
@FindBy(css = ".search-result")
})
private List<WebElement> searchResults;
// AND: chained locators (uses ByChained internally)
// Finds element matching second @FindBy within results of first @FindBy
@FindBys({
@FindBy(id = "search-form"),
@FindBy(tagName = "input")
})
private WebElement searchInput;
}