All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.micronaut.context.BeanResolutionContext Maven / Gradle / Ivy

/*
 * Copyright 2017-2020 original authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.micronaut.context;

import io.micronaut.context.env.ConfigurationPath;
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.core.annotation.UsedByGeneratedCode;
import io.micronaut.core.type.Argument;
import io.micronaut.core.value.ValueResolver;
import io.micronaut.inject.BeanDefinition;
import io.micronaut.inject.BeanIdentifier;
import io.micronaut.inject.FieldInjectionPoint;
import io.micronaut.inject.InjectionPoint;
import io.micronaut.inject.MethodInjectionPoint;

import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;

/**
 * Represents the resolution context for a current resolve of a given bean.
 *
 * @author Graeme Rocher
 * @since 1.0
 */
@Internal
public interface BeanResolutionContext extends ValueResolver, AutoCloseable {

    @Override
    default void close() {
        // no-op
    }

    /**
     * Get a bean of the given type and qualifier.
     *
     * @param beanType          The bean type
     * @param qualifier         The qualifier
     * @param                The bean type parameter
     * @return The found bean
     * @since 3.5.0
     */
    @NonNull
     T getBean(@NonNull Argument beanType, @Nullable Qualifier qualifier);

    /**
     * Get all beans of the given type and qualifier.
     *
     * @param beanType          The bean type
     * @param qualifier         The qualifier
     * @param                The bean type parameter
     * @return The found beans
     * @since 3.5.0
     */
    @NonNull
     Collection getBeansOfType(@NonNull Argument beanType, @Nullable Qualifier qualifier);

    /**
     * Obtains a stream of beans of the given type and qualifier.
     *
     * @param beanType          The bean type
     * @param qualifier         The qualifier
     * @param                The bean concrete type
     * @return A stream
     * @since 3.5.0
     */
    @NonNull
     Stream streamOfType(@NonNull  Argument beanType, @Nullable  Qualifier qualifier);

    /**
     * Obtains a map of beans of the given type and qualifier.
     *
     * @param beanType          The bean type
     * @param qualifier         The qualifier
     * @param                The bean type
     * @return A map of beans, never {@code null}.
     * @since 4.0.0
     */
    @NonNull
    default  Map mapOfType(@NonNull Argument beanType, @Nullable Qualifier qualifier) {
        return Collections.emptyMap();
    }

    /**
     * Find an optional bean of the given type and qualifier.
     *
     * @param beanType          The bean type
     * @param qualifier         The qualifier
     * @param                The bean type parameter
     * @return The found bean wrapped as an {@link Optional}
     * @since 3.5.0
     */
    @NonNull
     Optional findBean(@NonNull Argument beanType, @Nullable Qualifier qualifier);

    /**
     * Obtains the bean registrations for the given type and qualifier.
     *
     * @param beanType          The bean type
     * @param qualifier         The qualifier
     * @param                The generic type
     * @return A collection of {@link BeanRegistration}
     * @since 3.5.0
     */
    @NonNull
     Collection> getBeanRegistrations(@NonNull Argument beanType, @Nullable Qualifier qualifier);

    /**
     * Call back to destroy any {@link io.micronaut.context.annotation.InjectScope} beans.
     *
     * @see io.micronaut.context.annotation.InjectScope
     * @since 3.1.0
     */
    @UsedByGeneratedCode
    void destroyInjectScopedBeans();

    /**
     * Copy current context to be used later.
     *
     * @return The bean resolution context
     * @since 3.1.0
     */
    BeanResolutionContext copy();

    /**
     * @return The context
     */
    BeanContext getContext();

    /**
     * @return The class requested at the root of this resolution context
     */
    BeanDefinition getRootDefinition();

    /**
     * @return The path that this resolution has taken so far
     */
    Path getPath();

    /**
     * @return The configuration path.
     * @since 4.0.0
     */
    @NonNull
    ConfigurationPath getConfigurationPath();

    /**
     * Store a value within the context.
     *
     * @param key The key
     * @param value The value
     * @return The previous value or null
     */
    Object setAttribute(CharSequence key, Object value);

    /**
     * @param key The key
     * @return The attribute value
     */
    Object getAttribute(CharSequence key);

    /**
     * Remove the attribute for the given key.
     *
     * @param key the key
     * @return The previous value
     */
    Object removeAttribute(CharSequence key);

    /**
     * Get the map representing current attributes.
     *
     * @return All attributes
     * @since 4.0.0
     */
    @Nullable
    Map getAttributes();

    /**
     * Set new attributes map (The map is supposed to be mutable).
     *
     * @param attributes The attributes
     * @since 4.0.0
     */
    void setAttributes(@Nullable Map attributes);

    /**
     * Adds a bean that is created as part of the resolution. This is used to store references to instances passed to {@link BeanContext#inject(Object)}.
     *
     * @param beanIdentifier The bean identifier
     * @param beanRegistration The bean registration
     * @param  The instance type
     */
     void addInFlightBean(BeanIdentifier beanIdentifier, BeanRegistration beanRegistration);

    /**
     * Removes a bean that is in the process of being created. This is used to store references to instances passed to {@link BeanContext#inject(Object)}.
     *
     * @param beanIdentifier The bean identifier
     */
    void removeInFlightBean(BeanIdentifier beanIdentifier);

    /**
     * Obtains an inflight bean for the given identifier. An "In Flight" bean is one that is currently being
     * created but has not finished construction and been registered as a singleton just yet. For example
     * in the case whereby a bean as a {@code PostConstruct} method that also triggers bean resolution of the same bean.
     *
     * @param beanIdentifier The bean identifier
     * @param  The bean type
     * @return The bean
     */
    @Nullable  BeanRegistration getInFlightBean(BeanIdentifier beanIdentifier);

    /**
     * @return The current bean identifier
     */
    @Nullable Qualifier getCurrentQualifier();

    /**
     * Sets the current qualifier.
     * @param qualifier The qualifier
     */
    void setCurrentQualifier(@Nullable Qualifier qualifier);

    /**
     * Adds a dependent bean to the resolution context.
     *
     * @param beanRegistration The bean registration
     * @param  The generic type
     */
     void addDependentBean(BeanRegistration beanRegistration);

    /**
     * @return The dependent beans that must be destroyed by an upstream bean
     */
    default @NonNull List> getAndResetDependentBeans() {
        return Collections.emptyList();
    }

    /**
     * @return The current dependent beans that must be destroyed by an upstream bean
     *
     * @since 3.5.0
     */
    default @Nullable List> popDependentBeans() {
        return null;
    }

    /**
     * The push the current dependent beans that must be destroyed by an upstream bean.
     *
     * @param dependentBeans Dependent beans collection that can be used to add more dependents
     * @since 3.5.0
     */
    default void pushDependentBeans(@Nullable List> dependentBeans) {
    }

    /**
     * Marks first dependent as factory.
     * Dependent can be missing which means it's a singleton or scoped bean.
     *
     * @since 3.5.0
     */
    @UsedByGeneratedCode
    default void markDependentAsFactory() {
    }

    /**
     * @return The dependent factory beans that was used to create the bean in context
     * @since 3.5.0
     */
    default @Nullable BeanRegistration getAndResetDependentFactoryBean() {
        return null;
    }

    /**
     * Sets the configuration path.
     * @param configurationPath The configuration path.
     * @return The previous path
     */
    @Nullable
    ConfigurationPath setConfigurationPath(@Nullable ConfigurationPath configurationPath);

    /**
     * Represents a path taken to resolve a bean definitions dependencies.
     */
    interface Path extends Deque>, AutoCloseable {
        /**
         * Push an unresolved constructor call onto the queue.
         *
         * @param declaringType The type
         * @param beanType      The bean type
         * @return This path
         */
        Path pushBeanCreate(BeanDefinition declaringType, Argument beanType);

        /**
         * Push an unresolved constructor call onto the queue.
         *
         * @param declaringType        The type
         * @param methodName           The method name
         * @param argument             The unresolved argument
         * @param arguments            The arguments
         * @return This path
         */
        Path pushConstructorResolve(BeanDefinition declaringType, String methodName, Argument argument, Argument[] arguments);

        /**
         * Push an unresolved constructor call onto the queue.
         *
         * @param declaringType The type
         * @param argument      The unresolved argument
         * @return This path
         */
        Path pushConstructorResolve(BeanDefinition declaringType, Argument argument);

        /**
         * Push an unresolved method call onto the queue.
         *
         * @param declaringType        The type
         * @param methodInjectionPoint The method injection point
         * @param argument             The unresolved argument
         * @return This path
         */
        Path pushMethodArgumentResolve(BeanDefinition declaringType, MethodInjectionPoint methodInjectionPoint, Argument argument);

        /**
         * Push an unresolved method call onto the queue.
         *
         * @param declaringType        The type
         * @param methodName           The method name
         * @param argument             The unresolved argument
         * @param arguments            The arguments
         * @return This path
         */
        Path pushMethodArgumentResolve(BeanDefinition declaringType, String methodName, Argument argument, Argument[] arguments);

        /**
         * Push an unresolved field onto the queue.
         *
         * @param declaringType       declaring type
         * @param fieldInjectionPoint The field injection point
         * @return This path
         */
        Path pushFieldResolve(BeanDefinition declaringType, FieldInjectionPoint fieldInjectionPoint);

        /**
         * Push an unresolved field onto the queue.
         *
         * @param declaringType       declaring type
         * @param fieldAsArgument     The field as argument
         * @return This path
         */
        Path pushFieldResolve(BeanDefinition declaringType, Argument fieldAsArgument);

        Path pushAnnotationResolve(BeanDefinition beanDefinition, Argument annotationMemberBeanAsArgument);

        /**
         * Converts the path to a circular string.
         *
         * @return The circular string
         */
        String toCircularString();

        /**
         * @return The current path segment
         */
        Optional> currentSegment();

        @Override
        default void close() {
            pop();
        }
    }

    /**
     * A segment in a path.
     *
     * @param  the declaring type
     * @param  the injected type
     */
    interface Segment {

        /**
         * @return The type requested
         */
        BeanDefinition getDeclaringType();

        /**
         * @return The inject point
         */
        InjectionPoint getInjectionPoint();

        /**
         * @return The name of the segment. For a field this is the field name, for a method the method name and for a constructor the type name
         */
        String getName();

        /**
         * @return The argument to create the type. For a field this will be empty
         */
        Argument getArgument();
    }
}