
io.micronaut.context.AbstractBeanResolutionContext 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.Factory;
import io.micronaut.context.env.CachedEnvironment;
import io.micronaut.context.annotation.InjectScope;
import io.micronaut.context.env.ConfigurationPath;
import io.micronaut.context.exceptions.CircularDependencyException;
import io.micronaut.context.scope.CustomScope;
import io.micronaut.core.annotation.AnnotationMetadata;
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.core.convert.ArgumentConversionContext;
import io.micronaut.core.naming.Named;
import io.micronaut.core.type.Argument;
import io.micronaut.core.type.ArgumentCoercible;
import io.micronaut.core.util.ObjectUtils;
import io.micronaut.inject.*;
import java.util.*;
import java.util.stream.Stream;
/**
* Default implementation of the {@link BeanResolutionContext} interface.
*
* @author Graeme Rocher
* @since 1.2.3
*/
@Internal
public abstract class AbstractBeanResolutionContext implements BeanResolutionContext {
private static final String CONSTRUCTOR_METHOD_NAME = "";
protected final DefaultBeanContext context;
protected final BeanDefinition> rootDefinition;
protected final Path path;
private Map attributes;
private Qualifier> qualifier;
private List> dependentBeans;
private BeanRegistration> dependentFactory;
private ConfigurationPath configurationPath;
/**
* @param context The bean context
* @param rootDefinition The bean root definition
*/
@Internal
protected AbstractBeanResolutionContext(DefaultBeanContext context, BeanDefinition> rootDefinition) {
this.context = context;
this.rootDefinition = rootDefinition;
this.path = new DefaultPath();
}
@Override
public ConfigurationPath getConfigurationPath() {
if (configurationPath != null) {
return configurationPath;
} else {
this.configurationPath = ConfigurationPath.newPath();
return configurationPath;
}
}
@Override
public ConfigurationPath setConfigurationPath(ConfigurationPath configurationPath) {
ConfigurationPath old = this.configurationPath;
this.configurationPath = configurationPath;
return old;
}
@NonNull
@Override
public T getBean(@NonNull Argument beanType, @Nullable Qualifier qualifier) {
return context.getBean(this, beanType, qualifier);
}
@NonNull
@Override
public Collection getBeansOfType(@NonNull Argument beanType, @Nullable Qualifier qualifier) {
return context.getBeansOfType(this, beanType, qualifier);
}
@NonNull
@Override
public Stream streamOfType(@NonNull Argument beanType, @Nullable Qualifier qualifier) {
return context.streamOfType(this, beanType, qualifier);
}
@Override
public Map mapOfType(Argument beanType, Qualifier qualifier) {
return context.mapOfType(this, beanType, qualifier);
}
@NonNull
@Override
public Optional findBean(@NonNull Argument beanType, @Nullable Qualifier qualifier) {
return context.findBean(this, beanType, qualifier);
}
@NonNull
@Override
public Collection> getBeanRegistrations(@NonNull Argument beanType, @Nullable Qualifier qualifier) {
return context.getBeanRegistrations(this, beanType, qualifier);
}
/**
* Copy the state from a previous resolution context.
*
* @param context The previous context
*/
public void copyStateFrom(@NonNull AbstractBeanResolutionContext context) {
path.addAll(context.path);
qualifier = context.qualifier;
if (context.attributes != null) {
getAttributesOrCreate().putAll(context.attributes);
}
}
@Override
public void addDependentBean(BeanRegistration beanRegistration) {
if (beanRegistration.getBeanDefinition() == rootDefinition) {
// Don't add self
return;
}
if (dependentBeans == null) {
dependentBeans = new ArrayList<>(3);
}
dependentBeans.add(beanRegistration);
}
@Override
public void destroyInjectScopedBeans() {
final CustomScope> injectScope = context.getCustomScopeRegistry()
.findScope(InjectScope.class.getName())
.orElse(null);
if (injectScope instanceof LifeCycle> cycle) {
cycle.stop();
}
}
@NonNull
@Override
public List> getAndResetDependentBeans() {
if (dependentBeans == null) {
return Collections.emptyList();
}
final List> registrations = Collections.unmodifiableList(dependentBeans);
dependentBeans = null;
return registrations;
}
@Override
public void markDependentAsFactory() {
if (dependentBeans != null) {
if (dependentBeans.isEmpty()) {
return;
}
if (dependentBeans.size() != 1) {
throw new IllegalStateException("Expected only one bean dependent!");
}
dependentFactory = dependentBeans.remove(0);
}
}
@Override
public BeanRegistration> getAndResetDependentFactoryBean() {
BeanRegistration> result = this.dependentFactory;
this.dependentFactory = null;
return result;
}
@Override
public List> popDependentBeans() {
List> result = this.dependentBeans;
this.dependentBeans = null;
return result;
}
@Override
public void pushDependentBeans(List> dependentBeans) {
if (this.dependentBeans != null && !this.dependentBeans.isEmpty()) {
throw new IllegalStateException("Found existing dependent beans!");
}
this.dependentBeans = dependentBeans;
}
@Override
public final BeanContext getContext() {
return context;
}
@Override
public final BeanDefinition getRootDefinition() {
return rootDefinition;
}
@Override
public final Path getPath() {
return path;
}
@Override
public final Object setAttribute(CharSequence key, Object value) {
return getAttributesOrCreate().put(key, value);
}
/**
* @param key The key
* @return The attribute value
*/
@Override
public final Object getAttribute(CharSequence key) {
if (attributes == null) {
return null;
}
return attributes.get(key);
}
@Override
public final Object removeAttribute(CharSequence key) {
if (attributes != null && key != null) {
return attributes.remove(key);
}
return null;
}
@Override
public Map getAttributes() {
return attributes;
}
@Override
public void setAttributes(Map attributes) {
this.attributes = attributes;
}
@Nullable
@Override
public Qualifier> getCurrentQualifier() {
return qualifier;
}
@Override
public void setCurrentQualifier(@Nullable Qualifier> qualifier) {
this.qualifier = qualifier;
}
@Override
public Optional get(CharSequence name, ArgumentConversionContext conversionContext) {
if (attributes == null) {
return Optional.empty();
}
Object value = attributes.get(name);
if (value != null && conversionContext.getArgument().getType().isInstance(value)) {
return Optional.of((T) value);
}
return Optional.empty();
}
@Override
public Optional get(CharSequence name, Class requiredType) {
if (attributes == null) {
return Optional.empty();
}
Object value = attributes.get(name);
if (requiredType.isInstance(value)) {
return Optional.of((T) value);
}
return Optional.empty();
}
protected void onNewSegment(Segment, ?> segment) {
//no-op
}
@NonNull
private Map getAttributesOrCreate() {
if (attributes == null) {
attributes = new LinkedHashMap<>(2);
}
return attributes;
}
/**
* Class that represents a default path.
*/
class DefaultPath extends LinkedList> implements Path {
public static final String RIGHT_ARROW = " --> ";
private static final String CIRCULAR_ERROR_MSG = "Circular dependency detected";
DefaultPath() {
}
@Override
public String toString() {
Iterator> i = descendingIterator();
StringBuilder pathString = new StringBuilder();
while (i.hasNext()) {
pathString.append(i.next().toString());
if (i.hasNext()) {
pathString.append(RIGHT_ARROW);
}
}
return pathString.toString();
}
@SuppressWarnings("MagicNumber")
@Override
public String toCircularString() {
Iterator> i = descendingIterator();
StringBuilder pathString = new StringBuilder();
String ls = CachedEnvironment.getProperty("line.separator");
while (i.hasNext()) {
String segmentString = i.next().toString();
pathString.append(segmentString);
if (i.hasNext()) {
pathString.append(RIGHT_ARROW);
} else {
int totalLength = pathString.length() - 3;
String spaces = String.join("", Collections.nCopies(totalLength, " "));
pathString.append(ls)
.append("^")
.append(spaces)
.append("|")
.append(ls)
.append("|")
.append(spaces)
.append("|").append(ls)
.append("|")
.append(spaces)
.append("|").append(ls).append('+');
pathString.append(String.join("", Collections.nCopies(totalLength, "-"))).append('+');
}
}
return pathString.toString();
}
@Override
public Optional> currentSegment() {
return Optional.ofNullable(peek());
}
@Override
public Path pushConstructorResolve(BeanDefinition declaringType, Argument argument) {
ConstructorInjectionPoint> constructor = declaringType.getConstructor();
if (constructor instanceof MethodInjectionPoint, ?> methodInjectionPoint) {
return pushConstructorResolve(declaringType, methodInjectionPoint.getName(), argument, constructor.getArguments());
}
return pushConstructorResolve(declaringType, CONSTRUCTOR_METHOD_NAME, argument, constructor.getArguments());
}
@Override
public Path pushConstructorResolve(BeanDefinition declaringType, String methodName, Argument argument, Argument[] arguments) {
if (CONSTRUCTOR_METHOD_NAME.equals(methodName)) {
ConstructorSegment constructorSegment = new ConstructorArgumentSegment(declaringType, (Qualifier
© 2015 - 2025 Weber Informatics LLC | Privacy Policy