CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-quarkus--quarkus-arc

Build time CDI dependency injection framework for Quarkus applications with conditional bean support and context management

Pending
Overview
Eval results
Files

bean-invocation.mddocs/

Bean Invocation Utilities

Utility interfaces for invoking bean methods with automatic context management and lookup operations. These utilities provide convenient patterns for method invocation and bean resolution.

Capabilities

BeanInvoker Interface

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);
}

BeanLookupSupplier Class

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);
}

Advanced Invocation Patterns

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();
}

Integration with Async Processing

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);
}

Best Practices

Error Handling

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);
    }
}

Resource Management

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

docs

bean-container.md

bean-invocation.md

build-profiles.md

build-properties.md

index.md

interceptor-integration.md

logger-injection.md

runtime-lookup.md

tile.json