Build time CDI dependency injection framework for Quarkus applications with conditional bean support and context management
—
Utility interfaces for invoking bean methods with automatic context management and lookup operations. These utilities provide convenient patterns for method invocation and bean resolution.
Interface for invoking bean methods with automatic request context management.
/**
* Invokes a business method of a bean. The request context is activated if necessary.
*/
public interface BeanInvoker<T> {
/**
* Default implementation that manages request context automatically.
* If request context is already active, delegates to invokeBean().
* If request context is not active, activates it, calls invokeBean(), then terminates it.
*/
default void invoke(T param) throws Exception;
/**
* Abstract method that must be implemented to define the actual bean invocation logic.
*/
void invokeBean(T param) throws Exception;
}Usage Examples:
import io.quarkus.arc.runtime.BeanInvoker;
import io.quarkus.arc.Arc;
import jakarta.enterprise.context.ApplicationScoped;
// Custom invoker for user processing
public class UserProcessingInvoker implements BeanInvoker<String> {
@Override
public void invokeBean(String userId) throws Exception {
// Get the actual service bean
UserService userService = Arc.container().instance(UserService.class).get();
// Perform the business operation
userService.processUser(userId);
userService.updateLastProcessed(userId);
}
}
// Usage
@ApplicationScoped
public class UserManager {
public void processUserWithContextManagement(String userId) {
UserProcessingInvoker invoker = new UserProcessingInvoker();
try {
// Context is automatically managed
invoker.invoke(userId);
} catch (Exception e) {
System.err.println("Failed to process user: " + userId);
throw new RuntimeException(e);
}
}
}
// Complex invoker with multiple operations
public class OrderProcessingInvoker implements BeanInvoker<OrderRequest> {
@Override
public void invokeBean(OrderRequest request) throws Exception {
// All these operations will run within the same request context
OrderService orderService = Arc.container().instance(OrderService.class).get();
PaymentService paymentService = Arc.container().instance(PaymentService.class).get();
InventoryService inventoryService = Arc.container().instance(InventoryService.class).get();
// Process order
Order order = orderService.createOrder(request);
// Process payment
PaymentResult payment = paymentService.processPayment(request.getPaymentInfo());
// Update inventory
inventoryService.reserveItems(request.getItems());
// Finalize order
orderService.finalizeOrder(order, payment);
}
}
// Supporting classes
class OrderRequest {
private PaymentInfo paymentInfo;
private List<OrderItem> items;
public PaymentInfo getPaymentInfo() { return paymentInfo; }
public List<OrderItem> getItems() { return items; }
}
class Order { }
class PaymentInfo { }
class PaymentResult { }
class OrderItem { }
interface UserService {
void processUser(String userId);
void updateLastProcessed(String userId);
}
interface OrderService {
Order createOrder(OrderRequest request);
void finalizeOrder(Order order, PaymentResult payment);
}
interface PaymentService {
PaymentResult processPayment(PaymentInfo paymentInfo);
}
interface InventoryService {
void reserveItems(List<OrderItem> items);
}Supplier implementation that performs CDI bean lookup, bridging supplier pattern with CDI.
/**
* Supplier that performs CDI bean lookup using Arc container.
*/
public class BeanLookupSupplier implements Supplier<Object> {
private Class<?> type;
public BeanLookupSupplier();
public BeanLookupSupplier(Class<?> type);
public Class<?> getType();
public BeanLookupSupplier setType(Class<?> type);
/**
* Performs bean lookup using Arc.container().instance(type).get()
*/
public Object get();
}Usage Examples:
import io.quarkus.arc.runtime.BeanLookupSupplier;
import jakarta.enterprise.context.ApplicationScoped;
import java.util.function.Supplier;
import java.util.concurrent.CompletableFuture;
@ApplicationScoped
public class SupplierBasedService {
public void demonstrateBasicUsage() {
// Create supplier for specific bean type
Supplier<Object> userServiceSupplier = new BeanLookupSupplier(UserService.class);
// Use the supplier
UserService userService = (UserService) userServiceSupplier.get();
userService.processUser("user123");
}
public void demonstrateFluentUsage() {
// Fluent API usage
BeanLookupSupplier supplier = new BeanLookupSupplier()
.setType(NotificationService.class);
NotificationService notificationService = (NotificationService) supplier.get();
notificationService.sendNotification("Hello World");
}
public void demonstrateAsyncUsage() {
// Use supplier in async contexts
Supplier<Object> emailServiceSupplier = new BeanLookupSupplier(EmailService.class);
CompletableFuture.supplyAsync(() -> {
EmailService emailService = (EmailService) emailServiceSupplier.get();
return emailService.sendEmail("test@example.com", "Subject", "Body");
}).thenAccept(result -> {
System.out.println("Email sent: " + result);
});
}
public <T> void demonstrateGenericWrapper(Class<T> beanType) {
// Generic wrapper for type safety
TypedBeanSupplier<T> typedSupplier = new TypedBeanSupplier<>(beanType);
T service = typedSupplier.get();
// Now we have type-safe access
if (service instanceof Processable) {
((Processable) service).process("data");
}
}
}
// Type-safe wrapper around BeanLookupSupplier
class TypedBeanSupplier<T> implements Supplier<T> {
private final BeanLookupSupplier delegate;
private final Class<T> type;
public TypedBeanSupplier(Class<T> type) {
this.type = type;
this.delegate = new BeanLookupSupplier(type);
}
@Override
@SuppressWarnings("unchecked")
public T get() {
return (T) delegate.get();
}
public Class<T> getType() {
return type;
}
}
// Supporting interfaces
interface NotificationService {
void sendNotification(String message);
}
interface EmailService {
boolean sendEmail(String to, String subject, String body);
}Complex patterns combining both utilities for sophisticated invocation scenarios.
import io.quarkus.arc.runtime.BeanInvoker;
import io.quarkus.arc.runtime.BeanLookupSupplier;
import jakarta.enterprise.context.ApplicationScoped;
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;
@ApplicationScoped
public class AdvancedInvocationService {
// Batch processing with context management
public void batchProcessWithInvoker(List<String> userIds) {
BeanInvoker<List<String>> batchInvoker = new BeanInvoker<List<String>>() {
@Override
public void invokeBean(List<String> ids) throws Exception {
UserService userService = (UserService) new BeanLookupSupplier(UserService.class).get();
for (String id : ids) {
userService.processUser(id);
}
// Perform batch cleanup
userService.flushBatchProcessing();
}
};
try {
batchInvoker.invoke(userIds);
} catch (Exception e) {
throw new RuntimeException("Batch processing failed", e);
}
}
// Async processing with suppliers
public CompletableFuture<String> asyncProcessWithSupplier(String data) {
Supplier<Object> dataProcessorSupplier = new BeanLookupSupplier(DataProcessor.class);
return CompletableFuture.supplyAsync(() -> {
DataProcessor processor = (DataProcessor) dataProcessorSupplier.get();
return processor.processData(data);
});
}
// Conditional invocation based on bean availability
public void conditionalInvocation(String message) {
BeanInvoker<String> conditionalInvoker = new BeanInvoker<String>() {
@Override
public void invokeBean(String msg) throws Exception {
// Try to get optional service
BeanLookupSupplier auditSupplier = new BeanLookupSupplier()
.setType(AuditService.class);
try {
AuditService auditService = (AuditService) auditSupplier.get();
auditService.audit(msg);
} catch (Exception e) {
// Audit service not available, log instead
System.out.println("Audit not available, logging: " + msg);
}
// Always perform main operation
MainService mainService = (MainService) new BeanLookupSupplier(MainService.class).get();
mainService.process(msg);
}
};
try {
conditionalInvoker.invoke(message);
} catch (Exception e) {
throw new RuntimeException("Conditional invocation failed", e);
}
}
// Chain multiple operations with context preservation
public void chainedOperations(ProcessingRequest request) {
BeanInvoker<ProcessingRequest> chainedInvoker = new BeanInvoker<ProcessingRequest>() {
@Override
public void invokeBean(ProcessingRequest req) throws Exception {
// Create suppliers for all needed services
Supplier<Object> validatorSupplier = new BeanLookupSupplier(ValidationService.class);
Supplier<Object> transformerSupplier = new BeanLookupSupplier(TransformationService.class);
Supplier<Object> persisterSupplier = new BeanLookupSupplier(PersistenceService.class);
// Execute chain within single request context
ValidationService validator = (ValidationService) validatorSupplier.get();
validator.validate(req);
TransformationService transformer = (TransformationService) transformerSupplier.get();
ProcessedData processed = transformer.transform(req);
PersistenceService persister = (PersistenceService) persisterSupplier.get();
persister.persist(processed);
}
};
try {
chainedInvoker.invoke(request);
} catch (Exception e) {
throw new RuntimeException("Chained operations failed", e);
}
}
// Factory pattern using suppliers
public <T> ServiceFactory<T> createServiceFactory(Class<T> serviceType) {
return new ServiceFactory<T>() {
private final Supplier<Object> supplier = new BeanLookupSupplier(serviceType);
@Override
@SuppressWarnings("unchecked")
public T createService() {
return (T) supplier.get();
}
@Override
public void withService(ServiceConsumer<T> consumer) {
T service = createService();
consumer.accept(service);
}
};
}
public void demonstrateServiceFactory() {
ServiceFactory<ReportService> reportFactory = createServiceFactory(ReportService.class);
// Use factory to create and use service
reportFactory.withService(reportService -> {
reportService.generateReport("monthly");
reportService.sendReport();
});
}
}
// Supporting interfaces and classes
interface DataProcessor {
String processData(String data);
}
interface AuditService {
void audit(String message);
}
interface MainService {
void process(String message);
}
interface ValidationService {
void validate(ProcessingRequest request);
}
interface TransformationService {
ProcessedData transform(ProcessingRequest request);
}
interface PersistenceService {
void persist(ProcessedData data);
}
interface ReportService {
void generateReport(String type);
void sendReport();
}
interface ServiceFactory<T> {
T createService();
void withService(ServiceConsumer<T> consumer);
}
@FunctionalInterface
interface ServiceConsumer<T> {
void accept(T service);
}
class ProcessingRequest { }
class ProcessedData { }
// Extended UserService interface
interface UserService {
void processUser(String userId);
void updateLastProcessed(String userId);
void flushBatchProcessing();
}Examples of using bean invocation utilities in asynchronous contexts.
import io.quarkus.arc.runtime.BeanInvoker;
import io.quarkus.arc.runtime.BeanLookupSupplier;
import jakarta.enterprise.context.ApplicationScoped;
import java.util.concurrent.*;
import java.util.function.Supplier;
@ApplicationScoped
public class AsyncInvocationService {
private final ExecutorService executor = Executors.newFixedThreadPool(5);
public CompletableFuture<Void> asyncInvokeWithContext(String data) {
BeanInvoker<String> asyncInvoker = new BeanInvoker<String>() {
@Override
public void invokeBean(String input) throws Exception {
AsyncProcessingService service = (AsyncProcessingService)
new BeanLookupSupplier(AsyncProcessingService.class).get();
service.processAsync(input);
}
};
return CompletableFuture.runAsync(() -> {
try {
asyncInvoker.invoke(data);
} catch (Exception e) {
throw new RuntimeException(e);
}
}, executor);
}
public CompletableFuture<String> asyncSupplyWithBean(String input) {
Supplier<Object> serviceSupplier = new BeanLookupSupplier(ComputationService.class);
return CompletableFuture.supplyAsync(() -> {
ComputationService service = (ComputationService) serviceSupplier.get();
return service.compute(input);
}, executor);
}
public void parallelProcessing(List<String> items) {
List<CompletableFuture<Void>> futures = items.stream()
.map(item -> {
BeanInvoker<String> itemInvoker = new BeanInvoker<String>() {
@Override
public void invokeBean(String data) throws Exception {
ItemProcessor processor = (ItemProcessor)
new BeanLookupSupplier(ItemProcessor.class).get();
processor.processItem(data);
}
};
return CompletableFuture.runAsync(() -> {
try {
itemInvoker.invoke(item);
} catch (Exception e) {
throw new RuntimeException(e);
}
}, executor);
})
.collect(Collectors.toList());
// Wait for all to complete
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
}
// Cleanup
@PreDestroy
public void shutdown() {
executor.shutdown();
}
}
// Supporting interfaces
interface AsyncProcessingService {
void processAsync(String data);
}
interface ComputationService {
String compute(String input);
}
interface ItemProcessor {
void processItem(String item);
}public class SafeInvocationPractices {
public void safeInvokerUsage() {
BeanInvoker<String> safeInvoker = new BeanInvoker<String>() {
@Override
public void invokeBean(String data) throws Exception {
try {
RiskyService service = (RiskyService)
new BeanLookupSupplier(RiskyService.class).get();
service.riskyOperation(data);
} catch (ServiceException e) {
// Handle service-specific exceptions
System.err.println("Service error: " + e.getMessage());
throw e;
} catch (Exception e) {
// Handle unexpected exceptions
System.err.println("Unexpected error: " + e.getMessage());
throw new RuntimeException("Operation failed", e);
}
}
};
try {
safeInvoker.invoke("test-data");
} catch (Exception e) {
// Final error handling
System.err.println("Invocation failed: " + e.getMessage());
}
}
public void safeSupplierUsage() {
BeanLookupSupplier supplier = new BeanLookupSupplier()
.setType(OptionalService.class);
try {
OptionalService service = (OptionalService) supplier.get();
service.performOperation();
} catch (Exception e) {
// Handle bean lookup failures
System.err.println("Service not available: " + e.getMessage());
// Provide fallback behavior
performFallbackOperation();
}
}
private void performFallbackOperation() {
System.out.println("Executing fallback operation");
}
}
interface RiskyService {
void riskyOperation(String data) throws ServiceException;
}
interface OptionalService {
void performOperation();
}
class ServiceException extends Exception {
public ServiceException(String message) {
super(message);
}
}public class ResourceManagementPractices {
public void properResourceHandling() {
// Use try-with-resources pattern when applicable
BeanInvoker<String> resourceInvoker = new BeanInvoker<String>() {
@Override
public void invokeBean(String data) throws Exception {
ResourceIntensiveService service = (ResourceIntensiveService)
new BeanLookupSupplier(ResourceIntensiveService.class).get();
// Service should implement AutoCloseable if it manages resources
if (service instanceof AutoCloseable) {
try (AutoCloseable closeable = (AutoCloseable) service) {
service.processWithResources(data);
}
} else {
service.processWithResources(data);
}
}
};
try {
resourceInvoker.invoke("resource-intensive-data");
} catch (Exception e) {
throw new RuntimeException("Resource handling failed", e);
}
}
}
interface ResourceIntensiveService {
void processWithResources(String data);
}Install with Tessl CLI
npx tessl i tessl/maven-io-quarkus--quarkus-arc