package io.micronaut.runtime.context.env;
import io.micronaut.aop.MethodInterceptor;
import io.micronaut.aop.MethodInvocationContext;
import io.micronaut.context.BeanContext;
import io.micronaut.context.BeanRegistration;
import io.micronaut.context.annotation.Property;
import io.micronaut.context.env.Environment;
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.bind.annotation.Bindable;
import io.micronaut.core.type.Argument;
import io.micronaut.core.type.ReturnType;
import io.micronaut.core.value.PropertyNotFoundException;
import javax.inject.Singleton;
import java.util.Optional;
@Singleton
@Internal
public class ConfigurationIntroductionAdvice implements MethodInterceptor<Object, Object> {
private static final String MEMBER_BEAN = "bean";
private static final String MEMBER_NAME = "name";
private final Environment environment;
private final BeanContext beanContext;
ConfigurationIntroductionAdvice(Environment environment, BeanContext beanContext) {
this.environment = environment;
this.beanContext = beanContext;
}
@Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
final ReturnType<Object> rt = context.getReturnType();
final Class<Object> returnType = rt.getType();
if (context.isTrue(ConfigurationAdvice.class, MEMBER_BEAN)) {
if (context.isNullable()) {
final Object v = beanContext.findBean(returnType).orElse(null);
if (v != null) {
return environment.convertRequired(v, returnType);
} else {
return v;
}
} else {
return environment.convertRequired(
beanContext.getBean(returnType),
returnType
);
}
} else {
String property = context.stringValue(Property.class, MEMBER_NAME).orElse(null);
if (property == null) {
throw new IllegalStateException("No property name available to resolve");
}
boolean iterable = property.indexOf('*') > -1;
if (iterable) {
final BeanRegistration<Object> registration = beanContext.findBeanRegistration(context.getTarget()).orElse(null);
if (registration != null) {
final String name = registration.getIdentifier().getName();
property = property.replace("*", name);
}
}
final String defaultValue = context.stringValue(Bindable.class, "defaultValue").orElse(null);
final Argument<Object> argument = rt.asArgument();
final Optional<Object> value = environment.getProperty(
property,
argument
);
if (defaultValue != null) {
return value.orElseGet(() -> environment.convertRequired(
defaultValue,
argument
));
} else if (rt.isOptional()) {
return value.orElse(Optional.empty());
} else if (context.isNullable()) {
return value.orElse(null);
} else {
String finalProperty = property;
return value.orElseThrow(() -> new PropertyNotFoundException(finalProperty, argument.getType()));
}
}
}
}