
io.micronaut.context.BeanDefinitionDelegate 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
*
* 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.ConversionContext;
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 edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import javax.inject.Provider;
import java.util.*;
/**
* 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<>(2);
private BeanDefinitionDelegate(BeanDefinition definition) {
this.definition = definition;
}
@Nullable
@Override
public Qualifier resolveDynamicQualifier() {
Qualifier qualifier = null;
String name = get(NAMED_ATTRIBUTE, ConversionContext.STRING).orElse(null);
if (name != null) {
qualifier = Qualifiers.byName(name);
}
return qualifier;
}
/**
* @return The bean definition type
*/
BeanDefinition getDelegate() {
return definition;
}
@Override
public boolean isProxy() {
return definition.isProxy();
}
@Override
public boolean isIterable() {
return classValue(EachProperty.class.getName()).isPresent() || definition.isIterable();
}
@Override
public boolean isPrimary() {
return definition.isPrimary() || get(PRIMARY_ATTRIBUTE, Boolean.class).orElse(false);
}
@Override
public T build(BeanResolutionContext resolutionContext, BeanContext context, BeanDefinition definition) throws BeanInstantiationException {
LinkedHashMap oldAttributes = null;
if (!attributes.isEmpty()) {
LinkedHashMap oldAttrs = new LinkedHashMap<>(attributes.size());
attributes.forEach((key, value) -> {
Object previous = resolutionContext.setAttribute(key, value);
if (previous != null) {
oldAttrs.put(key, previous);
}
});
oldAttributes = oldAttrs;
}
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<>(requiredArguments.length);
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 {
Qualifier qualifier = Qualifiers.byName(named.toString());
// attempt bean lookup to full argument
if (Provider.class.isAssignableFrom(argumentType)) {
Optional> genericType = argument.getFirstTypeVariable();
if (genericType.isPresent()) {
Class beanType = genericType.get().getType();
fulfilled.put(argumentName, ((DefaultBeanContext) context).getBeanProvider(resolutionContext, beanType, qualifier));
}
} else {
Optional bean = context.findBean(argumentType, qualifier);
if (bean.isPresent()) {
fulfilled.put(argumentName, bean.get());
}
}
}
}
return parametrizedBeanFactory.build(resolutionContext, context, definition, fulfilled);
}
}
if (this.definition instanceof BeanFactory) {
return ((BeanFactory) this.definition).build(resolutionContext, context, definition);
} else {
throw new IllegalStateException("Cannot construct a dynamically registered singleton");
}
} finally {
for (String key : attributes.keySet()) {
resolutionContext.removeAttribute(key);
}
if (oldAttributes != null) {
oldAttributes.forEach(resolutionContext::setAttribute);
}
}
}
@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);
}
@Override
public String getName() {
return definition.getName();
}
/**
* @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;
}
@Override
default void validateBeanArgument(@NonNull BeanResolutionContext resolutionContext, @NonNull InjectionPoint injectionPoint, @NonNull Argument argument, int index, @Nullable V value) {
BeanDefinition definition = getTarget();
if (definition instanceof ValidatedBeanDefinition) {
((ValidatedBeanDefinition) definition).validateBeanArgument(
resolutionContext,
injectionPoint,
argument,
index,
value
);
}
}
}
/**
* @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