use of io.micronaut.inject.ast.MethodElement in project micronaut-core by micronaut-projects.
the class BeanDefinitionWriter method visitBeanDefinitionEnd.
/**
* Finalize the bean definition to the given output stream.
*/
@SuppressWarnings("Duplicates")
@Override
public void visitBeanDefinitionEnd() {
if (classWriter == null) {
throw new IllegalStateException("At least one called to visitBeanDefinitionConstructor(..) is required");
}
processAllBeanElementVisitors();
if (constructor instanceof MethodElement) {
MethodElement methodElement = (MethodElement) constructor;
boolean isParametrized = Arrays.stream(methodElement.getParameters()).map(AnnotationMetadataProvider::getAnnotationMetadata).anyMatch(this::isAnnotatedWithParameter);
if (isParametrized) {
interfaceTypes.add(ParametrizedBeanFactory.class);
}
}
String[] interfaceInternalNames = new String[interfaceTypes.size()];
Iterator<Class> j = interfaceTypes.iterator();
for (int i = 0; i < interfaceInternalNames.length; i++) {
interfaceInternalNames[i] = Type.getInternalName(j.next());
}
final String beanDefSignature = generateBeanDefSig(beanType);
classWriter.visit(V1_8, ACC_SYNTHETIC, beanDefinitionInternalName, beanDefSignature, isSuperFactory ? TYPE_ABSTRACT_BEAN_DEFINITION.getInternalName() : superType.getInternalName(), interfaceInternalNames);
classWriter.visitAnnotation(TYPE_GENERATED.getDescriptor(), false);
if (buildMethodVisitor == null) {
throw new IllegalStateException("At least one call to visitBeanDefinitionConstructor() is required");
}
GeneratorAdapter staticInit = visitStaticInitializer(classWriter);
classWriter.visitField(ACC_PRIVATE | ACC_FINAL | ACC_STATIC, FIELD_CONSTRUCTOR, Type.getType(AbstractInitializableBeanDefinition.MethodOrFieldReference.class).getDescriptor(), null, null);
int methodsLength = allMethodVisits.size();
if (!superBeanDefinition && methodsLength > 0) {
Type methodsFieldType = Type.getType(AbstractInitializableBeanDefinition.MethodReference[].class);
classWriter.visitField(ACC_PRIVATE | ACC_FINAL | ACC_STATIC, FIELD_INJECTION_METHODS, methodsFieldType.getDescriptor(), null, null);
pushNewArray(staticInit, AbstractInitializableBeanDefinition.MethodReference.class, methodsLength);
int i = 0;
for (MethodVisitData methodVisitData : allMethodVisits) {
pushStoreInArray(staticInit, i++, methodsLength, () -> pushNewMethodReference(staticInit, JavaModelUtils.getTypeReference(methodVisitData.beanType), methodVisitData.methodElement, methodVisitData.requiresReflection, methodVisitData.isPostConstruct(), methodVisitData.isPreDestroy()));
}
staticInit.putStatic(beanDefinitionType, FIELD_INJECTION_METHODS, methodsFieldType);
}
if (!fieldInjectionPoints.isEmpty()) {
Type fieldsFieldType = Type.getType(AbstractInitializableBeanDefinition.FieldReference[].class);
classWriter.visitField(ACC_PRIVATE | ACC_FINAL | ACC_STATIC, FIELD_INJECTION_FIELDS, fieldsFieldType.getDescriptor(), null, null);
int length = fieldInjectionPoints.size();
pushNewArray(staticInit, AbstractInitializableBeanDefinition.FieldReference.class, length);
for (int i = 0; i < length; i++) {
FieldVisitData fieldVisitData = fieldInjectionPoints.get(i);
pushStoreInArray(staticInit, i, length, () -> pushNewFieldReference(staticInit, JavaModelUtils.getTypeReference(fieldVisitData.beanType), fieldVisitData.fieldElement, fieldVisitData.requiresReflection));
}
staticInit.putStatic(beanDefinitionType, FIELD_INJECTION_FIELDS, fieldsFieldType);
}
if (!superBeanDefinition && hasTypeArguments()) {
Type typeArgumentsFieldType = Type.getType(Map.class);
classWriter.visitField(ACC_PRIVATE | ACC_FINAL | ACC_STATIC, FIELD_TYPE_ARGUMENTS, typeArgumentsFieldType.getDescriptor(), null, null);
pushStringMapOf(staticInit, typeArguments, true, null, new Consumer<Map<String, ClassElement>>() {
@Override
public void accept(Map<String, ClassElement> stringClassElementMap) {
pushTypeArgumentElements(beanDefinitionType, classWriter, staticInit, beanDefinitionName, stringClassElementMap, defaultsStorage, loadTypeMethods);
}
});
staticInit.putStatic(beanDefinitionType, FIELD_TYPE_ARGUMENTS, typeArgumentsFieldType);
}
// first build the constructor
visitBeanDefinitionConstructorInternal(staticInit, constructor, constructorRequiresReflection);
addInnerConfigurationMethod(staticInit);
addGetExposedTypes(staticInit);
staticInit.returnValue();
staticInit.visitMaxs(DEFAULT_MAX_STACK, defaultsStorage.size() + 3);
staticInit.visitEnd();
if (buildMethodVisitor != null) {
if (isPrimitiveBean) {
pushBoxPrimitiveIfNecessary(beanType, buildMethodVisitor);
}
buildMethodVisitor.returnValue();
buildMethodVisitor.visitMaxs(DEFAULT_MAX_STACK, 10);
}
if (injectMethodVisitor != null) {
if (injectEnd != null) {
injectMethodVisitor.visitLabel(injectEnd);
}
invokeSuperInjectMethod(injectMethodVisitor, INJECT_BEAN_METHOD);
if (isPrimitiveBean) {
pushBoxPrimitiveIfNecessary(beanType, injectMethodVisitor);
}
injectMethodVisitor.returnValue();
injectMethodVisitor.visitMaxs(DEFAULT_MAX_STACK, 10);
}
if (postConstructMethodVisitor != null) {
postConstructMethodVisitor.loadLocal(postConstructInstanceLocalVarIndex);
postConstructMethodVisitor.returnValue();
postConstructMethodVisitor.visitMaxs(DEFAULT_MAX_STACK, 10);
}
if (preDestroyMethodVisitor != null) {
preDestroyMethodVisitor.loadLocal(preDestroyInstanceLocalVarIndex);
preDestroyMethodVisitor.returnValue();
preDestroyMethodVisitor.visitMaxs(DEFAULT_MAX_STACK, 10);
}
if (interceptedDisposeMethod != null) {
interceptedDisposeMethod.visitMaxs(1, 1);
interceptedDisposeMethod.visitEnd();
}
getInterceptedType().ifPresent(t -> implementInterceptedTypeMethod(t, this.classWriter));
for (GeneratorAdapter method : loadTypeMethods.values()) {
method.visitMaxs(3, 1);
method.visitEnd();
}
classWriter.visitEnd();
this.beanFinalized = true;
}
use of io.micronaut.inject.ast.MethodElement in project micronaut-core by micronaut-projects.
the class BeanDefinitionWriter method isInterceptedLifeCycleByType.
private boolean isInterceptedLifeCycleByType(AnnotationMetadata annotationMetadata, String interceptType) {
return isLifeCycleCache.computeIfAbsent(interceptType, s -> {
if (this.beanTypeElement.isAssignable("io.micronaut.aop.Interceptor")) {
// interceptor beans cannot have lifecycle methods intercepted
return false;
}
final Element originatingElement = getOriginatingElements()[0];
final boolean isFactoryMethod = (originatingElement instanceof MethodElement && !(originatingElement instanceof ConstructorElement));
final boolean isProxyTarget = annotationMetadata.booleanValue(AnnotationUtil.ANN_AROUND, "proxyTarget").orElse(false) || isFactoryMethod;
// for beans that are @Around(proxyTarget=false) only the generated AOP impl should be intercepted
final boolean isAopType = StringUtils.isNotEmpty(interceptedType);
final boolean isConstructorInterceptionCandidate = (isProxyTarget && !isAopType) || (isAopType && !isProxyTarget);
final boolean hasAroundConstruct;
final AnnotationValue<Annotation> interceptorBindings = annotationMetadata.getAnnotation(AnnotationUtil.ANN_INTERCEPTOR_BINDINGS);
List<AnnotationValue<Annotation>> interceptorBindingAnnotations;
if (interceptorBindings != null) {
interceptorBindingAnnotations = interceptorBindings.getAnnotations(AnnotationMetadata.VALUE_MEMBER);
hasAroundConstruct = interceptorBindingAnnotations.stream().anyMatch(av -> av.stringValue("kind").map(k -> k.equals(interceptType)).orElse(false));
} else {
interceptorBindingAnnotations = Collections.emptyList();
hasAroundConstruct = false;
}
if (isConstructorInterceptionCandidate) {
return hasAroundConstruct;
} else if (hasAroundConstruct) {
AnnotationMetadata typeMetadata = annotationMetadata;
if (!isSuperFactory && typeMetadata instanceof AnnotationMetadataHierarchy) {
typeMetadata = ((AnnotationMetadataHierarchy) typeMetadata).getRootMetadata();
final AnnotationValue<Annotation> av = typeMetadata.getAnnotation(AnnotationUtil.ANN_INTERCEPTOR_BINDINGS);
if (av != null) {
interceptorBindingAnnotations = av.getAnnotations(AnnotationMetadata.VALUE_MEMBER);
} else {
interceptorBindingAnnotations = Collections.emptyList();
}
}
// if no other AOP advice is applied
return interceptorBindingAnnotations.stream().noneMatch(av -> av.stringValue("kind").map(k -> k.equals("AROUND")).orElse(false));
} else {
return false;
}
});
}
use of io.micronaut.inject.ast.MethodElement in project micronaut-core by micronaut-projects.
the class AbstractBeanDefinitionBuilder method build.
/**
* Build the bean definition writer.
* @return The writer, possibly null if it wasn't possible to build it
*/
@Nullable
public BeanDefinitionWriter build() {
if (exposedTypes != null) {
final AnnotationClassValue[] annotationClassValues = Arrays.stream(exposedTypes).map(ce -> new AnnotationClassValue<>(ce.getName())).toArray(AnnotationClassValue[]::new);
annotate(Bean.class, (builder) -> builder.member("typed", annotationClassValues));
}
final BeanDefinitionWriter beanDefinitionWriter = createBeanDefinitionWriter();
if (typeArguments != null) {
beanDefinitionWriter.visitTypeArguments(this.typeArguments);
}
if (constructorElement == null) {
constructorElement = initConstructor(beanType);
}
if (constructorElement == null) {
visitorContext.fail("Cannot create associated bean with no accessible primary constructor. Consider supply the constructor with createWith(..)", originatingElement);
return null;
} else {
beanDefinitionWriter.visitBeanDefinitionConstructor(constructorElement, !constructorElement.isPublic(), visitorContext);
}
Map<ClassElement, List<MemberElement>> sortedInjections = new LinkedHashMap<>();
List<MemberElement> allInjected = new ArrayList<>();
allInjected.addAll(injectedFields);
allInjected.addAll(injectedMethods);
allInjected.sort(SORTER);
for (MemberElement memberElement : allInjected) {
final List<MemberElement> list = sortedInjections.computeIfAbsent(memberElement.getDeclaringType(), classElement -> new ArrayList<>());
list.add(memberElement);
}
for (List<MemberElement> members : sortedInjections.values()) {
members.sort((o1, o2) -> {
if (o1 instanceof FieldElement && o2 instanceof MethodElement) {
return 1;
} else if (o1 instanceof MethodElement && o1 instanceof FieldElement) {
return -1;
}
return 0;
});
}
for (List<MemberElement> list : sortedInjections.values()) {
for (MemberElement memberElement : list) {
if (memberElement instanceof FieldElement) {
InternalBeanElementField ibf = (InternalBeanElementField) memberElement;
ibf.<InternalBeanElementField>with((element) -> visitField(beanDefinitionWriter, element, element));
} else {
InternalBeanElementMethod ibm = (InternalBeanElementMethod) memberElement;
ibm.<InternalBeanElementMethod>with((element) -> beanDefinitionWriter.visitMethodInjectionPoint(ibm.getDeclaringType(), ibm, ibm.isRequiresReflection(), visitorContext));
}
}
}
for (BeanMethodElement executableMethod : executableMethods) {
beanDefinitionWriter.visitExecutableMethod(beanType, executableMethod, visitorContext);
}
for (BeanMethodElement postConstructMethod : postConstructMethods) {
if (postConstructMethod.getDeclaringType().equals(beanType)) {
beanDefinitionWriter.visitPostConstructMethod(beanType, postConstructMethod, ((InternalBeanElementMethod) postConstructMethod).isRequiresReflection(), visitorContext);
}
}
for (BeanMethodElement preDestroyMethod : preDestroyMethods) {
if (preDestroyMethod.getDeclaringType().equals(beanType)) {
beanDefinitionWriter.visitPreDestroyMethod(beanType, preDestroyMethod, ((InternalBeanElementMethod) preDestroyMethod).isRequiresReflection(), visitorContext);
}
}
beanDefinitionWriter.visitBeanDefinitionEnd();
return beanDefinitionWriter;
}
Aggregations