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

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

/*
 * Copyright 2017-2019 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
 *
 * http://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.EachProperty;
import io.micronaut.context.annotation.Primary;
import io.micronaut.context.exceptions.BeanInstantiationException;
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.convert.ArgumentConversionContext;
import io.micronaut.core.convert.ConversionService;
import io.micronaut.core.naming.NameResolver;
import io.micronaut.core.naming.Named;
import io.micronaut.core.type.Argument;
import io.micronaut.core.value.ValueResolver;
import io.micronaut.inject.*;
import io.micronaut.inject.qualifiers.Qualifiers;

import java.lang.annotation.Annotation;
import java.util.*;
import java.util.stream.Stream;

/**
 * A delegate bean definition.
 *
 * @param  The bean type
 * @author Graeme Rocher
 * @since 1.0
 */
@Internal
class BeanDefinitionDelegate extends AbstractBeanContextConditional implements DelegatingBeanDefinition, BeanFactory, NameResolver, ValueResolver {

    static final String PRIMARY_ATTRIBUTE = Primary.class.getName();

    protected final BeanDefinition definition;
    protected final Map attributes = new HashMap<>();

    private BeanDefinitionDelegate(BeanDefinition definition) {
        if (!(definition instanceof BeanFactory)) {
            throw new IllegalArgumentException("Delegate can only be used for bean factories");
        }
        this.definition = definition;
    }

    @Override
    public boolean isAbstract() {
        return definition.isAbstract();
    }

    @Override
    public boolean isProxy() {
        return definition.isProxy();
    }

    /**
     * @return The bean definition type
     */
    BeanDefinition getDelegate() {
        return definition;
    }

    @Override
    public Optional> getScope() {
        return definition.getScope();
    }

    @Override
    public boolean isSingleton() {
        return definition.isSingleton();
    }

    @Override
    public boolean isProvided() {
        return definition.isProvided();
    }

    @Override
    public boolean isIterable() {
        return get(EachProperty.class.getName(), Class.class) != null || definition.isIterable();
    }

    @Override
    public boolean isPrimary() {
        return definition.isPrimary() || get(PRIMARY_ATTRIBUTE, Boolean.class).orElse(false);
    }

    @Override
    public Class getBeanType() {
        return definition.getBeanType();
    }

    @Override
    public Optional> getDeclaringType() {
        return definition.getDeclaringType();
    }

    @Override
    public ConstructorInjectionPoint getConstructor() {
        return definition.getConstructor();
    }

    @Override
    public Collection getRequiredComponents() {
        return definition.getRequiredComponents();
    }

    @Override
    public Collection getInjectedMethods() {
        return definition.getInjectedMethods();
    }

    @Override
    public Collection getInjectedFields() {
        return definition.getInjectedFields();
    }

    @Override
    public Collection getPostConstructMethods() {
        return definition.getPostConstructMethods();
    }

    @Override
    public Collection getPreDestroyMethods() {
        return definition.getPreDestroyMethods();
    }

    @Override
    public String getName() {
        return definition.getName();
    }

    @Override
    public  Optional> findMethod(String name, Class[] argumentTypes) {
        return definition.findMethod(name, argumentTypes);
    }

    @Override
    public  Stream> findPossibleMethods(String name) {
        return definition.findPossibleMethods(name);
    }

    @Override
    public T inject(BeanContext context, T bean) {
        return definition.inject(context, bean);
    }

    @Override
    public T inject(BeanResolutionContext resolutionContext, BeanContext context, T bean) {
        return definition.inject(resolutionContext, context, bean);
    }

    @Override
    public Collection> getExecutableMethods() {
        return definition.getExecutableMethods();
    }

    @Override
    public T build(BeanResolutionContext resolutionContext, BeanContext context, BeanDefinition definition) throws BeanInstantiationException {
        resolutionContext.putAll(attributes);
        try {
            if (this.definition instanceof ParametrizedBeanFactory) {
                ParametrizedBeanFactory parametrizedBeanFactory = (ParametrizedBeanFactory) this.definition;
                Argument[] requiredArguments = parametrizedBeanFactory.getRequiredArguments();
                Object named = attributes.get(Named.class.getName());
                if (named != null) {
                    Map fulfilled = new LinkedHashMap<>();
                    for (Argument argument : requiredArguments) {
                        Class argumentType = argument.getType();
                        Optional result = ConversionService.SHARED.convert(named, argumentType);
                        String argumentName = argument.getName();
                        if (result.isPresent()) {
                            fulfilled.put(argumentName, result.get());
                        } else {
                            // attempt bean lookup to full argument
                            Optional bean = context.findBean(argumentType, Qualifiers.byName(named.toString()));
                            if (bean.isPresent()) {
                                fulfilled.put(argumentName, bean.get());
                            }
                        }
                    }
                    return parametrizedBeanFactory.build(resolutionContext, context, definition, fulfilled);
                }
            }
            return ((BeanFactory) this.definition).build(resolutionContext, context, definition);
        } finally {
            for (String key : attributes.keySet()) {
                resolutionContext.remove(key);
            }
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        BeanDefinitionDelegate that = (BeanDefinitionDelegate) o;
        return Objects.equals(definition, that.definition) &&
            Objects.equals(resolveName().orElse(null), that.resolveName().orElse(null));
    }

    @Override
    public int hashCode() {
        return Objects.hash(definition, resolveName().orElse(null));
    }

    /**
     * @return The bean definition type
     */
    public BeanDefinition getTarget() {
        return definition;
    }

    @Override
    public Optional resolveName() {
        return get(Named.class.getName(), String.class);
    }

    /**
     * Adds a new attribute.
     *
     * @param name  The name
     * @param value The value
     */
    public void put(String name, Object value) {
        this.attributes.put(name, value);
    }

    @Override
    public  Optional get(String name, ArgumentConversionContext conversionContext) {
        Object value = attributes.get(name);
        if (value != null && conversionContext.getArgument().getType().isInstance(value)) {
            return Optional.of((T) value);
        }
        return Optional.empty();
    }

    @Override
    public String toString() {
        return definition.toString();
    }

    /**
     * @param definition The bean definition type
     * @param         The type
     * @return The new bean definition
     */
    static  BeanDefinitionDelegate create(BeanDefinition definition) {
        if (definition instanceof InitializingBeanDefinition || definition instanceof DisposableBeanDefinition) {
            if (definition instanceof ValidatedBeanDefinition) {
                return new LifeCycleValidatingDelegate<>(definition);
            } else {
                return new LifeCycleDelegate<>(definition);
            }
        } else if (definition instanceof ValidatedBeanDefinition) {
            return new ValidatingDelegate<>(definition);
        }
        return new BeanDefinitionDelegate<>(definition);
    }

    /**
     * @param  The bean definition type
     */
    interface ProxyInitializingBeanDefinition extends DelegatingBeanDefinition, InitializingBeanDefinition {
        @Override
        default T initialize(BeanResolutionContext resolutionContext, BeanContext context, T bean) {
            BeanDefinition definition = getTarget();
            if (definition instanceof InitializingBeanDefinition) {
                return ((InitializingBeanDefinition) definition).initialize(resolutionContext, context, bean);
            }
            return bean;
        }
    }

    /**
     * @param  The bean definition type
     */
    interface ProxyDisposableBeanDefinition extends DelegatingBeanDefinition, DisposableBeanDefinition {
        @Override
        default T dispose(BeanResolutionContext resolutionContext, BeanContext context, T bean) {
            BeanDefinition definition = getTarget();
            if (definition instanceof DisposableBeanDefinition) {
                return ((DisposableBeanDefinition) definition).dispose(resolutionContext, context, bean);
            }
            return bean;
        }
    }

    /**
     * @param  The bean definition type
     */
    interface ProxyValidatingBeanDefinition extends DelegatingBeanDefinition, ValidatedBeanDefinition {
        @Override
        default T validate(BeanResolutionContext resolutionContext, T instance) {
            BeanDefinition definition = getTarget();
            if (definition instanceof ValidatedBeanDefinition) {
                return ((ValidatedBeanDefinition) definition).validate(resolutionContext, instance);
            }
            return instance;
        }
    }

    /**
     * @param  The bean definition type
     */
    private static final class LifeCycleDelegate extends BeanDefinitionDelegate implements ProxyInitializingBeanDefinition, ProxyDisposableBeanDefinition {
        private LifeCycleDelegate(BeanDefinition definition) {
            super(definition);
        }
    }

    /**
     * @param  The bean definition type
     */
    private static final class ValidatingDelegate extends BeanDefinitionDelegate implements ProxyValidatingBeanDefinition {
        private ValidatingDelegate(BeanDefinition definition) {
            super(definition);
        }
    }

    /**
     * @param  The bean definition type
     */
    private static final class LifeCycleValidatingDelegate extends BeanDefinitionDelegate implements ProxyValidatingBeanDefinition, ProxyInitializingBeanDefinition, ProxyDisposableBeanDefinition {
        private LifeCycleValidatingDelegate(BeanDefinition definition) {
            super(definition);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy