or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

annotations.mdapplication-context.mdbean-definition.mdbean-factory.mdbean-processing.mdbean-providers.mdenvironment-config.mdevents.mdexceptions.mdindex.mdscoping.md

bean-processing.mddocs/

0

# Bean Processing and Extensibility

1

2

The bean processing framework provides extension points for customizing bean creation, method execution, and framework behavior. It enables advanced features like AOP, validation, and custom framework integrations.

3

4

## Core Processing Interfaces

5

6

### BeanDefinitionProcessor

7

8

Interface for processing and modifying bean definitions during context initialization.

9

10

```java { .api }

11

/**

12

* Processor interface for bean definition modification

13

* @param <T> The bean type

14

*/

15

public interface BeanDefinitionProcessor<T> {

16

/**

17

* Process a bean definition and optionally return a modified version

18

* @param beanDefinition The original bean definition

19

* @param context The bean context

20

* @return The processed bean definition

21

*/

22

BeanDefinition<T> process(BeanDefinition<T> beanDefinition, BeanContext context);

23

24

/**

25

* Check if this processor applies to the given bean definition

26

* @param beanDefinition The bean definition to check

27

* @return true if this processor should process the bean definition

28

*/

29

default boolean supports(BeanDefinition<T> beanDefinition) {

30

return true;

31

}

32

}

33

```

34

35

### ExecutableMethodProcessor

36

37

Interface for processing executable methods on beans for AOP and framework features.

38

39

```java { .api }

40

/**

41

* Processor interface for executable method processing

42

* @param <T> The bean type

43

*/

44

public interface ExecutableMethodProcessor<T> {

45

/**

46

* Process an executable method

47

* @param beanDefinition The bean definition containing the method

48

* @param method The executable method to process

49

*/

50

void process(BeanDefinition<?> beanDefinition, ExecutableMethod<T, ?> method);

51

52

/**

53

* Get the method annotation type this processor handles

54

* @return The annotation type

55

*/

56

Class<? extends Annotation> getAnnotationType();

57

}

58

```

59

60

**Usage Examples:**

61

62

```java

63

import io.micronaut.context.processor.BeanDefinitionProcessor;

64

import io.micronaut.context.processor.ExecutableMethodProcessor;

65

import jakarta.inject.Singleton;

66

67

@Singleton

68

public class AuditBeanProcessor implements BeanDefinitionProcessor<Object> {

69

70

@Override

71

public BeanDefinition<Object> process(BeanDefinition<Object> beanDefinition, BeanContext context) {

72

if (beanDefinition.hasAnnotation(Auditable.class)) {

73

// Wrap bean definition to add auditing capabilities

74

return new AuditableBeanDefinition<>(beanDefinition);

75

}

76

return beanDefinition;

77

}

78

79

@Override

80

public boolean supports(BeanDefinition<Object> beanDefinition) {

81

return beanDefinition.hasAnnotation(Auditable.class);

82

}

83

}

84

85

@Singleton

86

public class TimedMethodProcessor implements ExecutableMethodProcessor<Object> {

87

88

@Override

89

public void process(BeanDefinition<?> beanDefinition, ExecutableMethod<Object, ?> method) {

90

if (method.hasAnnotation(Timed.class)) {

91

// Register timing interceptor for this method

92

registerTimingInterceptor(beanDefinition, method);

93

}

94

}

95

96

@Override

97

public Class<? extends Annotation> getAnnotationType() {

98

return Timed.class;

99

}

100

101

private void registerTimingInterceptor(BeanDefinition<?> beanDefinition, ExecutableMethod<?, ?> method) {

102

// Implementation to register timing interceptor

103

}

104

}

105

```

106

107

## Registry and Introspection

108

109

### BeanDefinitionRegistry

110

111

Registry interface providing comprehensive bean definition management and introspection.

112

113

```java { .api }

114

/**

115

* Registry for bean definition metadata and introspection

116

*/

117

public interface BeanDefinitionRegistry {

118

/**

119

* Check if a bean of the given type exists

120

* @param beanType The bean type

121

* @return true if bean exists

122

*/

123

<T> boolean containsBean(Class<T> beanType);

124

125

/**

126

* Check if a bean exists with qualifier

127

* @param beanType The bean type

128

* @param qualifier The qualifier

129

* @return true if bean exists

130

*/

131

<T> boolean containsBean(Class<T> beanType, Qualifier<T> qualifier);

132

133

/**

134

* Find bean definition for the given type

135

* @param beanType The bean type

136

* @return Optional bean definition

137

*/

138

<T> Optional<BeanDefinition<T>> findBeanDefinition(Class<T> beanType);

139

140

/**

141

* Find bean definition with qualifier

142

* @param beanType The bean type

143

* @param qualifier The qualifier

144

* @return Optional bean definition

145

*/

146

<T> Optional<BeanDefinition<T>> findBeanDefinition(Class<T> beanType, Qualifier<T> qualifier);

147

148

/**

149

* Get all bean definitions for the given type

150

* @param beanType The bean type

151

* @return Collection of bean definitions

152

*/

153

<T> Collection<BeanDefinition<T>> getBeanDefinitions(Class<T> beanType);

154

155

/**

156

* Get single bean definition for the given type

157

* @param beanType The bean type

158

* @return Bean definition

159

* @throws NoSuchBeanException if not found

160

* @throws NonUniqueBeanException if multiple found

161

*/

162

<T> BeanDefinition<T> getBeanDefinition(Class<T> beanType);

163

164

/**

165

* Get all bean definitions

166

* @return Collection of all bean definitions

167

*/

168

Collection<BeanDefinition<?>> getAllBeanDefinitions();

169

170

/**

171

* Get bean definitions by annotation

172

* @param annotation The annotation type

173

* @return Collection of matching bean definitions

174

*/

175

Collection<BeanDefinition<?>> getBeanDefinitionsForAnnotation(Class<? extends Annotation> annotation);

176

}

177

```

178

179

### BeanIntrospection

180

181

Interface for introspecting bean properties and methods without reflection.

182

183

```java { .api }

184

/**

185

* Bean introspection interface for reflection-free property access

186

* @param <T> The bean type

187

*/

188

public interface BeanIntrospection<T> {

189

/**

190

* Get the bean type

191

* @return The bean type

192

*/

193

Class<T> getBeanType();

194

195

/**

196

* Instantiate the bean

197

* @param args Constructor arguments

198

* @return Bean instance

199

*/

200

T instantiate(Object... args);

201

202

/**

203

* Get all bean properties

204

* @return Collection of bean properties

205

*/

206

Collection<BeanProperty<T, Object>> getBeanProperties();

207

208

/**

209

* Get bean property by name

210

* @param name Property name

211

* @return Optional bean property

212

*/

213

Optional<BeanProperty<T, Object>> getProperty(String name);

214

215

/**

216

* Get required bean property by name

217

* @param name Property name

218

* @return Bean property

219

* @throws IntrospectionException if property not found

220

*/

221

BeanProperty<T, Object> getRequiredProperty(String name);

222

223

/**

224

* Get indexed bean properties (array/collection properties)

225

* @return Collection of indexed properties

226

*/

227

Collection<BeanProperty<T, Object>> getIndexedProperties();

228

229

/**

230

* Get constructor arguments

231

* @return Array of constructor arguments

232

*/

233

Argument<?>[] getConstructorArguments();

234

}

235

```

236

237

**Usage Examples:**

238

239

```java

240

import io.micronaut.core.beans.BeanIntrospection;

241

import io.micronaut.core.beans.BeanProperty;

242

243

public class BeanProcessor {

244

245

public void processBeanProperties(Object bean) {

246

BeanIntrospection<Object> introspection = BeanIntrospection.getIntrospection(bean.getClass());

247

248

// Process all properties

249

for (BeanProperty<Object, Object> property : introspection.getBeanProperties()) {

250

Object value = property.get(bean);

251

System.out.println("Property " + property.getName() + " = " + value);

252

253

// Validate or transform property values

254

if (property.hasAnnotation(NotNull.class) && value == null) {

255

throw new ValidationException("Property " + property.getName() + " cannot be null");

256

}

257

}

258

259

// Copy properties between beans

260

BeanIntrospection<Object> targetIntrospection = BeanIntrospection.getIntrospection(TargetBean.class);

261

Object targetBean = targetIntrospection.instantiate();

262

263

introspection.getBeanProperties().forEach(sourceProperty -> {

264

targetIntrospection.getProperty(sourceProperty.getName())

265

.ifPresent(targetProperty -> {

266

Object value = sourceProperty.get(bean);

267

targetProperty.set(targetBean, value);

268

});

269

});

270

}

271

}

272

```

273

274

## Execution and Method Handling

275

276

### ExecutionHandleLocator

277

278

Interface for optimized method execution without reflection.

279

280

```java { .api }

281

/**

282

* Locator for optimized executable method handles

283

*/

284

public interface ExecutionHandleLocator {

285

/**

286

* Find execution handle for method

287

* @param beanType The bean type

288

* @param method The method name

289

* @param argumentTypes The argument types

290

* @return Optional execution handle

291

*/

292

<T, R> Optional<ExecutionHandle<T, R>> findExecutionHandle(Class<T> beanType, String method, Class<?>... argumentTypes);

293

294

/**

295

* Get required execution handle for method

296

* @param beanType The bean type

297

* @param method The method name

298

* @param argumentTypes The argument types

299

* @return Execution handle

300

* @throws NoSuchMethodException if method not found

301

*/

302

<T, R> ExecutionHandle<T, R> getExecutionHandle(Class<T> beanType, String method, Class<?>... argumentTypes);

303

304

/**

305

* Find all execution handles for bean type

306

* @param beanType The bean type

307

* @return Stream of execution handles

308

*/

309

<T> Stream<ExecutionHandle<T, ?>> findExecutionHandles(Class<T> beanType);

310

}

311

```

312

313

### ExecutionHandle

314

315

Interface representing an optimized executable method.

316

317

```java { .api }

318

/**

319

* Handle for optimized method execution

320

* @param <T> The bean type

321

* @param <R> The return type

322

*/

323

public interface ExecutionHandle<T, R> {

324

/**

325

* Invoke the method on the target instance

326

* @param target The target instance

327

* @param arguments The method arguments

328

* @return The method result

329

*/

330

R invoke(T target, Object... arguments);

331

332

/**

333

* Get the executable method

334

* @return The executable method

335

*/

336

ExecutableMethod<T, R> getExecutableMethod();

337

338

/**

339

* Get the target bean type

340

* @return The bean type

341

*/

342

Class<T> getDeclaringType();

343

344

/**

345

* Get the method name

346

* @return The method name

347

*/

348

String getMethodName();

349

350

/**

351

* Get argument types

352

* @return Array of argument types

353

*/

354

Argument<?>[] getArguments();

355

356

/**

357

* Get return type

358

* @return The return type argument

359

*/

360

Argument<R> getReturnType();

361

}

362

```

363

364

**Usage Examples:**

365

366

```java

367

import io.micronaut.inject.ExecutionHandle;

368

import io.micronaut.inject.ExecutionHandleLocator;

369

370

@Singleton

371

public class DynamicMethodInvoker {

372

373

private final ExecutionHandleLocator handleLocator;

374

375

public DynamicMethodInvoker(ExecutionHandleLocator handleLocator) {

376

this.handleLocator = handleLocator;

377

}

378

379

public Object invokeMethod(Object target, String methodName, Object... args) {

380

Class<?>[] argTypes = Arrays.stream(args)

381

.map(Object::getClass)

382

.toArray(Class<?>[]::new);

383

384

ExecutionHandle<Object, Object> handle = handleLocator

385

.findExecutionHandle(target.getClass(), methodName, argTypes)

386

.orElseThrow(() -> new NoSuchMethodException("Method not found: " + methodName));

387

388

return handle.invoke(target, args);

389

}

390

391

public void invokeAllMethods(Object target, String pattern) {

392

handleLocator.findExecutionHandles(target.getClass())

393

.filter(handle -> handle.getMethodName().matches(pattern))

394

.forEach(handle -> {

395

try {

396

handle.invoke(target);

397

} catch (Exception e) {

398

System.err.println("Failed to invoke " + handle.getMethodName() + ": " + e.getMessage());

399

}

400

});

401

}

402

}

403

```

404

405

## Advanced Processing Patterns

406

407

### Conditional Processing

408

409

```java

410

@Singleton

411

public class ConditionalBeanProcessor implements BeanDefinitionProcessor<Object> {

412

413

private final Environment environment;

414

415

public ConditionalBeanProcessor(Environment environment) {

416

this.environment = environment;

417

}

418

419

@Override

420

public BeanDefinition<Object> process(BeanDefinition<Object> beanDefinition, BeanContext context) {

421

if (beanDefinition.hasAnnotation(ConditionalOnProperty.class)) {

422

String property = beanDefinition.getAnnotation(ConditionalOnProperty.class)

423

.stringValue("name").orElse("");

424

425

if (!environment.containsProperty(property)) {

426

// Return disabled bean definition

427

return new DisabledBeanDefinition<>(beanDefinition);

428

}

429

}

430

return beanDefinition;

431

}

432

}

433

```

434

435

### Method Interception Processing

436

437

```java

438

@Singleton

439

public class CachingMethodProcessor implements ExecutableMethodProcessor<Object> {

440

441

private final CacheManager cacheManager;

442

443

public CachingMethodProcessor(CacheManager cacheManager) {

444

this.cacheManager = cacheManager;

445

}

446

447

@Override

448

public void process(BeanDefinition<?> beanDefinition, ExecutableMethod<Object, ?> method) {

449

if (method.hasAnnotation(Cacheable.class)) {

450

String cacheName = method.getAnnotation(Cacheable.class)

451

.stringValue().orElse("default");

452

453

// Register caching interceptor

454

registerCachingInterceptor(beanDefinition, method, cacheName);

455

}

456

}

457

458

@Override

459

public Class<? extends Annotation> getAnnotationType() {

460

return Cacheable.class;

461

}

462

463

private void registerCachingInterceptor(BeanDefinition<?> beanDefinition,

464

ExecutableMethod<?, ?> method,

465

String cacheName) {

466

// Implementation to register caching interceptor

467

}

468

}

469

```

470

471

## Types

472

473

### Processing-related Types

474

475

```java { .api }

476

public interface BeanProperty<B, T> {

477

String getName();

478

Class<T> getType();

479

Argument<T> asArgument();

480

481

T get(B bean);

482

void set(B bean, T value);

483

484

boolean isReadOnly();

485

boolean isWriteOnly();

486

boolean hasAnnotation(Class<? extends Annotation> annotation);

487

}

488

489

public interface ExecutableMethod<T, R> extends AnnotationMetadata {

490

String getMethodName();

491

Class<T> getDeclaringType();

492

Class<R> getReturnType();

493

Argument<?>[] getArguments();

494

495

R invoke(T instance, Object... arguments);

496

boolean isAbstract();

497

boolean isStatic();

498

boolean isPublic();

499

boolean isPrivate();

500

boolean isFinal();

501

}

502

503

public class IntrospectionException extends RuntimeException {

504

public IntrospectionException(String message);

505

public IntrospectionException(String message, Throwable cause);

506

}

507

```