or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-config.mdatomic-variables.mdcondition-evaluation.mdcore-await.mdexception-handling.mdfield-reflection.mdindex.mdtimeout-polling.md

field-reflection.mddocs/

0

# Field and Reflection Support

1

2

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

3

4

## Capabilities

5

6

### Field Access Entry Points

7

8

Create field supplier builders for accessing object fields via reflection.

9

10

#### Instance Field Access

11

12

```java { .api }

13

/**

14

* Create field supplier builder for instance fields

15

* @param object instance containing the field to monitor

16

* @return FieldSupplierBuilder for field specification

17

*/

18

static FieldSupplierBuilder fieldIn(Object object);

19

```

20

21

#### Static Field Access

22

23

```java { .api }

24

/**

25

* Create field supplier builder for static fields

26

* @param clazz class containing the static field to monitor

27

* @return FieldSupplierBuilder for field specification

28

*/

29

static FieldSupplierBuilder fieldIn(Class<?> clazz);

30

```

31

32

### Field Supplier Builder

33

34

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

35

36

#### Type-Based Field Selection

37

38

```java { .api }

39

/**

40

* Specify expected field type for selection and create a supplier

41

* @param fieldType class of the field type (generic parameter preserved)

42

* @return NameAndAnnotationFieldSupplier for additional criteria or direct usage

43

*/

44

<T> NameAndAnnotationFieldSupplier<T> ofType(Class<T> fieldType);

45

```

46

47

### Field Supplier Interfaces

48

49

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

50

51

#### NameAndAnnotationFieldSupplier

52

53

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

54

55

```java { .api }

56

interface NameAndAnnotationFieldSupplier<T> extends Callable<T> {

57

/**

58

* Narrow field selection by field name

59

* @param fieldName the exact name of the field

60

* @return AnnotationFieldSupplier for optional annotation criteria

61

*/

62

AnnotationFieldSupplier<T> andWithName(String fieldName);

63

64

/**

65

* Narrow field selection by annotation type

66

* @param annotationType the annotation class that must be present on the field

67

* @return NameFieldSupplier for optional name criteria

68

*/

69

NameFieldSupplier<T> andAnnotatedWith(Class<? extends Annotation> annotationType);

70

71

/**

72

* Use the field supplier directly (finds first field of specified type)

73

* @return the field value

74

*/

75

T call() throws Exception;

76

}

77

```

78

79

#### AnnotationFieldSupplier

80

81

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

82

83

```java { .api }

84

interface AnnotationFieldSupplier<T> extends Callable<T> {

85

/**

86

* Further narrow field selection by annotation (requires exact match of name, type, and annotation)

87

* @param annotationType the annotation class that must be present on the field

88

* @return Callable supplier for the precisely specified field

89

*/

90

Callable<T> andAnnotatedWith(Class<? extends Annotation> annotationType);

91

92

/**

93

* Use the field supplier (finds field by name and type)

94

* @return the field value

95

*/

96

T call();

97

}

98

```

99

100

#### NameFieldSupplier

101

102

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

103

104

```java { .api }

105

interface NameFieldSupplier<T> extends Callable<T> {

106

/**

107

* Further narrow field selection by field name (requires exact match of annotation, type, and name)

108

* @param fieldName the exact name of the field

109

* @return Callable supplier for the precisely specified field

110

*/

111

Callable<T> andWithName(String fieldName);

112

113

/**

114

* Use the field supplier (finds field by annotation and type)

115

* @return the field value

116

*/

117

T call() throws Exception;

118

}

119

120

#### NameAndAnnotationFieldSupplier

121

122

Primary supplier class that allows chaining name and annotation criteria.

123

124

```java { .api }

125

/**

126

* Add name constraint to field selection

127

* @param fieldName exact name of the field

128

* @return AnnotationFieldSupplier for optional annotation constraint

129

*/

130

AnnotationFieldSupplier<T> andWithName(String fieldName);

131

132

/**

133

* Add annotation constraint to field selection

134

* @param annotationType annotation class that must be present on field

135

* @return NameFieldSupplier for optional name constraint

136

*/

137

NameFieldSupplier<T> andAnnotatedWith(Class<? extends Annotation> annotationType);

138

139

/**

140

* Get field value using type constraint only

141

* @return field value cast to expected type

142

* @throws FieldNotFoundException if no field of specified type found

143

*/

144

T call() throws Exception;

145

```

146

147

#### AnnotationFieldSupplier

148

149

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

150

151

```java { .api }

152

/**

153

* Add annotation constraint (returns self for chaining)

154

* @param annotationType annotation class that must be present on field

155

* @return this supplier for call() execution

156

*/

157

Callable<T> andAnnotatedWith(Class<? extends Annotation> annotationType);

158

159

/**

160

* Get field value using type and name constraints

161

* @return field value cast to expected type

162

* @throws FieldNotFoundException if field not found or type mismatch

163

*/

164

T call() throws Exception;

165

```

166

167

#### NameFieldSupplier

168

169

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

170

171

```java { .api }

172

/**

173

* Add name constraint (returns anonymous Callable)

174

* @param fieldName exact name of the field

175

* @return Callable for call() execution

176

*/

177

Callable<T> andWithName(String fieldName);

178

179

/**

180

* Get field value using type and annotation constraints

181

* @return field value cast to expected type

182

* @throws FieldNotFoundException if field not found or type mismatch

183

*/

184

T call() throws Exception;

185

```

186

187

## Field Access Patterns

188

189

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

190

191

### Pattern 1: Type-Only Access

192

```java

193

// Access field by type only (first field of matching type)

194

await().until(fieldIn(object).ofType(int.class), equalTo(42));

195

```

196

197

### Pattern 2: Type + Name Access

198

```java

199

// Access field by type and name

200

await().until(fieldIn(object).ofType(String.class).andWithName("username"), equalTo("admin"));

201

```

202

203

### Pattern 3: Type + Annotation Access

204

```java

205

// Access field by type and annotation

206

await().until(fieldIn(object).ofType(boolean.class).andAnnotatedWith(MyAnnotation.class), equalTo(true));

207

```

208

209

### Pattern 4: Type + Name + Annotation Access

210

```java

211

// Access field by type, name, and annotation (most specific)

212

await().until(fieldIn(object).ofType(int.class)

213

.andWithName("counter")

214

.andAnnotatedWith(MyAnnotation.class), greaterThan(10));

215

```

216

217

### Pattern 5: Type + Annotation + Name Access

218

```java

219

// Alternative order: type, annotation, then name

220

await().until(fieldIn(object).ofType(int.class)

221

.andAnnotatedWith(MyAnnotation.class)

222

.andWithName("counter"), greaterThan(10));

223

```

224

225

## Static Field Access

226

227

```java

228

// Access static fields using class reference

229

await().until(fieldIn(DatabasePool.class).ofType(int.class).andWithName("activeConnections"), lessThan(10));

230

231

// Access static field by type only

232

await().until(fieldIn(ConfigManager.class).ofType(boolean.class), equalTo(true));

233

```

234

235

## Exception Handling

236

237

Field access can throw several exceptions during reflection operations:

238

239

```java { .api }

240

/**

241

* Thrown when field cannot be found based on specified criteria

242

*/

243

class FieldNotFoundException extends RuntimeException {

244

public FieldNotFoundException(String message);

245

}

246

247

/**

248

* Thrown when multiple fields match criteria and disambiguation is required

249

*/

250

class TooManyFieldsFoundException extends RuntimeException {

251

public TooManyFieldsFoundException(String message);

252

}

253

```

254

255

### Common Exception Scenarios

256

257

```java

258

try {

259

await().until(fieldIn(object).ofType(String.class), equalTo("expected"));

260

} catch (ConditionTimeoutException e) {

261

// Timeout occurred before field reached expected value

262

if (e.getCause() instanceof FieldNotFoundException) {

263

// Field of specified type doesn't exist

264

}

265

}

266

```

267

268

## Advanced Field Access Examples

269

270

### Complex Object Field Navigation

271

272

```java

273

// Wait for nested object field value

274

await().until(fieldIn(userService).ofType(DatabaseConnection.class)

275

.andWithName("connection"),

276

connection -> connection.isActive());

277

278

// Wait for collection field size

279

await().until(fieldIn(cache).ofType(ConcurrentMap.class)

280

.andWithName("entries"),

281

map -> ((Map<?, ?>) map).size() > 100);

282

```

283

284

### Annotation-Based Field Selection

285

286

```java

287

// Wait for field annotated with @Metric

288

await().until(fieldIn(processor).ofType(long.class)

289

.andAnnotatedWith(Metric.class),

290

greaterThan(1000L));

291

292

// Wait for @ConfigValue annotated field to change

293

await().until(fieldIn(configService).ofType(String.class)

294

.andAnnotatedWith(ConfigValue.class)

295

.andWithName("databaseUrl"),

296

not(equalTo("localhost:3306")));

297

```

298

299

### Type Safety and Generics

300

301

```java

302

// Type-safe field access preserves generics

303

AtomicReference<String> result = await().until(

304

fieldIn(asyncService).ofType(AtomicReference.class)

305

.andWithName("result"),

306

ref -> ref.get() != null);

307

308

// Works with complex generic types

309

List<Order> orders = await().until(

310

fieldIn(orderService).ofType(List.class)

311

.andWithName("pendingOrders"),

312

list -> !((List<?>) list).isEmpty());

313

```