0
# Bean Invocation Utilities
1
2
Utility interfaces for invoking bean methods with automatic context management and lookup operations. These utilities provide convenient patterns for method invocation and bean resolution.
3
4
## Capabilities
5
6
### BeanInvoker Interface
7
8
Interface for invoking bean methods with automatic request context management.
9
10
```java { .api }
11
/**
12
* Invokes a business method of a bean. The request context is activated if necessary.
13
*/
14
public interface BeanInvoker<T> {
15
/**
16
* Default implementation that manages request context automatically.
17
* If request context is already active, delegates to invokeBean().
18
* If request context is not active, activates it, calls invokeBean(), then terminates it.
19
*/
20
default void invoke(T param) throws Exception;
21
22
/**
23
* Abstract method that must be implemented to define the actual bean invocation logic.
24
*/
25
void invokeBean(T param) throws Exception;
26
}
27
```
28
29
**Usage Examples:**
30
31
```java
32
import io.quarkus.arc.runtime.BeanInvoker;
33
import io.quarkus.arc.Arc;
34
import jakarta.enterprise.context.ApplicationScoped;
35
36
// Custom invoker for user processing
37
public class UserProcessingInvoker implements BeanInvoker<String> {
38
39
@Override
40
public void invokeBean(String userId) throws Exception {
41
// Get the actual service bean
42
UserService userService = Arc.container().instance(UserService.class).get();
43
44
// Perform the business operation
45
userService.processUser(userId);
46
userService.updateLastProcessed(userId);
47
}
48
}
49
50
// Usage
51
@ApplicationScoped
52
public class UserManager {
53
54
public void processUserWithContextManagement(String userId) {
55
UserProcessingInvoker invoker = new UserProcessingInvoker();
56
57
try {
58
// Context is automatically managed
59
invoker.invoke(userId);
60
} catch (Exception e) {
61
System.err.println("Failed to process user: " + userId);
62
throw new RuntimeException(e);
63
}
64
}
65
}
66
67
// Complex invoker with multiple operations
68
public class OrderProcessingInvoker implements BeanInvoker<OrderRequest> {
69
70
@Override
71
public void invokeBean(OrderRequest request) throws Exception {
72
// All these operations will run within the same request context
73
OrderService orderService = Arc.container().instance(OrderService.class).get();
74
PaymentService paymentService = Arc.container().instance(PaymentService.class).get();
75
InventoryService inventoryService = Arc.container().instance(InventoryService.class).get();
76
77
// Process order
78
Order order = orderService.createOrder(request);
79
80
// Process payment
81
PaymentResult payment = paymentService.processPayment(request.getPaymentInfo());
82
83
// Update inventory
84
inventoryService.reserveItems(request.getItems());
85
86
// Finalize order
87
orderService.finalizeOrder(order, payment);
88
}
89
}
90
91
// Supporting classes
92
class OrderRequest {
93
private PaymentInfo paymentInfo;
94
private List<OrderItem> items;
95
96
public PaymentInfo getPaymentInfo() { return paymentInfo; }
97
public List<OrderItem> getItems() { return items; }
98
}
99
100
class Order { }
101
class PaymentInfo { }
102
class PaymentResult { }
103
class OrderItem { }
104
105
interface UserService {
106
void processUser(String userId);
107
void updateLastProcessed(String userId);
108
}
109
110
interface OrderService {
111
Order createOrder(OrderRequest request);
112
void finalizeOrder(Order order, PaymentResult payment);
113
}
114
115
interface PaymentService {
116
PaymentResult processPayment(PaymentInfo paymentInfo);
117
}
118
119
interface InventoryService {
120
void reserveItems(List<OrderItem> items);
121
}
122
```
123
124
### BeanLookupSupplier Class
125
126
Supplier implementation that performs CDI bean lookup, bridging supplier pattern with CDI.
127
128
```java { .api }
129
/**
130
* Supplier that performs CDI bean lookup using Arc container.
131
*/
132
public class BeanLookupSupplier implements Supplier<Object> {
133
private Class<?> type;
134
135
public BeanLookupSupplier();
136
public BeanLookupSupplier(Class<?> type);
137
138
public Class<?> getType();
139
public BeanLookupSupplier setType(Class<?> type);
140
141
/**
142
* Performs bean lookup using Arc.container().instance(type).get()
143
*/
144
public Object get();
145
}
146
```
147
148
**Usage Examples:**
149
150
```java
151
import io.quarkus.arc.runtime.BeanLookupSupplier;
152
import jakarta.enterprise.context.ApplicationScoped;
153
import java.util.function.Supplier;
154
import java.util.concurrent.CompletableFuture;
155
156
@ApplicationScoped
157
public class SupplierBasedService {
158
159
public void demonstrateBasicUsage() {
160
// Create supplier for specific bean type
161
Supplier<Object> userServiceSupplier = new BeanLookupSupplier(UserService.class);
162
163
// Use the supplier
164
UserService userService = (UserService) userServiceSupplier.get();
165
userService.processUser("user123");
166
}
167
168
public void demonstrateFluentUsage() {
169
// Fluent API usage
170
BeanLookupSupplier supplier = new BeanLookupSupplier()
171
.setType(NotificationService.class);
172
173
NotificationService notificationService = (NotificationService) supplier.get();
174
notificationService.sendNotification("Hello World");
175
}
176
177
public void demonstrateAsyncUsage() {
178
// Use supplier in async contexts
179
Supplier<Object> emailServiceSupplier = new BeanLookupSupplier(EmailService.class);
180
181
CompletableFuture.supplyAsync(() -> {
182
EmailService emailService = (EmailService) emailServiceSupplier.get();
183
return emailService.sendEmail("test@example.com", "Subject", "Body");
184
}).thenAccept(result -> {
185
System.out.println("Email sent: " + result);
186
});
187
}
188
189
public <T> void demonstrateGenericWrapper(Class<T> beanType) {
190
// Generic wrapper for type safety
191
TypedBeanSupplier<T> typedSupplier = new TypedBeanSupplier<>(beanType);
192
T service = typedSupplier.get();
193
194
// Now we have type-safe access
195
if (service instanceof Processable) {
196
((Processable) service).process("data");
197
}
198
}
199
}
200
201
// Type-safe wrapper around BeanLookupSupplier
202
class TypedBeanSupplier<T> implements Supplier<T> {
203
private final BeanLookupSupplier delegate;
204
private final Class<T> type;
205
206
public TypedBeanSupplier(Class<T> type) {
207
this.type = type;
208
this.delegate = new BeanLookupSupplier(type);
209
}
210
211
@Override
212
@SuppressWarnings("unchecked")
213
public T get() {
214
return (T) delegate.get();
215
}
216
217
public Class<T> getType() {
218
return type;
219
}
220
}
221
222
// Supporting interfaces
223
interface NotificationService {
224
void sendNotification(String message);
225
}
226
227
interface EmailService {
228
boolean sendEmail(String to, String subject, String body);
229
}
230
```
231
232
### Advanced Invocation Patterns
233
234
Complex patterns combining both utilities for sophisticated invocation scenarios.
235
236
```java
237
import io.quarkus.arc.runtime.BeanInvoker;
238
import io.quarkus.arc.runtime.BeanLookupSupplier;
239
import jakarta.enterprise.context.ApplicationScoped;
240
import java.util.concurrent.CompletableFuture;
241
import java.util.function.Supplier;
242
243
@ApplicationScoped
244
public class AdvancedInvocationService {
245
246
// Batch processing with context management
247
public void batchProcessWithInvoker(List<String> userIds) {
248
BeanInvoker<List<String>> batchInvoker = new BeanInvoker<List<String>>() {
249
@Override
250
public void invokeBean(List<String> ids) throws Exception {
251
UserService userService = (UserService) new BeanLookupSupplier(UserService.class).get();
252
253
for (String id : ids) {
254
userService.processUser(id);
255
}
256
257
// Perform batch cleanup
258
userService.flushBatchProcessing();
259
}
260
};
261
262
try {
263
batchInvoker.invoke(userIds);
264
} catch (Exception e) {
265
throw new RuntimeException("Batch processing failed", e);
266
}
267
}
268
269
// Async processing with suppliers
270
public CompletableFuture<String> asyncProcessWithSupplier(String data) {
271
Supplier<Object> dataProcessorSupplier = new BeanLookupSupplier(DataProcessor.class);
272
273
return CompletableFuture.supplyAsync(() -> {
274
DataProcessor processor = (DataProcessor) dataProcessorSupplier.get();
275
return processor.processData(data);
276
});
277
}
278
279
// Conditional invocation based on bean availability
280
public void conditionalInvocation(String message) {
281
BeanInvoker<String> conditionalInvoker = new BeanInvoker<String>() {
282
@Override
283
public void invokeBean(String msg) throws Exception {
284
// Try to get optional service
285
BeanLookupSupplier auditSupplier = new BeanLookupSupplier()
286
.setType(AuditService.class);
287
288
try {
289
AuditService auditService = (AuditService) auditSupplier.get();
290
auditService.audit(msg);
291
} catch (Exception e) {
292
// Audit service not available, log instead
293
System.out.println("Audit not available, logging: " + msg);
294
}
295
296
// Always perform main operation
297
MainService mainService = (MainService) new BeanLookupSupplier(MainService.class).get();
298
mainService.process(msg);
299
}
300
};
301
302
try {
303
conditionalInvoker.invoke(message);
304
} catch (Exception e) {
305
throw new RuntimeException("Conditional invocation failed", e);
306
}
307
}
308
309
// Chain multiple operations with context preservation
310
public void chainedOperations(ProcessingRequest request) {
311
BeanInvoker<ProcessingRequest> chainedInvoker = new BeanInvoker<ProcessingRequest>() {
312
@Override
313
public void invokeBean(ProcessingRequest req) throws Exception {
314
// Create suppliers for all needed services
315
Supplier<Object> validatorSupplier = new BeanLookupSupplier(ValidationService.class);
316
Supplier<Object> transformerSupplier = new BeanLookupSupplier(TransformationService.class);
317
Supplier<Object> persisterSupplier = new BeanLookupSupplier(PersistenceService.class);
318
319
// Execute chain within single request context
320
ValidationService validator = (ValidationService) validatorSupplier.get();
321
validator.validate(req);
322
323
TransformationService transformer = (TransformationService) transformerSupplier.get();
324
ProcessedData processed = transformer.transform(req);
325
326
PersistenceService persister = (PersistenceService) persisterSupplier.get();
327
persister.persist(processed);
328
}
329
};
330
331
try {
332
chainedInvoker.invoke(request);
333
} catch (Exception e) {
334
throw new RuntimeException("Chained operations failed", e);
335
}
336
}
337
338
// Factory pattern using suppliers
339
public <T> ServiceFactory<T> createServiceFactory(Class<T> serviceType) {
340
return new ServiceFactory<T>() {
341
private final Supplier<Object> supplier = new BeanLookupSupplier(serviceType);
342
343
@Override
344
@SuppressWarnings("unchecked")
345
public T createService() {
346
return (T) supplier.get();
347
}
348
349
@Override
350
public void withService(ServiceConsumer<T> consumer) {
351
T service = createService();
352
consumer.accept(service);
353
}
354
};
355
}
356
357
public void demonstrateServiceFactory() {
358
ServiceFactory<ReportService> reportFactory = createServiceFactory(ReportService.class);
359
360
// Use factory to create and use service
361
reportFactory.withService(reportService -> {
362
reportService.generateReport("monthly");
363
reportService.sendReport();
364
});
365
}
366
}
367
368
// Supporting interfaces and classes
369
interface DataProcessor {
370
String processData(String data);
371
}
372
373
interface AuditService {
374
void audit(String message);
375
}
376
377
interface MainService {
378
void process(String message);
379
}
380
381
interface ValidationService {
382
void validate(ProcessingRequest request);
383
}
384
385
interface TransformationService {
386
ProcessedData transform(ProcessingRequest request);
387
}
388
389
interface PersistenceService {
390
void persist(ProcessedData data);
391
}
392
393
interface ReportService {
394
void generateReport(String type);
395
void sendReport();
396
}
397
398
interface ServiceFactory<T> {
399
T createService();
400
void withService(ServiceConsumer<T> consumer);
401
}
402
403
@FunctionalInterface
404
interface ServiceConsumer<T> {
405
void accept(T service);
406
}
407
408
class ProcessingRequest { }
409
class ProcessedData { }
410
411
// Extended UserService interface
412
interface UserService {
413
void processUser(String userId);
414
void updateLastProcessed(String userId);
415
void flushBatchProcessing();
416
}
417
```
418
419
### Integration with Async Processing
420
421
Examples of using bean invocation utilities in asynchronous contexts.
422
423
```java
424
import io.quarkus.arc.runtime.BeanInvoker;
425
import io.quarkus.arc.runtime.BeanLookupSupplier;
426
import jakarta.enterprise.context.ApplicationScoped;
427
import java.util.concurrent.*;
428
import java.util.function.Supplier;
429
430
@ApplicationScoped
431
public class AsyncInvocationService {
432
433
private final ExecutorService executor = Executors.newFixedThreadPool(5);
434
435
public CompletableFuture<Void> asyncInvokeWithContext(String data) {
436
BeanInvoker<String> asyncInvoker = new BeanInvoker<String>() {
437
@Override
438
public void invokeBean(String input) throws Exception {
439
AsyncProcessingService service = (AsyncProcessingService)
440
new BeanLookupSupplier(AsyncProcessingService.class).get();
441
service.processAsync(input);
442
}
443
};
444
445
return CompletableFuture.runAsync(() -> {
446
try {
447
asyncInvoker.invoke(data);
448
} catch (Exception e) {
449
throw new RuntimeException(e);
450
}
451
}, executor);
452
}
453
454
public CompletableFuture<String> asyncSupplyWithBean(String input) {
455
Supplier<Object> serviceSupplier = new BeanLookupSupplier(ComputationService.class);
456
457
return CompletableFuture.supplyAsync(() -> {
458
ComputationService service = (ComputationService) serviceSupplier.get();
459
return service.compute(input);
460
}, executor);
461
}
462
463
public void parallelProcessing(List<String> items) {
464
List<CompletableFuture<Void>> futures = items.stream()
465
.map(item -> {
466
BeanInvoker<String> itemInvoker = new BeanInvoker<String>() {
467
@Override
468
public void invokeBean(String data) throws Exception {
469
ItemProcessor processor = (ItemProcessor)
470
new BeanLookupSupplier(ItemProcessor.class).get();
471
processor.processItem(data);
472
}
473
};
474
475
return CompletableFuture.runAsync(() -> {
476
try {
477
itemInvoker.invoke(item);
478
} catch (Exception e) {
479
throw new RuntimeException(e);
480
}
481
}, executor);
482
})
483
.collect(Collectors.toList());
484
485
// Wait for all to complete
486
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
487
}
488
489
// Cleanup
490
@PreDestroy
491
public void shutdown() {
492
executor.shutdown();
493
}
494
}
495
496
// Supporting interfaces
497
interface AsyncProcessingService {
498
void processAsync(String data);
499
}
500
501
interface ComputationService {
502
String compute(String input);
503
}
504
505
interface ItemProcessor {
506
void processItem(String item);
507
}
508
```
509
510
## Best Practices
511
512
### Error Handling
513
514
```java
515
public class SafeInvocationPractices {
516
517
public void safeInvokerUsage() {
518
BeanInvoker<String> safeInvoker = new BeanInvoker<String>() {
519
@Override
520
public void invokeBean(String data) throws Exception {
521
try {
522
RiskyService service = (RiskyService)
523
new BeanLookupSupplier(RiskyService.class).get();
524
service.riskyOperation(data);
525
} catch (ServiceException e) {
526
// Handle service-specific exceptions
527
System.err.println("Service error: " + e.getMessage());
528
throw e;
529
} catch (Exception e) {
530
// Handle unexpected exceptions
531
System.err.println("Unexpected error: " + e.getMessage());
532
throw new RuntimeException("Operation failed", e);
533
}
534
}
535
};
536
537
try {
538
safeInvoker.invoke("test-data");
539
} catch (Exception e) {
540
// Final error handling
541
System.err.println("Invocation failed: " + e.getMessage());
542
}
543
}
544
545
public void safeSupplierUsage() {
546
BeanLookupSupplier supplier = new BeanLookupSupplier()
547
.setType(OptionalService.class);
548
549
try {
550
OptionalService service = (OptionalService) supplier.get();
551
service.performOperation();
552
} catch (Exception e) {
553
// Handle bean lookup failures
554
System.err.println("Service not available: " + e.getMessage());
555
// Provide fallback behavior
556
performFallbackOperation();
557
}
558
}
559
560
private void performFallbackOperation() {
561
System.out.println("Executing fallback operation");
562
}
563
}
564
565
interface RiskyService {
566
void riskyOperation(String data) throws ServiceException;
567
}
568
569
interface OptionalService {
570
void performOperation();
571
}
572
573
class ServiceException extends Exception {
574
public ServiceException(String message) {
575
super(message);
576
}
577
}
578
```
579
580
### Resource Management
581
582
```java
583
public class ResourceManagementPractices {
584
585
public void properResourceHandling() {
586
// Use try-with-resources pattern when applicable
587
BeanInvoker<String> resourceInvoker = new BeanInvoker<String>() {
588
@Override
589
public void invokeBean(String data) throws Exception {
590
ResourceIntensiveService service = (ResourceIntensiveService)
591
new BeanLookupSupplier(ResourceIntensiveService.class).get();
592
593
// Service should implement AutoCloseable if it manages resources
594
if (service instanceof AutoCloseable) {
595
try (AutoCloseable closeable = (AutoCloseable) service) {
596
service.processWithResources(data);
597
}
598
} else {
599
service.processWithResources(data);
600
}
601
}
602
};
603
604
try {
605
resourceInvoker.invoke("resource-intensive-data");
606
} catch (Exception e) {
607
throw new RuntimeException("Resource handling failed", e);
608
}
609
}
610
}
611
612
interface ResourceIntensiveService {
613
void processWithResources(String data);
614
}
615
```