CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-awaitility--awaitility

A Java DSL for synchronizing asynchronous operations

Pending
Overview
Eval results
Files

field-reflection.mddocs/

Field and Reflection Support

Utilities for waiting on private field values and object state changes using reflection, ideal for testing internal component state.

Capabilities

Field Access Entry Points

Create field supplier builders for accessing object fields via reflection.

Instance Field Access

/**
 * Create field supplier builder for instance fields
 * @param object instance containing the field to monitor
 * @return FieldSupplierBuilder for field specification
 */
static FieldSupplierBuilder fieldIn(Object object);

Static Field Access

/**
 * Create field supplier builder for static fields  
 * @param clazz class containing the static field to monitor
 * @return FieldSupplierBuilder for field specification
 */
static FieldSupplierBuilder fieldIn(Class<?> clazz);

Field Supplier Builder

Builder interface for specifying field selection criteria and creating callable suppliers.

Type-Based Field Selection

/**
 * Specify expected field type for selection and create a supplier
 * @param fieldType class of the field type (generic parameter preserved)
 * @return NameAndAnnotationFieldSupplier for additional criteria or direct usage
 */
<T> NameAndAnnotationFieldSupplier<T> ofType(Class<T> fieldType);

Field Supplier Interfaces

The field access API provides nested supplier classes that implement Callable<T> for different selection criteria combinations.

NameAndAnnotationFieldSupplier

Primary supplier class returned by ofType() that supports additional field narrowing criteria.

interface NameAndAnnotationFieldSupplier<T> extends Callable<T> {
    /**
     * Narrow field selection by field name
     * @param fieldName the exact name of the field
     * @return AnnotationFieldSupplier for optional annotation criteria
     */
    AnnotationFieldSupplier<T> andWithName(String fieldName);
    
    /**
     * Narrow field selection by annotation type
     * @param annotationType the annotation class that must be present on the field
     * @return NameFieldSupplier for optional name criteria
     */
    NameFieldSupplier<T> andAnnotatedWith(Class<? extends Annotation> annotationType);
    
    /**
     * Use the field supplier directly (finds first field of specified type)
     * @return the field value
     */
    T call() throws Exception;
}

AnnotationFieldSupplier

Supplier for fields selected by type and name, with optional annotation criteria.

interface AnnotationFieldSupplier<T> extends Callable<T> {
    /**
     * Further narrow field selection by annotation (requires exact match of name, type, and annotation)
     * @param annotationType the annotation class that must be present on the field
     * @return Callable supplier for the precisely specified field
     */
    Callable<T> andAnnotatedWith(Class<? extends Annotation> annotationType);
    
    /**
     * Use the field supplier (finds field by name and type)
     * @return the field value
     */
    T call();
}

NameFieldSupplier

Supplier for fields selected by type and annotation, with optional name criteria.

interface NameFieldSupplier<T> extends Callable<T> {
    /**
     * Further narrow field selection by field name (requires exact match of annotation, type, and name)
     * @param fieldName the exact name of the field
     * @return Callable supplier for the precisely specified field
     */
    Callable<T> andWithName(String fieldName);
    
    /**
     * Use the field supplier (finds field by annotation and type)
     * @return the field value
     */
    T call() throws Exception;
}

#### NameAndAnnotationFieldSupplier

Primary supplier class that allows chaining name and annotation criteria.

```java { .api }
/**
 * Add name constraint to field selection
 * @param fieldName exact name of the field
 * @return AnnotationFieldSupplier for optional annotation constraint
 */
AnnotationFieldSupplier<T> andWithName(String fieldName);

/**
 * Add annotation constraint to field selection  
 * @param annotationType annotation class that must be present on field
 * @return NameFieldSupplier for optional name constraint
 */
NameFieldSupplier<T> andAnnotatedWith(Class<? extends Annotation> annotationType);

/**
 * Get field value using type constraint only
 * @return field value cast to expected type
 * @throws FieldNotFoundException if no field of specified type found
 */
T call() throws Exception;

AnnotationFieldSupplier

Supplier for fields selected by type and name, allowing annotation constraint.

/**
 * Add annotation constraint (returns self for chaining)
 * @param annotationType annotation class that must be present on field
 * @return this supplier for call() execution
 */
Callable<T> andAnnotatedWith(Class<? extends Annotation> annotationType);

/**
 * Get field value using type and name constraints
 * @return field value cast to expected type  
 * @throws FieldNotFoundException if field not found or type mismatch
 */
T call() throws Exception;

NameFieldSupplier

Supplier for fields selected by type and annotation, allowing name constraint.

/**
 * Add name constraint (returns anonymous Callable)
 * @param fieldName exact name of the field
 * @return Callable for call() execution
 */
Callable<T> andWithName(String fieldName);

/**
 * Get field value using type and annotation constraints
 * @return field value cast to expected type
 * @throws FieldNotFoundException if field not found or type mismatch  
 */
T call() throws Exception;

Field Access Patterns

The field access API supports several selection patterns through method chaining:

Pattern 1: Type-Only Access

// Access field by type only (first field of matching type)
await().until(fieldIn(object).ofType(int.class), equalTo(42));

Pattern 2: Type + Name Access

// Access field by type and name
await().until(fieldIn(object).ofType(String.class).andWithName("username"), equalTo("admin"));

Pattern 3: Type + Annotation Access

// Access field by type and annotation
await().until(fieldIn(object).ofType(boolean.class).andAnnotatedWith(MyAnnotation.class), equalTo(true));

Pattern 4: Type + Name + Annotation Access

// Access field by type, name, and annotation (most specific)
await().until(fieldIn(object).ofType(int.class)
    .andWithName("counter")
    .andAnnotatedWith(MyAnnotation.class), greaterThan(10));

Pattern 5: Type + Annotation + Name Access

// Alternative order: type, annotation, then name
await().until(fieldIn(object).ofType(int.class)
    .andAnnotatedWith(MyAnnotation.class)
    .andWithName("counter"), greaterThan(10));

Static Field Access

// Access static fields using class reference
await().until(fieldIn(DatabasePool.class).ofType(int.class).andWithName("activeConnections"), lessThan(10));

// Access static field by type only
await().until(fieldIn(ConfigManager.class).ofType(boolean.class), equalTo(true));

Exception Handling

Field access can throw several exceptions during reflection operations:

/**
 * Thrown when field cannot be found based on specified criteria
 */
class FieldNotFoundException extends RuntimeException {
    public FieldNotFoundException(String message);
}

/**
 * Thrown when multiple fields match criteria and disambiguation is required
 */
class TooManyFieldsFoundException extends RuntimeException {
    public TooManyFieldsFoundException(String message);
}

Common Exception Scenarios

try {
    await().until(fieldIn(object).ofType(String.class), equalTo("expected"));
} catch (ConditionTimeoutException e) {
    // Timeout occurred before field reached expected value
    if (e.getCause() instanceof FieldNotFoundException) {
        // Field of specified type doesn't exist
    }
}

Advanced Field Access Examples

Complex Object Field Navigation

// Wait for nested object field value
await().until(fieldIn(userService).ofType(DatabaseConnection.class)
    .andWithName("connection"), 
    connection -> connection.isActive());

// Wait for collection field size
await().until(fieldIn(cache).ofType(ConcurrentMap.class)
    .andWithName("entries"),
    map -> ((Map<?, ?>) map).size() > 100);

Annotation-Based Field Selection

// Wait for field annotated with @Metric
await().until(fieldIn(processor).ofType(long.class)
    .andAnnotatedWith(Metric.class), 
    greaterThan(1000L));

// Wait for @ConfigValue annotated field to change
await().until(fieldIn(configService).ofType(String.class)
    .andAnnotatedWith(ConfigValue.class)
    .andWithName("databaseUrl"),
    not(equalTo("localhost:3306")));

Type Safety and Generics

// Type-safe field access preserves generics
AtomicReference<String> result = await().until(
    fieldIn(asyncService).ofType(AtomicReference.class)
        .andWithName("result"),
    ref -> ref.get() != null);

// Works with complex generic types
List<Order> orders = await().until(
    fieldIn(orderService).ofType(List.class)
        .andWithName("pendingOrders"),
    list -> !((List<?>) list).isEmpty());

Install with Tessl CLI

npx tessl i tessl/maven-org-awaitility--awaitility

docs

advanced-config.md

atomic-variables.md

condition-evaluation.md

core-await.md

exception-handling.md

field-reflection.md

index.md

timeout-polling.md

tile.json