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

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

There is a newer version: 4.7.5
Show newest version
/*
 * 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.annotation.EachBean;
import io.micronaut.context.annotation.Parameter;
import io.micronaut.context.exceptions.BeanInstantiationException;
import io.micronaut.context.exceptions.DisabledBeanException;
import io.micronaut.core.annotation.AnnotationMetadata;
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.convert.ConversionContext;
import io.micronaut.core.convert.ConversionService;
import io.micronaut.core.type.Argument;
import io.micronaut.inject.BeanDefinition;
import io.micronaut.inject.ParametrizedBeanFactory;

import javax.inject.Qualifier;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;

/**
 * A {@link BeanDefinition} that is a {@link ParametrizedBeanFactory}.
 *
 * @param  The Bean definition type
 * @author Graeme Rocher
 * @since 1.0
 */
@Internal
public abstract class AbstractParametrizedBeanDefinition extends AbstractBeanDefinition implements ParametrizedBeanFactory {

    private final Argument[] requiredArguments;

    /**
     * @param producedType       The produced type
     * @param declaringType      The declaring type
     * @param methodName         The method name
     * @param methodMetadata     The method metadata
     * @param requiresReflection Whether requires refection
     * @param arguments          The arguments
     */
    public AbstractParametrizedBeanDefinition(Class producedType, Class declaringType, String methodName, AnnotationMetadata methodMetadata, boolean requiresReflection, Argument... arguments) {
        super(producedType, declaringType, methodName, methodMetadata, requiresReflection, arguments);
        this.requiredArguments = resolveRequiredArguments();
    }

    /**
     * @param type               The type
     * @param annotationMetadata The annotation metadata
     * @param requiresReflection Whether requires reflection
     * @param arguments          The arguments
     */
    protected AbstractParametrizedBeanDefinition(Class type,
                                                 AnnotationMetadata annotationMetadata,
                                                 boolean requiresReflection,
                                                 Argument... arguments) {
        super(type, annotationMetadata, requiresReflection, arguments);
        this.requiredArguments = resolveRequiredArguments();
    }

    @Override
    public Argument[] getRequiredArguments() {
        return requiredArguments;
    }

    @Override
    public final T build(BeanResolutionContext resolutionContext,
                         BeanContext context,
                         BeanDefinition definition,
                         Map requiredArgumentValues) throws BeanInstantiationException {

        requiredArgumentValues = requiredArgumentValues != null ? new LinkedHashMap<>(requiredArgumentValues) : Collections.emptyMap();
        Argument[] requiredArguments = getRequiredArguments();
        Optional eachBeanType = definition.classValue(EachBean.class);
        for (Argument requiredArgument : requiredArguments) {
            if (requiredArgument.getType() == BeanResolutionContext.class) {
                requiredArgumentValues.put(requiredArgument.getName(), resolutionContext);
            }

            BeanResolutionContext.Path path = resolutionContext.getPath();
            try {
                path.pushConstructorResolve(this, requiredArgument);
                String argumentName = requiredArgument.getName();
                if (!requiredArgumentValues.containsKey(argumentName) && !requiredArgument.isNullable()) {
                    if (eachBeanType.filter(type -> type == requiredArgument.getType()).isPresent()) {
                        throw new DisabledBeanException("@EachBean parameter disabled for argument: " + requiredArgument.getName());
                    }
                    throw new BeanInstantiationException(resolutionContext, "Missing bean argument value: " + argumentName);
                }
                Object value = requiredArgumentValues.get(argumentName);
                boolean requiresConversion = value != null && !requiredArgument.getType().isInstance(value);
                if (requiresConversion) {
                    Optional converted = ConversionService.SHARED.convert(value, requiredArgument.getType(), ConversionContext.of(requiredArgument));
                    Object finalValue = value;
                    value = converted.orElseThrow(() -> new BeanInstantiationException(resolutionContext, "Invalid value [" + finalValue + "] for argument: " + argumentName));
                    requiredArgumentValues.put(argumentName, value);
                }
            } finally {
                path.pop();
            }
        }
        return doBuild(resolutionContext, context, definition, requiredArgumentValues);
    }

    /**
     * @param resolutionContext      The resolution context
     * @param context                The bean context
     * @param definition             The bean definition
     * @param requiredArgumentValues The required arguments
     * @return The built instance
     */
    protected abstract T doBuild(BeanResolutionContext resolutionContext, BeanContext context, BeanDefinition definition, Map requiredArgumentValues);

    private Argument[] resolveRequiredArguments() {
        return Arrays.stream(getConstructor().getArguments())
            .filter(arg -> {
                Optional> qualifierType = arg.getAnnotationMetadata().getAnnotationTypeByStereotype(Qualifier.class);
                return qualifierType.isPresent() && qualifierType.get() == Parameter.class;
            })
            .toArray(Argument[]::new);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy