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
```