use of io.micronaut.inject.ast.ConstructorElement in project micronaut-core by micronaut-projects.
the class BeanIntrospectionWriter method invokeBeanConstructor.
private void invokeBeanConstructor(GeneratorAdapter writer, MethodElement constructor, BiConsumer<GeneratorAdapter, MethodElement> argumentsPusher) {
boolean isConstructor = constructor instanceof ConstructorElement;
boolean isCompanion = constructor != defaultConstructor && constructor.getDeclaringType().getSimpleName().endsWith("$Companion");
List<ParameterElement> constructorArguments = Arrays.asList(constructor.getParameters());
Collection<Type> argumentTypes = constructorArguments.stream().map(pe -> JavaModelUtils.getTypeReference(pe.getType())).collect(Collectors.toList());
if (isConstructor) {
writer.newInstance(beanType);
writer.dup();
} else if (isCompanion) {
writer.getStatic(beanType, "Companion", JavaModelUtils.getTypeReference(constructor.getDeclaringType()));
}
argumentsPusher.accept(writer, constructor);
if (isConstructor) {
final String constructorDescriptor = getConstructorDescriptor(constructorArguments);
writer.invokeConstructor(beanType, new Method("<init>", constructorDescriptor));
} else if (constructor.isStatic()) {
final String methodDescriptor = getMethodDescriptor(beanType, argumentTypes);
Method method = new Method(constructor.getName(), methodDescriptor);
if (classElement.isInterface()) {
writer.visitMethodInsn(Opcodes.INVOKESTATIC, beanType.getInternalName(), method.getName(), method.getDescriptor(), true);
} else {
writer.invokeStatic(beanType, method);
}
} else if (isCompanion) {
writer.invokeVirtual(JavaModelUtils.getTypeReference(constructor.getDeclaringType()), new Method(constructor.getName(), getMethodDescriptor(beanType, argumentTypes)));
}
}
use of io.micronaut.inject.ast.ConstructorElement in project micronaut-core by micronaut-projects.
the class AbstractBeanDefinitionBuilder method produceBeans.
@Override
public <E extends MemberElement> BeanElementBuilder produceBeans(ElementQuery<E> methodsOrFields, Consumer<BeanElementBuilder> childBeanBuilder) {
methodsOrFields = methodsOrFields.onlyConcrete().onlyInstance().modifiers((modifiers) -> modifiers.contains(ElementModifier.PUBLIC));
final List<E> enclosedElements = this.beanType.getEnclosedElements(methodsOrFields);
for (E enclosedElement : enclosedElements) {
if (enclosedElement instanceof FieldElement) {
FieldElement fe = (FieldElement) enclosedElement;
final ClassElement type = fe.getGenericField().getType();
if (type.isPublic() && !type.isPrimitive()) {
return addChildBean(fe, childBeanBuilder);
}
}
if (enclosedElement instanceof MethodElement && !(enclosedElement instanceof ConstructorElement)) {
MethodElement me = (MethodElement) enclosedElement;
final ClassElement type = me.getGenericReturnType().getType();
if (type.isPublic() && !type.isPrimitive()) {
return addChildBean(me, childBeanBuilder);
}
}
}
return this;
}
use of io.micronaut.inject.ast.ConstructorElement in project micronaut-core by micronaut-projects.
the class JavaClassElement method getEnclosedElements.
@Override
public <T extends io.micronaut.inject.ast.Element> List<T> getEnclosedElements(@NonNull ElementQuery<T> query) {
Objects.requireNonNull(query, "Query cannot be null");
ElementQuery.Result<T> result = query.result();
ElementKind kind = getElementKind(result.getElementType());
List<T> resultingElements = new ArrayList<>();
List<Element> enclosedElements = new ArrayList<>(getDeclaredEnclosedElements());
boolean onlyDeclared = result.isOnlyDeclared();
boolean onlyAbstract = result.isOnlyAbstract();
boolean onlyConcrete = result.isOnlyConcrete();
boolean onlyInstance = result.isOnlyInstance();
if (!onlyDeclared) {
Elements elements = visitorContext.getElements();
TypeMirror superclass = classElement.getSuperclass();
// traverse the super class true and add elements that are not overridden
while (superclass instanceof DeclaredType) {
DeclaredType dt = (DeclaredType) superclass;
TypeElement element = (TypeElement) dt.asElement();
// reached non-accessible class like Object, Enum, Record etc.
if (element.getQualifiedName().toString().startsWith("java.lang.")) {
break;
}
List<? extends Element> superElements = element.getEnclosedElements();
List<Element> elementsToAdd = new ArrayList<>(superElements.size());
superElements: for (Element superElement : superElements) {
ElementKind superKind = superElement.getKind();
if (superKind == kind) {
for (Element enclosedElement : enclosedElements) {
if (elements.hides(enclosedElement, superElement)) {
continue superElements;
} else if (enclosedElement.getKind() == ElementKind.METHOD && superElement.getKind() == ElementKind.METHOD) {
final ExecutableElement methodCandidate = (ExecutableElement) superElement;
if (elements.overrides((ExecutableElement) enclosedElement, methodCandidate, this.classElement)) {
continue superElements;
}
}
}
// dependency injection method resolution requires extended overrides checks
if (result.isOnlyInjected() && superElement.getKind() == ElementKind.METHOD) {
final ExecutableElement methodCandidate = (ExecutableElement) superElement;
// check for extended override
final String thisClassName = this.classElement.getQualifiedName().toString();
final String declaringClassName = element.getQualifiedName().toString();
boolean isParent = !declaringClassName.equals(thisClassName);
final ModelUtils javaModelUtils = visitorContext.getModelUtils();
final ExecutableElement overridingMethod = javaModelUtils.overridingOrHidingMethod(methodCandidate, this.classElement, false).orElse(methodCandidate);
TypeElement overridingClass = javaModelUtils.classElementFor(overridingMethod);
boolean overridden = isParent && overridingClass != null && !overridingClass.getQualifiedName().toString().equals(declaringClassName);
boolean isPackagePrivate = javaModelUtils.isPackagePrivate(methodCandidate);
boolean isPrivate = methodCandidate.getModifiers().contains(Modifier.PRIVATE);
if (overridden && !(isPrivate || isPackagePrivate)) {
// bail out if the method has been overridden, since it will have already been handled
continue;
}
if (isParent && overridden) {
boolean overriddenInjected = overridden && visitorContext.getAnnotationUtils().getAnnotationMetadata(overridingMethod).hasDeclaredAnnotation(AnnotationUtil.INJECT);
String packageOfOverridingClass = visitorContext.getElements().getPackageOf(overridingMethod).getQualifiedName().toString();
String packageOfDeclaringClass = visitorContext.getElements().getPackageOf(element).getQualifiedName().toString();
boolean isPackagePrivateAndPackagesDiffer = overridden && isPackagePrivate && !packageOfOverridingClass.equals(packageOfDeclaringClass);
if (!overriddenInjected && !isPackagePrivateAndPackagesDiffer && !isPrivate) {
// and is not annotated with @Inject
continue;
}
}
}
if (onlyAbstract && !superElement.getModifiers().contains(Modifier.ABSTRACT)) {
continue;
} else if (onlyConcrete && superElement.getModifiers().contains(Modifier.ABSTRACT)) {
continue;
} else if (onlyInstance && superElement.getModifiers().contains(Modifier.STATIC)) {
continue;
}
elementsToAdd.add(superElement);
}
}
enclosedElements.addAll(elementsToAdd);
superclass = element.getSuperclass();
}
if (kind == ElementKind.METHOD) {
// if the element kind is interfaces then we need to go through interfaces as well
Set<TypeElement> allInterfaces = visitorContext.getModelUtils().getAllInterfaces(this.classElement);
List<Element> elementsToAdd = new ArrayList<>(allInterfaces.size());
for (TypeElement itfe : allInterfaces) {
List<? extends Element> interfaceElements = itfe.getEnclosedElements();
interfaceElements: for (Element interfaceElement : interfaceElements) {
if (interfaceElement.getKind() == ElementKind.METHOD) {
ExecutableElement ee = (ExecutableElement) interfaceElement;
if (onlyAbstract && ee.getModifiers().contains(Modifier.DEFAULT)) {
continue;
} else if (onlyConcrete && !ee.getModifiers().contains(Modifier.DEFAULT)) {
continue;
}
for (Element enclosedElement : enclosedElements) {
if (enclosedElement.getKind() == ElementKind.METHOD) {
if (elements.overrides((ExecutableElement) enclosedElement, ee, this.classElement)) {
continue interfaceElements;
}
}
}
elementsToAdd.add(interfaceElement);
}
}
}
enclosedElements.addAll(elementsToAdd);
elementsToAdd.clear();
}
}
boolean onlyAccessible = result.isOnlyAccessible();
if (kind == ElementKind.METHOD) {
if (onlyAbstract) {
if (isInterface()) {
enclosedElements.removeIf((e) -> e.getModifiers().contains(Modifier.DEFAULT));
} else {
enclosedElements.removeIf((e) -> !e.getModifiers().contains(Modifier.ABSTRACT));
}
} else if (onlyConcrete) {
if (isInterface()) {
enclosedElements.removeIf((e) -> !e.getModifiers().contains(Modifier.DEFAULT));
} else {
enclosedElements.removeIf((e) -> e.getModifiers().contains(Modifier.ABSTRACT));
}
}
}
if (onlyInstance) {
enclosedElements.removeIf((e) -> e.getModifiers().contains(Modifier.STATIC));
}
List<Predicate<Set<ElementModifier>>> modifierPredicates = result.getModifierPredicates();
List<Predicate<String>> namePredicates = result.getNamePredicates();
List<Predicate<AnnotationMetadata>> annotationPredicates = result.getAnnotationPredicates();
final List<Predicate<ClassElement>> typePredicates = result.getTypePredicates();
boolean hasNamePredicates = !namePredicates.isEmpty();
boolean hasModifierPredicates = !modifierPredicates.isEmpty();
boolean hasAnnotationPredicates = !annotationPredicates.isEmpty();
boolean hasTypePredicates = !typePredicates.isEmpty();
final JavaElementFactory elementFactory = visitorContext.getElementFactory();
elementLoop: for (Element enclosedElement : enclosedElements) {
ElementKind enclosedElementKind = enclosedElement.getKind();
if (enclosedElementKind == kind || (enclosedElementKind == ElementKind.ENUM && kind == ElementKind.CLASS)) {
String elementName = enclosedElement.getSimpleName().toString();
if (onlyAccessible) {
// exclude private members
if (enclosedElement.getModifiers().contains(Modifier.PRIVATE)) {
continue;
} else if (elementName.startsWith("$")) {
// exclude synthetic members or bridge methods that start with $
continue;
} else {
Element enclosingElement = enclosedElement.getEnclosingElement();
final ClassElement onlyAccessibleFrom = result.getOnlyAccessibleFromType().orElse(this);
Object accessibleFrom = onlyAccessibleFrom.getNativeType();
// we need to check if it package private and within a different package so it can be excluded
if (enclosingElement != accessibleFrom && visitorContext.getModelUtils().isPackagePrivate(enclosedElement)) {
if (enclosingElement instanceof TypeElement) {
Name qualifiedName = ((TypeElement) enclosingElement).getQualifiedName();
String packageName = NameUtils.getPackageName(qualifiedName.toString());
if (!packageName.equals(onlyAccessibleFrom.getPackageName())) {
continue;
}
}
}
}
}
if (hasModifierPredicates) {
Set<ElementModifier> modifiers = enclosedElement.getModifiers().stream().map(m -> ElementModifier.valueOf(m.name())).collect(Collectors.toSet());
for (Predicate<Set<ElementModifier>> modifierPredicate : modifierPredicates) {
if (!modifierPredicate.test(modifiers)) {
continue elementLoop;
}
}
}
if (hasNamePredicates) {
for (Predicate<String> namePredicate : namePredicates) {
if (!namePredicate.test(elementName)) {
continue elementLoop;
}
}
}
final AnnotationMetadata metadata = visitorContext.getAnnotationUtils().getAnnotationMetadata(enclosedElement);
if (hasAnnotationPredicates) {
for (Predicate<AnnotationMetadata> annotationPredicate : annotationPredicates) {
if (!annotationPredicate.test(metadata)) {
continue elementLoop;
}
}
}
T element;
switch(enclosedElementKind) {
case METHOD:
final ExecutableElement executableElement = (ExecutableElement) enclosedElement;
// noinspection unchecked
element = (T) elementFactory.newMethodElement(this, executableElement, metadata, genericTypeInfo);
break;
case FIELD:
// noinspection unchecked
element = (T) elementFactory.newFieldElement(this, (VariableElement) enclosedElement, metadata);
break;
case CONSTRUCTOR:
// noinspection unchecked
element = (T) elementFactory.newConstructorElement(this, (ExecutableElement) enclosedElement, metadata);
break;
case CLASS:
case ENUM:
// noinspection unchecked
element = (T) elementFactory.newClassElement((TypeElement) enclosedElement, metadata);
break;
default:
element = null;
}
if (element != null) {
if (hasTypePredicates) {
for (Predicate<ClassElement> typePredicate : typePredicates) {
ClassElement classElement;
if (element instanceof ConstructorElement) {
classElement = this;
} else if (element instanceof MethodElement) {
classElement = ((MethodElement) element).getGenericReturnType();
} else if (element instanceof ClassElement) {
classElement = (ClassElement) element;
} else {
classElement = ((FieldElement) element).getGenericField();
}
if (!typePredicate.test(classElement)) {
continue elementLoop;
}
}
}
List<Predicate<T>> elementPredicates = result.getElementPredicates();
if (!elementPredicates.isEmpty()) {
for (Predicate<T> elementPredicate : elementPredicates) {
if (!elementPredicate.test(element)) {
continue elementLoop;
}
}
}
resultingElements.add(element);
}
}
}
return Collections.unmodifiableList(resultingElements);
}
use of io.micronaut.inject.ast.ConstructorElement 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.ConstructorElement 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