Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
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
*
* 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.annotation.Primary;
import io.micronaut.context.env.ConfigurationPath;
import io.micronaut.context.exceptions.BeanInstantiationException;
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.core.naming.NameResolver;
import io.micronaut.core.type.Argument;
import io.micronaut.core.util.ObjectUtils;
import io.micronaut.inject.BeanDefinition;
import io.micronaut.inject.DelegatingBeanDefinition;
import io.micronaut.inject.DisposableBeanDefinition;
import io.micronaut.inject.InitializingBeanDefinition;
import io.micronaut.inject.InjectableBeanDefinition;
import io.micronaut.inject.InjectionPoint;
import io.micronaut.inject.InstantiatableBeanDefinition;
import io.micronaut.inject.ParametrizedInstantiatableBeanDefinition;
import io.micronaut.inject.ValidatedBeanDefinition;
import io.micronaut.inject.qualifiers.PrimaryQualifier;
import io.micronaut.inject.qualifiers.Qualifiers;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
/**
* A delegate bean definition.
*
* @param The bean type
* @author Graeme Rocher
* @since 1.0
*/
@Internal
sealed class BeanDefinitionDelegate extends AbstractBeanContextConditional
implements DelegatingBeanDefinition, InstantiatableBeanDefinition,
InjectableBeanDefinition, NameResolver {
protected final BeanDefinition definition;
@Nullable
protected final Qualifier qualifier;
@Nullable
private final ConfigurationPath configurationPath;
private final Map>> typeArgumentsMap;
private BeanDefinitionDelegate(BeanDefinition definition, @Nullable Qualifier qualifier,
@Nullable ConfigurationPath configurationPath,
@NonNull Map>> typeArgumentsMap) {
this.definition = definition;
this.qualifier = qualifier;
this.configurationPath = configurationPath;
this.typeArgumentsMap = typeArgumentsMap;
}
public Optional getConfigurationPath() {
return Optional.ofNullable(configurationPath);
}
@Override
public List> getTypeArguments(String type) {
List> arguments = typeArgumentsMap.get(type);
return arguments == null ? getTarget().getTypeArguments(type) : arguments;
}
@Override
public Qualifier getDeclaredQualifier() {
return qualifier;
}
/**
* @return the qualifier
*/
@Nullable
public Qualifier getQualifier() {
return qualifier;
}
@Nullable
@Override
public Qualifier resolveDynamicQualifier() {
return qualifier;
}
/**
* @return The bean definition type
*/
BeanDefinition getDelegate() {
return definition;
}
@Override
public boolean isProxy() {
return definition.isProxy();
}
@Override
public boolean isIterable() {
return definition.isIterable();
}
@Override
public boolean isPrimary() {
return isQualifiedAsPrimary(qualifier) || definition.isPrimary() || isPrimaryThroughAttribute();
}
private boolean isQualifiedAsPrimary(Qualifier> q) {
return q != null && (q == PrimaryQualifier.INSTANCE || q.contains(PrimaryQualifier.INSTANCE));
}
private boolean isPrimaryThroughAttribute() {
if (configurationPath != null) {
return configurationPath.isPrimary();
}
return false;
}
@Override
public T inject(BeanContext context, T bean) {
if (definition instanceof InjectableBeanDefinition injectableBeanDefinition) {
return injectableBeanDefinition.inject(context, bean);
}
return bean;
}
@Override
public T inject(BeanResolutionContext resolutionContext, BeanContext context, T bean) {
if (definition instanceof InjectableBeanDefinition injectableBeanDefinition) {
return injectableBeanDefinition.inject(resolutionContext, context, bean);
}
return bean;
}
@Override
public T instantiate(BeanResolutionContext resolutionContext, BeanContext context) throws BeanInstantiationException {
ConfigurationPath oldPath = null;
if (configurationPath != null) {
oldPath = resolutionContext.getConfigurationPath();
resolutionContext.setConfigurationPath(configurationPath);
}
try {
if (this.definition instanceof ParametrizedInstantiatableBeanDefinition parametrizedInstantiatableBeanDefinition) {
Argument[] requiredArguments = parametrizedInstantiatableBeanDefinition.getRequiredArguments();
Map fulfilled = getParametersValues(resolutionContext, (DefaultBeanContext) context, definition, requiredArguments);
return parametrizedInstantiatableBeanDefinition.instantiate(resolutionContext, context, fulfilled);
}
if (this.definition instanceof InstantiatableBeanDefinition instantiatableBeanDefinition) {
return instantiatableBeanDefinition.instantiate(resolutionContext, context);
}
throw new IllegalStateException("Cannot construct a dynamically registered singleton");
} finally {
resolutionContext.setConfigurationPath(oldPath);
}
}
@Nullable
private Map getParametersValues(BeanResolutionContext resolutionContext,
DefaultBeanContext context,
BeanDefinition definition,
Argument[] requiredArguments) {
if (requiredArguments.length == 0) {
return Collections.emptyMap();
}
Map fulfilled = new LinkedHashMap<>(requiredArguments.length, 1);
ConfigurationPath configurationPath = resolutionContext.getConfigurationPath();
for (Argument argument : requiredArguments) {
String argumentName = argument.getName();
if (argument.isAnnotationPresent(Parameter.class)) {
Class> type = argument.getWrapperType();
boolean isEnum = Enum.class.isAssignableFrom(type);
if (CharSequence.class.isAssignableFrom(type) || isEnum) {
String simpleName = configurationPath.simpleName();
if (simpleName != null) {
Object value = isEnum ? context.getConversionService().convertRequired(simpleName, type) : simpleName;
fulfilled.put(argumentName, value);
} else {
String name = findName(resolutionContext.getCurrentQualifier());
if (name != null) {
Object value = isEnum ? context.getConversionService().convertRequired(name, type) : name;
fulfilled.put(argumentName, value);
}
}
} else if (Number.class.isAssignableFrom(type)) {
fulfilled.put(argumentName, context.getConversionService().convertRequired(configurationPath.index(), argument));
} else if (qualifier != null && hasDeclaredAnnotation(EachBean.class) && String.class.equals(type) && "name".equals(argumentName)) {
String name = findName(qualifier);
if (name != null) {
fulfilled.put(argumentName, name);
}
} else {
if (argument.isProvider()) {
Argument> pt = argument.getFirstTypeVariable().orElse(null);
if (pt != null) {
type = pt.getType();
}
}
try (BeanResolutionContext.Path ignored = resolutionContext.getPath().pushConstructorResolve(definition, argument)) {
if (type.equals(configurationPath.configurationType())) {
Object bean = context.findBean(resolutionContext, argument, configurationPath.beanQualifier()).orElse(null);
fulfilled.put(argumentName, bean);
} else {
ConfigurationPath old = resolutionContext.setConfigurationPath(null);// reset
try {
Qualifier q = qualifier != null ? (Qualifier) qualifier : configurationPath.beanQualifier();
Object bean = context.findBean(resolutionContext, argument, q).orElse(null);
fulfilled.put(argumentName, bean);
} finally {
resolutionContext.setConfigurationPath(old);
}
}
}
}
}
}
return fulfilled;
}
@Nullable
private String findName(@Nullable Qualifier> q) {
if (q == null) {
return null;
}
String name = Qualifiers.findName(q);
if (name != null) {
return name;
}
if (isQualifiedAsPrimary(q)) {
return Primary.SIMPLE_NAME;
}
return null;
}
@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(qualifier, that.qualifier);
}
@Override
public int hashCode() {
return ObjectUtils.hash(definition, qualifier);
}
/**
* @return The bean definition type
*/
@Override
public BeanDefinition getTarget() {
return definition;
}
@Override
public Optional resolveName() {
return Optional.ofNullable(findName(qualifier));
}
@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) {
return create(definition, null);
}
/**
* @param definition The bean definition type
* @param qualifier The bean qualifier
* @param The type
* @return The new bean definition
*/
static BeanDefinitionDelegate create(BeanDefinition definition, Qualifier qualifier) {
return create(definition, qualifier, null, Map.of());
}
/**
* @param definition The bean definition type
* @param qualifier The bean qualifier
* @param typeArgumentsMap The type arguments
* @param The type
* @return The new bean definition
* @since 4.6
*/
static BeanDefinitionDelegate create(BeanDefinition definition,
Qualifier qualifier,
@NonNull Map>> typeArgumentsMap) {
return create(definition, qualifier, null, typeArgumentsMap);
}
/**
* @param definition The bean definition type
* @param qualifier The bean qualifier
* @param path The configuration path.
* @param typeArgumentsMap The type arguments
* @param The type
* @return The new bean definition
*/
static BeanDefinitionDelegate create(BeanDefinition definition,
Qualifier qualifier,
ConfigurationPath path,
@NonNull Map>> typeArgumentsMap) {
if (definition instanceof InitializingBeanDefinition || definition instanceof DisposableBeanDefinition) {
if (definition instanceof ValidatedBeanDefinition) {
return new LifeCycleValidatingDelegate<>(definition, qualifier, path, typeArgumentsMap);
} else {
return new LifeCycleDelegate<>(definition, qualifier, path, typeArgumentsMap);
}
} else if (definition instanceof ValidatedBeanDefinition) {
return new ValidatingDelegate<>(definition, qualifier, path, typeArgumentsMap);
}
return new BeanDefinitionDelegate<>(definition, qualifier, path, typeArgumentsMap);
}
/**
* @param definition The bean definition type
* @param qualifier The bean qualifier
* @param path The configuration path.
* @param The type
* @return The new bean definition
*/
static BeanDefinitionDelegate create(BeanDefinition definition,
Qualifier qualifier,
ConfigurationPath path) {
return create(definition, qualifier, path, Map.of());
}
@Override
@NonNull
public String getName() {
return definition.getName();
}
/**
* @param The bean definition type
*/
sealed 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
*/
sealed 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
*/
sealed 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, Qualifier qualifier, ConfigurationPath path, @NonNull Map>> typeArgumentsMap) {
super(definition, qualifier, path, typeArgumentsMap);
}
}
/**
* @param The bean definition type
*/
private static final class ValidatingDelegate extends BeanDefinitionDelegate implements ProxyValidatingBeanDefinition {
private ValidatingDelegate(BeanDefinition definition, Qualifier qualifier, ConfigurationPath path, @NonNull Map>> typeArgumentsMap) {
super(definition, qualifier, path, typeArgumentsMap);
}
}
/**
* @param The bean definition type
*/
private static final class LifeCycleValidatingDelegate extends BeanDefinitionDelegate implements ProxyValidatingBeanDefinition, ProxyInitializingBeanDefinition, ProxyDisposableBeanDefinition {
private LifeCycleValidatingDelegate(BeanDefinition definition, Qualifier qualifier, ConfigurationPath path, @NonNull Map>> typeArgumentsMap) {
super(definition, qualifier, path, typeArgumentsMap);
}
}
}