CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-micronaut--micronaut-inject

Core dependency injection interfaces and components for the Micronaut Framework

Pending
Overview
Eval results
Files

bean-processing.mddocs/

Bean Processing and Extensibility

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.

Core Processing Interfaces

BeanDefinitionProcessor

Interface for processing and modifying bean definitions during context initialization.

/**
 * Processor interface for bean definition modification
 * @param <T> The bean type
 */
public interface BeanDefinitionProcessor<T> {
    /**
     * Process a bean definition and optionally return a modified version
     * @param beanDefinition The original bean definition
     * @param context The bean context
     * @return The processed bean definition
     */
    BeanDefinition<T> process(BeanDefinition<T> beanDefinition, BeanContext context);
    
    /**
     * Check if this processor applies to the given bean definition
     * @param beanDefinition The bean definition to check
     * @return true if this processor should process the bean definition
     */
    default boolean supports(BeanDefinition<T> beanDefinition) {
        return true;
    }
}

ExecutableMethodProcessor

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

/**
 * Processor interface for executable method processing
 * @param <T> The bean type
 */
public interface ExecutableMethodProcessor<T> {
    /**
     * Process an executable method
     * @param beanDefinition The bean definition containing the method
     * @param method The executable method to process
     */
    void process(BeanDefinition<?> beanDefinition, ExecutableMethod<T, ?> method);
    
    /**
     * Get the method annotation type this processor handles
     * @return The annotation type
     */
    Class<? extends Annotation> getAnnotationType();
}

Usage Examples:

import io.micronaut.context.processor.BeanDefinitionProcessor;
import io.micronaut.context.processor.ExecutableMethodProcessor;
import jakarta.inject.Singleton;

@Singleton
public class AuditBeanProcessor implements BeanDefinitionProcessor<Object> {
    
    @Override
    public BeanDefinition<Object> process(BeanDefinition<Object> beanDefinition, BeanContext context) {
        if (beanDefinition.hasAnnotation(Auditable.class)) {
            // Wrap bean definition to add auditing capabilities
            return new AuditableBeanDefinition<>(beanDefinition);
        }
        return beanDefinition;
    }
    
    @Override
    public boolean supports(BeanDefinition<Object> beanDefinition) {
        return beanDefinition.hasAnnotation(Auditable.class);
    }
}

@Singleton
public class TimedMethodProcessor implements ExecutableMethodProcessor<Object> {
    
    @Override
    public void process(BeanDefinition<?> beanDefinition, ExecutableMethod<Object, ?> method) {
        if (method.hasAnnotation(Timed.class)) {
            // Register timing interceptor for this method
            registerTimingInterceptor(beanDefinition, method);
        }
    }
    
    @Override
    public Class<? extends Annotation> getAnnotationType() {
        return Timed.class;
    }
    
    private void registerTimingInterceptor(BeanDefinition<?> beanDefinition, ExecutableMethod<?, ?> method) {
        // Implementation to register timing interceptor
    }
}

Registry and Introspection

BeanDefinitionRegistry

Registry interface providing comprehensive bean definition management and introspection.

/**
 * Registry for bean definition metadata and introspection
 */
public interface BeanDefinitionRegistry {
    /**
     * Check if a bean of the given type exists
     * @param beanType The bean type
     * @return true if bean exists
     */
    <T> boolean containsBean(Class<T> beanType);
    
    /**
     * Check if a bean exists with qualifier
     * @param beanType The bean type
     * @param qualifier The qualifier
     * @return true if bean exists
     */
    <T> boolean containsBean(Class<T> beanType, Qualifier<T> qualifier);
    
    /**
     * Find bean definition for the given type
     * @param beanType The bean type
     * @return Optional bean definition
     */
    <T> Optional<BeanDefinition<T>> findBeanDefinition(Class<T> beanType);
    
    /**
     * Find bean definition with qualifier
     * @param beanType The bean type
     * @param qualifier The qualifier
     * @return Optional bean definition
     */
    <T> Optional<BeanDefinition<T>> findBeanDefinition(Class<T> beanType, Qualifier<T> qualifier);
    
    /**
     * Get all bean definitions for the given type
     * @param beanType The bean type
     * @return Collection of bean definitions
     */
    <T> Collection<BeanDefinition<T>> getBeanDefinitions(Class<T> beanType);
    
    /**
     * Get single bean definition for the given type
     * @param beanType The bean type
     * @return Bean definition
     * @throws NoSuchBeanException if not found
     * @throws NonUniqueBeanException if multiple found
     */
    <T> BeanDefinition<T> getBeanDefinition(Class<T> beanType);
    
    /**
     * Get all bean definitions
     * @return Collection of all bean definitions
     */
    Collection<BeanDefinition<?>> getAllBeanDefinitions();
    
    /**
     * Get bean definitions by annotation
     * @param annotation The annotation type
     * @return Collection of matching bean definitions
     */
    Collection<BeanDefinition<?>> getBeanDefinitionsForAnnotation(Class<? extends Annotation> annotation);
}

BeanIntrospection

Interface for introspecting bean properties and methods without reflection.

/**
 * Bean introspection interface for reflection-free property access
 * @param <T> The bean type
 */
public interface BeanIntrospection<T> {
    /**
     * Get the bean type
     * @return The bean type
     */
    Class<T> getBeanType();
    
    /**
     * Instantiate the bean
     * @param args Constructor arguments
     * @return Bean instance
     */
    T instantiate(Object... args);
    
    /**
     * Get all bean properties
     * @return Collection of bean properties
     */
    Collection<BeanProperty<T, Object>> getBeanProperties();
    
    /**
     * Get bean property by name
     * @param name Property name
     * @return Optional bean property
     */
    Optional<BeanProperty<T, Object>> getProperty(String name);
    
    /**
     * Get required bean property by name
     * @param name Property name
     * @return Bean property
     * @throws IntrospectionException if property not found
     */
    BeanProperty<T, Object> getRequiredProperty(String name);
    
    /**
     * Get indexed bean properties (array/collection properties)
     * @return Collection of indexed properties
     */
    Collection<BeanProperty<T, Object>> getIndexedProperties();
    
    /**
     * Get constructor arguments
     * @return Array of constructor arguments
     */
    Argument<?>[] getConstructorArguments();
}

Usage Examples:

import io.micronaut.core.beans.BeanIntrospection;
import io.micronaut.core.beans.BeanProperty;

public class BeanProcessor {
    
    public void processBeanProperties(Object bean) {
        BeanIntrospection<Object> introspection = BeanIntrospection.getIntrospection(bean.getClass());
        
        // Process all properties
        for (BeanProperty<Object, Object> property : introspection.getBeanProperties()) {
            Object value = property.get(bean);
            System.out.println("Property " + property.getName() + " = " + value);
            
            // Validate or transform property values
            if (property.hasAnnotation(NotNull.class) && value == null) {
                throw new ValidationException("Property " + property.getName() + " cannot be null");
            }
        }
        
        // Copy properties between beans
        BeanIntrospection<Object> targetIntrospection = BeanIntrospection.getIntrospection(TargetBean.class);
        Object targetBean = targetIntrospection.instantiate();
        
        introspection.getBeanProperties().forEach(sourceProperty -> {
            targetIntrospection.getProperty(sourceProperty.getName())
                .ifPresent(targetProperty -> {
                    Object value = sourceProperty.get(bean);
                    targetProperty.set(targetBean, value);
                });
        });
    }
}

Execution and Method Handling

ExecutionHandleLocator

Interface for optimized method execution without reflection.

/**
 * Locator for optimized executable method handles
 */
public interface ExecutionHandleLocator {
    /**
     * Find execution handle for method
     * @param beanType The bean type
     * @param method The method name
     * @param argumentTypes The argument types
     * @return Optional execution handle
     */
    <T, R> Optional<ExecutionHandle<T, R>> findExecutionHandle(Class<T> beanType, String method, Class<?>... argumentTypes);
    
    /**
     * Get required execution handle for method
     * @param beanType The bean type
     * @param method The method name
     * @param argumentTypes The argument types
     * @return Execution handle
     * @throws NoSuchMethodException if method not found
     */
    <T, R> ExecutionHandle<T, R> getExecutionHandle(Class<T> beanType, String method, Class<?>... argumentTypes);
    
    /**
     * Find all execution handles for bean type
     * @param beanType The bean type
     * @return Stream of execution handles
     */
    <T> Stream<ExecutionHandle<T, ?>> findExecutionHandles(Class<T> beanType);
}

ExecutionHandle

Interface representing an optimized executable method.

/**
 * Handle for optimized method execution
 * @param <T> The bean type
 * @param <R> The return type
 */
public interface ExecutionHandle<T, R> {
    /**
     * Invoke the method on the target instance
     * @param target The target instance
     * @param arguments The method arguments
     * @return The method result
     */
    R invoke(T target, Object... arguments);
    
    /**
     * Get the executable method
     * @return The executable method
     */
    ExecutableMethod<T, R> getExecutableMethod();
    
    /**
     * Get the target bean type
     * @return The bean type
     */
    Class<T> getDeclaringType();
    
    /**
     * Get the method name
     * @return The method name
     */
    String getMethodName();
    
    /**
     * Get argument types
     * @return Array of argument types
     */
    Argument<?>[] getArguments();
    
    /**
     * Get return type
     * @return The return type argument
     */
    Argument<R> getReturnType();
}

Usage Examples:

import io.micronaut.inject.ExecutionHandle;
import io.micronaut.inject.ExecutionHandleLocator;

@Singleton
public class DynamicMethodInvoker {
    
    private final ExecutionHandleLocator handleLocator;
    
    public DynamicMethodInvoker(ExecutionHandleLocator handleLocator) {
        this.handleLocator = handleLocator;
    }
    
    public Object invokeMethod(Object target, String methodName, Object... args) {
        Class<?>[] argTypes = Arrays.stream(args)
            .map(Object::getClass)
            .toArray(Class<?>[]::new);
            
        ExecutionHandle<Object, Object> handle = handleLocator
            .findExecutionHandle(target.getClass(), methodName, argTypes)
            .orElseThrow(() -> new NoSuchMethodException("Method not found: " + methodName));
            
        return handle.invoke(target, args);
    }
    
    public void invokeAllMethods(Object target, String pattern) {
        handleLocator.findExecutionHandles(target.getClass())
            .filter(handle -> handle.getMethodName().matches(pattern))
            .forEach(handle -> {
                try {
                    handle.invoke(target);
                } catch (Exception e) {
                    System.err.println("Failed to invoke " + handle.getMethodName() + ": " + e.getMessage());
                }
            });
    }
}

Advanced Processing Patterns

Conditional Processing

@Singleton
public class ConditionalBeanProcessor implements BeanDefinitionProcessor<Object> {
    
    private final Environment environment;
    
    public ConditionalBeanProcessor(Environment environment) {
        this.environment = environment;
    }
    
    @Override
    public BeanDefinition<Object> process(BeanDefinition<Object> beanDefinition, BeanContext context) {
        if (beanDefinition.hasAnnotation(ConditionalOnProperty.class)) {
            String property = beanDefinition.getAnnotation(ConditionalOnProperty.class)
                .stringValue("name").orElse("");
            
            if (!environment.containsProperty(property)) {
                // Return disabled bean definition
                return new DisabledBeanDefinition<>(beanDefinition);
            }
        }
        return beanDefinition;
    }
}

Method Interception Processing

@Singleton
public class CachingMethodProcessor implements ExecutableMethodProcessor<Object> {
    
    private final CacheManager cacheManager;
    
    public CachingMethodProcessor(CacheManager cacheManager) {
        this.cacheManager = cacheManager;
    }
    
    @Override
    public void process(BeanDefinition<?> beanDefinition, ExecutableMethod<Object, ?> method) {
        if (method.hasAnnotation(Cacheable.class)) {
            String cacheName = method.getAnnotation(Cacheable.class)
                .stringValue().orElse("default");
            
            // Register caching interceptor
            registerCachingInterceptor(beanDefinition, method, cacheName);
        }
    }
    
    @Override
    public Class<? extends Annotation> getAnnotationType() {
        return Cacheable.class;
    }
    
    private void registerCachingInterceptor(BeanDefinition<?> beanDefinition, 
                                          ExecutableMethod<?, ?> method, 
                                          String cacheName) {
        // Implementation to register caching interceptor
    }
}

Types

Processing-related Types

public interface BeanProperty<B, T> {
    String getName();
    Class<T> getType();
    Argument<T> asArgument();
    
    T get(B bean);
    void set(B bean, T value);
    
    boolean isReadOnly();
    boolean isWriteOnly();
    boolean hasAnnotation(Class<? extends Annotation> annotation);
}

public interface ExecutableMethod<T, R> extends AnnotationMetadata {
    String getMethodName();
    Class<T> getDeclaringType();
    Class<R> getReturnType();
    Argument<?>[] getArguments();
    
    R invoke(T instance, Object... arguments);
    boolean isAbstract();
    boolean isStatic();
    boolean isPublic();
    boolean isPrivate();
    boolean isFinal();
}

public class IntrospectionException extends RuntimeException {
    public IntrospectionException(String message);
    public IntrospectionException(String message, Throwable cause);
}

Install with Tessl CLI

npx tessl i tessl/maven-io-micronaut--micronaut-inject

docs

annotations.md

application-context.md

bean-definition.md

bean-factory.md

bean-processing.md

bean-providers.md

environment-config.md

events.md

exceptions.md

index.md

scoping.md

tile.json