BeanDefinitionVisitor.java
/*
* 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.inject.writer;
import io.micronaut.core.annotation.AnnotationMetadata;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.core.util.Toggleable;
import io.micronaut.inject.BeanDefinition;
import io.micronaut.inject.ast.ClassElement;
import io.micronaut.inject.ast.Element;
import io.micronaut.inject.ast.FieldElement;
import io.micronaut.inject.ast.MethodElement;
import io.micronaut.inject.ast.ParameterElement;
import io.micronaut.inject.ast.TypedElement;
import io.micronaut.inject.configuration.ConfigurationMetadataBuilder;
import io.micronaut.inject.visitor.VisitorContext;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.Optional;
/**
* Interface for {@link BeanDefinitionVisitor} implementations such as {@link BeanDefinitionWriter}.
*
* @author Graeme Rocher
* @since 1.0
*/
public interface BeanDefinitionVisitor extends OriginatingElements, Toggleable {
/**
* The suffix use for generated AOP intercepted types.
*/
String PROXY_SUFFIX = "$Intercepted";
/**
* @return The element where the bean definition originated from.
*/
@Nullable
Element getOriginatingElement();
/**
* <p>In the case where the produced class is produced by a factory method annotated with
* {@link io.micronaut.context.annotation.Bean} this method should be called.</p>
*
* @param factoryClass The factory class
* @param factoryMethod The factory method
*/
void visitBeanFactoryMethod(ClassElement factoryClass,
MethodElement factoryMethod);
/**
* <p>In the case where the produced class is produced by a factory method annotated with
* {@link io.micronaut.context.annotation.Bean} this method should be called.</p>
*
* @param factoryClass The factory class
* @param factoryMethod The factory method
* @param parameters The parameters
*/
void visitBeanFactoryMethod(ClassElement factoryClass,
MethodElement factoryMethod,
ParameterElement[] parameters);
/**
* <p>In the case where the produced class is produced by a factory field annotated with
* {@link io.micronaut.context.annotation.Bean} this method should be called.</p>
*
* @param factoryClass The factory class
* @param factoryField The factory field
*/
void visitBeanFactoryField(ClassElement factoryClass, FieldElement factoryField);
/**
* Visits the constructor used to create the bean definition.
*
* @param constructor The method element that represents the constructor
* @param requiresReflection Whether invoking the constructor requires reflection
* @param visitorContext The visitor context
*/
void visitBeanDefinitionConstructor(MethodElement constructor,
boolean requiresReflection,
VisitorContext visitorContext);
/**
* Visits the constructor used to create the bean definition in the case where no constructor is present.
* This method should only be called in the class defines no constructor.
*
* @param annotationMetadata The annotation metadata for the constructor
* @param visitorContext The visitor context
*/
void visitDefaultConstructor(
AnnotationMetadata annotationMetadata,
VisitorContext visitorContext
);
/**
* @return A map of the type arguments for the bean.
*/
@NonNull
Map<String, ClassElement> getTypeArgumentMap();
/**
* @return The name of the bean definition reference class.
*/
@NonNull
String getBeanDefinitionReferenceClassName();
/**
* @return Whether the provided type an interface
*/
boolean isInterface();
/**
* @return Is the bean singleton
*/
boolean isSingleton();
/**
* Visit a marker interface on the generated bean definition.
*
* @param interfaceType The interface type
*/
void visitBeanDefinitionInterface(Class<? extends BeanDefinition> interfaceType);
/**
* Alter the super class of this bean definition. The passed class should be a subclass of
* {@link io.micronaut.context.AbstractInitializableBeanDefinition}.
*
* @param name The super type
*/
void visitSuperBeanDefinition(String name);
/**
* Alter the super class of this bean definition to use another factory bean.
*
* @param beanName The bean name
*/
void visitSuperBeanDefinitionFactory(String beanName);
/**
* @return The full class name of the bean
*/
String getBeanTypeName();
/**
* Make the bean definition as validated by jakarta.validation.
*
* @param validated Whether the bean definition is validated
*/
void setValidated(boolean validated);
/**
* Sets the name of the intercepted type.
*
* @param typeName The type name
*/
void setInterceptedType(String typeName);
/**
* @return The intercepted type
*/
Optional<String> getInterceptedType();
/**
* @return Return whether the bean definition is validated.
*/
boolean isValidated();
/**
* @return The name of the bean definition class
*/
String getBeanDefinitionName();
/**
* Finalize the bean definition to the given output stream.
*/
void visitBeanDefinitionEnd();
/**
* Write the state of the writer to the given compilation directory.
*
* @param compilationDir The compilation directory
* @throws IOException If an I/O error occurs
*/
default void writeTo(File compilationDir) throws IOException {
accept(new DirectoryClassWriterOutputVisitor(compilationDir));
}
/**
* Write the class to output via a visitor that manages output destination.
*
* @param visitor the writer output visitor
* @throws IOException If an error occurs
*/
void accept(ClassWriterOutputVisitor visitor) throws IOException;
/**
* Visits an injection point for a setter.
*
* @param declaringType The declaring type
* @param methodElement The method element
* @param annotationMetadata The annotationMetadata
* @param requiresReflection Whether the setter requires reflection
* @param isOptional Whether the setter is optional
*/
void visitSetterValue(TypedElement declaringType,
MethodElement methodElement,
AnnotationMetadata annotationMetadata,
boolean requiresReflection,
boolean isOptional);
/**
* Visits a method injection point.
* @param declaringType The declaring type of the method. Either a Class or a string representing
* the name of the type
* @param methodElement The method element
* @param requiresReflection Whether the method requires reflection
* @param visitorContext The visitor context
*/
void visitPostConstructMethod(TypedElement declaringType,
MethodElement methodElement,
boolean requiresReflection,
VisitorContext visitorContext);
/**
* Visits a method injection point.
*
* @param beanType The bean type of the method
* @param methodElement The method element
* @param requiresReflection Whether the method requires reflection
* @param visitorContext The visitor context
*/
void visitPreDestroyMethod(TypedElement beanType,
MethodElement methodElement,
boolean requiresReflection,
VisitorContext visitorContext);
/**
* Visits a method injection point.
*
* @param beanType The bean type of the method
* @param methodElement The method element
* @param requiresReflection Whether the method requires reflection
* @param visitorContext The visitor context
*/
void visitMethodInjectionPoint(TypedElement beanType,
MethodElement methodElement,
boolean requiresReflection,
VisitorContext visitorContext);
/**
* Visit a method that is to be made executable allow invocation of said method without reflection.
*
* @param declaringBean The declaring bean of the method. Note this may differ from {@link MethodElement#getDeclaringType()} in the case of the method coming from a super class or interface.
* @param methodElement The method element
* @param visitorContext The visitor context
* @return The index of a new method
*/
int visitExecutableMethod(TypedElement declaringBean,
MethodElement methodElement,
VisitorContext visitorContext);
/**
* Visits a field injection point.
*
* @param declaringType The declaring type. Either a Class or a string representing the name of the type
* @param fieldElement The field element
* @param requiresReflection Whether accessing the field requires reflection
* @param visitorContext The visitor context
*/
void visitFieldInjectionPoint(TypedElement declaringType,
FieldElement fieldElement,
boolean requiresReflection,
VisitorContext visitorContext);
/**
* Visits an annotation injection point.
*
* @param annotationMemberBeanType The type of the injected bean
* @param annotationMemberProperty Required property of the injected bean
* @param requiredValue Required value of the bean property for the bean to be loaded
* @param notEqualsValue The bean property value which should not be equal to present value for the bean to
* be loaded
*/
void visitAnnotationMemberPropertyInjectionPoint(TypedElement annotationMemberBeanType,
String annotationMemberProperty,
@Nullable String requiredValue,
@Nullable String notEqualsValue);
/**
* Visits a field injection point.
*
* @param declaringType The declaring type. Either a Class or a string representing the name of the type
* @param fieldElement The field element
* @param requiresReflection Whether accessing the field requires reflection
* @param isOptional Is the value optional
*/
void visitFieldValue(TypedElement declaringType,
FieldElement fieldElement,
boolean requiresReflection,
boolean isOptional);
/**
* @return The package name of the bean
*/
String getPackageName();
/**
* @return The short name of the bean
*/
String getBeanSimpleName();
/**
* @return The annotation metadata
*/
AnnotationMetadata getAnnotationMetadata();
/**
* Begin defining a configuration builder.
*
* @param type The type of the builder
* @param field The name of the field that represents the builder
* @param annotationMetadata The annotation metadata associated with the field
* @param metadataBuilder The {@link ConfigurationMetadataBuilder}
* @param isInterface Whether the builder type is an interface or not
* @see io.micronaut.context.annotation.ConfigurationBuilder
*/
void visitConfigBuilderField(
ClassElement type,
String field,
AnnotationMetadata annotationMetadata,
ConfigurationMetadataBuilder metadataBuilder,
boolean isInterface);
/**
* Begin defining a configuration builder.
*
* @param type The type of the builder
* @param methodName The name of the method that returns the builder
* @param annotationMetadata The annotation metadata associated with the field
* @param metadataBuilder The {@link ConfigurationMetadataBuilder}
* @param isInterface Whether the builder type is an interface or not
* @see io.micronaut.context.annotation.ConfigurationBuilder
*/
void visitConfigBuilderMethod(
ClassElement type,
String methodName,
AnnotationMetadata annotationMetadata,
ConfigurationMetadataBuilder metadataBuilder,
boolean isInterface);
/**
* Visit a configuration builder method.
*
* @param propertyName The property name
* @param returnType The return type
* @param methodName The method name
* @param paramType The method type
* @param generics The generic types of the method
* @param path The property path
* @see io.micronaut.context.annotation.ConfigurationBuilder
*/
void visitConfigBuilderMethod(String propertyName,
ClassElement returnType,
String methodName,
@Nullable ClassElement paramType,
Map<String, ClassElement> generics,
String path);
/**
* Visit a configuration builder method that accepts a long and a TimeUnit.
*
* @param propertyName The property name
* @param returnType The return type
* @param methodName The method name
* @param path The property path
* @see io.micronaut.context.annotation.ConfigurationBuilder
*/
void visitConfigBuilderDurationMethod(String propertyName,
ClassElement returnType,
String methodName,
String path);
/**
* Finalize a configuration builder field.
*
* @see io.micronaut.context.annotation.ConfigurationBuilder
*/
void visitConfigBuilderEnd();
/**
* By default, when the {@link io.micronaut.context.BeanContext} is started, the
* {@link BeanDefinition#getExecutableMethods()} are not processed by registered
* {@link io.micronaut.context.processor.ExecutableMethodProcessor} instances unless this method returns true.
*
* @return Whether the bean definition requires method processing
* @see io.micronaut.context.annotation.Executable#processOnStartup()
*/
default boolean requiresMethodProcessing() {
return false;
}
/**
* Sets whether the {@link BeanDefinition#requiresMethodProcessing()} returns true.
*
* @param shouldPreProcess True if they should be pre-processed
*/
void setRequiresMethodProcessing(boolean shouldPreProcess);
/**
* Visits the type arguments for the bean.
*
* @param typeArguments The type arguments
*/
void visitTypeArguments(Map<String, Map<String, ClassElement>> typeArguments);
/**
* @return The generic type arguments for the bean type.
* @since 3.0.0
*/
default @NonNull ClassElement[] getTypeArguments() {
return ClassElement.ZERO_CLASS_ELEMENTS;
}
/**
* Returns whether another bean exists that proxies this bean. In other words
* this bean is the target of a proxy.
*
* @return Is the reference a proxy target.
* @since 4.0.0
*/
default boolean isProxiedBean() {
return false;
}
/**
* Returns whether another bean is a proxy target that needs to be retained.
*
* @return Is the reference a proxy target.
* @since 4.0.0
*/
boolean isProxyTarget();
}