Search in sources :

Example 6 with MethodElement

use of io.micronaut.inject.ast.MethodElement 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;
}
Also used : ElementQuery(io.micronaut.inject.ast.ElementQuery) Arrays(java.util.Arrays) ArrayUtils(io.micronaut.core.util.ArrayUtils) FieldElement(io.micronaut.inject.ast.FieldElement) BeanFieldElement(io.micronaut.inject.ast.beans.BeanFieldElement) ClassElement(io.micronaut.inject.ast.ClassElement) HashMap(java.util.HashMap) Internal(io.micronaut.core.annotation.Internal) ConstructorElement(io.micronaut.inject.ast.ConstructorElement) BeanMethodElement(io.micronaut.inject.ast.beans.BeanMethodElement) ParameterElement(io.micronaut.inject.ast.ParameterElement) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) PreDestroy(javax.annotation.PreDestroy) ElementFactory(io.micronaut.inject.ast.ElementFactory) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Nullable(io.micronaut.core.annotation.Nullable) Map(java.util.Map) ElementModifier(io.micronaut.inject.ast.ElementModifier) AnnotationClassValue(io.micronaut.core.annotation.AnnotationClassValue) Property(io.micronaut.context.annotation.Property) Element(io.micronaut.inject.ast.Element) Iterator(java.util.Iterator) Predicate(java.util.function.Predicate) Set(java.util.Set) IOException(java.io.IOException) Value(io.micronaut.context.annotation.Value) BeanParameterElement(io.micronaut.inject.ast.beans.BeanParameterElement) MemberElement(io.micronaut.inject.ast.MemberElement) Bean(io.micronaut.context.annotation.Bean) Consumer(java.util.function.Consumer) NonNull(io.micronaut.core.annotation.NonNull) VisitorContext(io.micronaut.inject.visitor.VisitorContext) List(java.util.List) BeanConstructorElement(io.micronaut.inject.ast.beans.BeanConstructorElement) AnnotationValueBuilder(io.micronaut.core.annotation.AnnotationValueBuilder) BeanElementBuilder(io.micronaut.inject.ast.beans.BeanElementBuilder) AnnotationValue(io.micronaut.core.annotation.AnnotationValue) MethodElement(io.micronaut.inject.ast.MethodElement) ConfigurationMetadataBuilder(io.micronaut.inject.configuration.ConfigurationMetadataBuilder) Annotation(java.lang.annotation.Annotation) PostConstruct(javax.annotation.PostConstruct) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) Comparator(java.util.Comparator) Collections(java.util.Collections) MutableAnnotationMetadata(io.micronaut.inject.annotation.MutableAnnotationMetadata) ConstructorElement(io.micronaut.inject.ast.ConstructorElement) BeanConstructorElement(io.micronaut.inject.ast.beans.BeanConstructorElement) FieldElement(io.micronaut.inject.ast.FieldElement) BeanFieldElement(io.micronaut.inject.ast.beans.BeanFieldElement) BeanMethodElement(io.micronaut.inject.ast.beans.BeanMethodElement) MethodElement(io.micronaut.inject.ast.MethodElement) ClassElement(io.micronaut.inject.ast.ClassElement)

Example 7 with MethodElement

use of io.micronaut.inject.ast.MethodElement in project micronaut-core by micronaut-projects.

the class TestBeanFactoryDefiningVisitor method visitClass.

@Override
public void visitClass(ClassElement element, VisitorContext context) {
    if (element.hasAnnotation(Prototype.class)) {
        context.getClassElement(TestBeanProducer.class).ifPresent((producer) -> {
            final BeanElementBuilder beanElementBuilder = element.addAssociatedBean(producer);
            final ElementQuery<MethodElement> query = ElementQuery.ALL_METHODS.annotated((am) -> am.hasAnnotation(TestProduces.class));
            beanElementBuilder.produceBeans(query);
            final ElementQuery<FieldElement> fields = ElementQuery.ALL_FIELDS.annotated((am) -> am.hasAnnotation(TestProduces.class));
            beanElementBuilder.produceBeans(fields);
        });
    }
}
Also used : BeanElementBuilder(io.micronaut.inject.ast.beans.BeanElementBuilder) MethodElement(io.micronaut.inject.ast.MethodElement) FieldElement(io.micronaut.inject.ast.FieldElement)

Example 8 with MethodElement

use of io.micronaut.inject.ast.MethodElement in project micronaut-core by micronaut-projects.

the class AopProxyWriter method visitAroundMethod.

/**
 * Visit a method that is to be proxied.
 *
 * @param beanType      The bean type.
 * @param methodElement The method element
 */
public void visitAroundMethod(TypedElement beanType, MethodElement methodElement) {
    ClassElement returnType = methodElement.isSuspend() ? ClassElement.of(Object.class) : methodElement.getReturnType();
    Type returnTypeObject = JavaModelUtils.getTypeReference(returnType);
    boolean isPrimitive = returnType.isPrimitive();
    boolean isVoidReturn = isPrimitive && returnTypeObject.equals(Type.VOID_TYPE);
    final Optional<MethodElement> overridden = methodElement.getOwningType().getEnclosedElement(ElementQuery.ALL_METHODS.onlyInstance().named(name -> name.equals(methodElement.getName())).filter(el -> el.overrides(methodElement)));
    if (overridden.isPresent()) {
        MethodElement overriddenBy = overridden.get();
        String methodElementKey = methodElement.getName() + Arrays.stream(methodElement.getSuspendParameters()).map(p -> p.getType().getName()).collect(Collectors.joining(","));
        String overriddenByKey = overriddenBy.getName() + Arrays.stream(methodElement.getSuspendParameters()).map(p -> p.getGenericType().getName()).collect(Collectors.joining(","));
        if (!methodElementKey.equals(overriddenByKey)) {
            buildMethodDelegate(methodElement, overriddenBy, isVoidReturn);
            return;
        }
    }
    String methodName = methodElement.getName();
    List<ParameterElement> argumentTypeList = Arrays.asList(methodElement.getSuspendParameters());
    int argumentCount = argumentTypeList.size();
    final Type declaringTypeReference = JavaModelUtils.getTypeReference(beanType);
    MethodRef methodKey = new MethodRef(methodName, argumentTypeList, returnTypeObject);
    if (!proxiedMethodsRefSet.contains(methodKey)) {
        String interceptedProxyClassName = null;
        String interceptedProxyBridgeMethodName = null;
        if (!isProxyTarget) {
            if (!methodElement.isAbstract() || methodElement.isDefault()) {
                interceptedProxyClassName = proxyFullName;
                interceptedProxyBridgeMethodName = "$$access$$" + methodName;
                String bridgeDesc = getMethodDescriptor(returnType, argumentTypeList);
                // now build a bridge to invoke the original method
                MethodVisitor bridgeWriter = classWriter.visitMethod(ACC_SYNTHETIC, interceptedProxyBridgeMethodName, bridgeDesc, null, null);
                GeneratorAdapter bridgeGenerator = new GeneratorAdapter(bridgeWriter, ACC_SYNTHETIC, interceptedProxyBridgeMethodName, bridgeDesc);
                bridgeGenerator.loadThis();
                for (int i = 0; i < argumentTypeList.size(); i++) {
                    bridgeGenerator.loadArg(i);
                }
                String desc = getMethodDescriptor(returnType, argumentTypeList);
                bridgeWriter.visitMethodInsn(INVOKESPECIAL, declaringTypeReference.getInternalName(), methodName, desc, this.isInterface && methodElement.isDefault());
                pushReturnValue(bridgeWriter, returnType);
                bridgeWriter.visitMaxs(DEFAULT_MAX_STACK, 1);
                bridgeWriter.visitEnd();
            }
        }
        BeanDefinitionWriter beanDefinitionWriter = parentWriter == null ? proxyBeanDefinitionWriter : parentWriter;
        int methodIndex = beanDefinitionWriter.visitExecutableMethod(beanType, methodElement, interceptedProxyClassName, interceptedProxyBridgeMethodName);
        int index = proxyMethodCount++;
        methodKey.methodIndex = methodIndex;
        proxiedMethods.add(methodKey);
        proxiedMethodsRefSet.add(methodKey);
        proxyTargetMethods.add(methodKey);
        buildMethodOverride(returnType, methodName, index, argumentTypeList, argumentCount, isVoidReturn);
    }
}
Also used : ElementQuery(io.micronaut.inject.ast.ElementQuery) Arrays(java.util.Arrays) InterceptedProxy(io.micronaut.aop.InterceptedProxy) MethodVisitor(org.objectweb.asm.MethodVisitor) BeanContext(io.micronaut.context.BeanContext) ArrayUtils(io.micronaut.core.util.ArrayUtils) FieldElement(io.micronaut.inject.ast.FieldElement) DefaultBeanContext(io.micronaut.context.DefaultBeanContext) Type(org.objectweb.asm.Type) ProxyingBeanDefinitionVisitor(io.micronaut.inject.writer.ProxyingBeanDefinitionVisitor) Introduced(io.micronaut.aop.Introduced) MethodInterceptorChain(io.micronaut.aop.chain.MethodInterceptorChain) Map(java.util.Map) BeanResolutionContext(io.micronaut.context.BeanResolutionContext) AbstractClassFileWriter(io.micronaut.inject.writer.AbstractClassFileWriter) HotSwappableInterceptedProxy(io.micronaut.aop.HotSwappableInterceptedProxy) BeanLocator(io.micronaut.context.BeanLocator) ClassVisitor(org.objectweb.asm.ClassVisitor) ReadWriteLock(java.util.concurrent.locks.ReadWriteLock) Set(java.util.Set) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) StringUtils(io.micronaut.core.util.StringUtils) List(java.util.List) Interceptor(io.micronaut.aop.Interceptor) AnnotationUtil(io.micronaut.core.annotation.AnnotationUtil) AnnotationValue(io.micronaut.core.annotation.AnnotationValue) ProxyBeanDefinition(io.micronaut.inject.ProxyBeanDefinition) MethodElement(io.micronaut.inject.ast.MethodElement) Optional(java.util.Optional) InterceptorChain(io.micronaut.aop.chain.InterceptorChain) BeanDefinitionWriter(io.micronaut.inject.writer.BeanDefinitionWriter) ConfigurationMetadata(io.micronaut.inject.configuration.ConfigurationMetadata) JavaModelUtils(io.micronaut.inject.processing.JavaModelUtils) ClassWriter(org.objectweb.asm.ClassWriter) BeanRegistration(io.micronaut.context.BeanRegistration) OriginatingElements(io.micronaut.inject.writer.OriginatingElements) Qualifier(io.micronaut.context.Qualifier) Label(org.objectweb.asm.Label) ClassElement(io.micronaut.inject.ast.ClassElement) ReentrantReadWriteLock(java.util.concurrent.locks.ReentrantReadWriteLock) Toggleable(io.micronaut.core.util.Toggleable) DefaultAnnotationMetadata(io.micronaut.inject.annotation.DefaultAnnotationMetadata) Constructor(java.lang.reflect.Constructor) ExecutableMethod(io.micronaut.inject.ExecutableMethod) ParameterElement(io.micronaut.inject.ast.ParameterElement) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) Method(org.objectweb.asm.commons.Method) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) TypedElement(io.micronaut.inject.ast.TypedElement) AnnotationMetadataReference(io.micronaut.inject.annotation.AnnotationMetadataReference) ConfigurationReader(io.micronaut.context.annotation.ConfigurationReader) Argument(io.micronaut.core.type.Argument) ClassWriterOutputVisitor(io.micronaut.inject.writer.ClassWriterOutputVisitor) LinkedHashSet(java.util.LinkedHashSet) ExecutableMethodsDefinitionWriter(io.micronaut.inject.writer.ExecutableMethodsDefinitionWriter) OutputStream(java.io.OutputStream) Opcodes(org.objectweb.asm.Opcodes) Element(io.micronaut.inject.ast.Element) Iterator(java.util.Iterator) InterceptedMethodUtil(io.micronaut.aop.internal.intercepted.InterceptedMethodUtil) IOException(java.io.IOException) OptionalValues(io.micronaut.core.value.OptionalValues) ReflectionUtils(io.micronaut.core.reflect.ReflectionUtils) File(java.io.File) InterceptorKind(io.micronaut.aop.InterceptorKind) NonNull(io.micronaut.core.annotation.NonNull) ExecutionHandleLocator(io.micronaut.context.ExecutionHandleLocator) VisitorContext(io.micronaut.inject.visitor.VisitorContext) Lock(java.util.concurrent.locks.Lock) ConfigurationMetadataBuilder(io.micronaut.inject.configuration.ConfigurationMetadataBuilder) BeanDefinitionVisitor(io.micronaut.inject.writer.BeanDefinitionVisitor) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) BeanDefinition(io.micronaut.inject.BeanDefinition) Collections(java.util.Collections) Intercepted(io.micronaut.aop.Intercepted) MethodElement(io.micronaut.inject.ast.MethodElement) ClassElement(io.micronaut.inject.ast.ClassElement) BeanDefinitionWriter(io.micronaut.inject.writer.BeanDefinitionWriter) MethodVisitor(org.objectweb.asm.MethodVisitor) Type(org.objectweb.asm.Type) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) ParameterElement(io.micronaut.inject.ast.ParameterElement)

Example 9 with MethodElement

use of io.micronaut.inject.ast.MethodElement in project micronaut-core by micronaut-projects.

the class JavaClassElement method getBeanProperties.

@Override
public List<PropertyElement> getBeanProperties() {
    if (this.beanProperties == null) {
        Map<String, BeanPropertyData> props = new LinkedHashMap<>();
        Map<String, VariableElement> fields = new LinkedHashMap<>();
        if (isRecord()) {
            classElement.asType().accept(new SuperclassAwareTypeVisitor<Object, Object>(visitorContext) {

                @Override
                protected boolean isAcceptable(Element element) {
                    return JavaModelUtils.isRecord(element);
                }

                @Override
                public Object visitDeclared(DeclaredType type, Object o) {
                    Element element = type.asElement();
                    if (isAcceptable(element)) {
                        List<? extends Element> enclosedElements = element.getEnclosedElements();
                        for (Element enclosedElement : enclosedElements) {
                            if (JavaModelUtils.isRecordComponent(enclosedElement) || enclosedElement instanceof ExecutableElement) {
                                if (enclosedElement.getKind() != ElementKind.CONSTRUCTOR) {
                                    accept(type, enclosedElement, o);
                                }
                            }
                        }
                    }
                    return o;
                }

                @Override
                protected void accept(DeclaredType type, Element element, Object o) {
                    String name = element.getSimpleName().toString();
                    if (element instanceof ExecutableElement) {
                        BeanPropertyData beanPropertyData = props.get(name);
                        if (beanPropertyData != null) {
                            beanPropertyData.getter = (ExecutableElement) element;
                        }
                    } else {
                        props.computeIfAbsent(name, propertyName -> {
                            BeanPropertyData beanPropertyData = new BeanPropertyData(propertyName);
                            beanPropertyData.declaringType = JavaClassElement.this;
                            beanPropertyData.type = mirrorToClassElement(element.asType(), visitorContext, genericTypeInfo, true);
                            return beanPropertyData;
                        });
                    }
                }
            }, null);
        } else {
            classElement.asType().accept(new PublicMethodVisitor<Object, Object>(visitorContext) {

                final String[] readPrefixes = getValue(AccessorsStyle.class, "readPrefixes", String[].class).orElse(new String[] { AccessorsStyle.DEFAULT_READ_PREFIX });

                final String[] writePrefixes = getValue(AccessorsStyle.class, "writePrefixes", String[].class).orElse(new String[] { AccessorsStyle.DEFAULT_WRITE_PREFIX });

                @Override
                protected boolean isAcceptable(javax.lang.model.element.Element element) {
                    if (element.getKind() == ElementKind.FIELD) {
                        return true;
                    }
                    if (element.getKind() == ElementKind.METHOD && element instanceof ExecutableElement) {
                        Set<Modifier> modifiers = element.getModifiers();
                        if (modifiers.contains(Modifier.PUBLIC) && !modifiers.contains(Modifier.STATIC)) {
                            ExecutableElement executableElement = (ExecutableElement) element;
                            String methodName = executableElement.getSimpleName().toString();
                            if (methodName.contains("$")) {
                                return false;
                            }
                            if (NameUtils.isReaderName(methodName, readPrefixes) && executableElement.getParameters().isEmpty()) {
                                return true;
                            } else {
                                return NameUtils.isWriterName(methodName, writePrefixes) && executableElement.getParameters().size() == 1;
                            }
                        }
                    }
                    return false;
                }

                @Override
                protected void accept(DeclaredType declaringType, javax.lang.model.element.Element element, Object o) {
                    if (element instanceof VariableElement) {
                        fields.put(element.getSimpleName().toString(), (VariableElement) element);
                        return;
                    }
                    ExecutableElement executableElement = (ExecutableElement) element;
                    String methodName = executableElement.getSimpleName().toString();
                    final TypeElement declaringTypeElement = (TypeElement) executableElement.getEnclosingElement();
                    if (NameUtils.isReaderName(methodName, readPrefixes) && executableElement.getParameters().isEmpty()) {
                        String propertyName = NameUtils.getPropertyNameForGetter(methodName, readPrefixes);
                        TypeMirror returnType = executableElement.getReturnType();
                        ClassElement getterReturnType;
                        if (returnType instanceof TypeVariable) {
                            TypeVariable tv = (TypeVariable) returnType;
                            final String tvn = tv.toString();
                            final ClassElement classElement = getTypeArguments().get(tvn);
                            if (classElement != null) {
                                getterReturnType = classElement;
                            } else {
                                getterReturnType = mirrorToClassElement(returnType, visitorContext, JavaClassElement.this.genericTypeInfo, true);
                            }
                        } else {
                            getterReturnType = mirrorToClassElement(returnType, visitorContext, JavaClassElement.this.genericTypeInfo, true);
                        }
                        BeanPropertyData beanPropertyData = props.computeIfAbsent(propertyName, BeanPropertyData::new);
                        configureDeclaringType(declaringTypeElement, beanPropertyData);
                        beanPropertyData.type = getterReturnType;
                        beanPropertyData.getter = executableElement;
                        if (beanPropertyData.setter != null) {
                            TypeMirror typeMirror = beanPropertyData.setter.getParameters().get(0).asType();
                            ClassElement setterParameterType = mirrorToClassElement(typeMirror, visitorContext, JavaClassElement.this.genericTypeInfo, true);
                            if (!setterParameterType.isAssignable(getterReturnType)) {
                                // not a compatible setter
                                beanPropertyData.setter = null;
                            }
                        }
                    } else if (NameUtils.isWriterName(methodName, writePrefixes) && executableElement.getParameters().size() == 1) {
                        String propertyName = NameUtils.getPropertyNameForSetter(methodName, writePrefixes);
                        TypeMirror typeMirror = executableElement.getParameters().get(0).asType();
                        ClassElement setterParameterType = mirrorToClassElement(typeMirror, visitorContext, JavaClassElement.this.genericTypeInfo, true);
                        BeanPropertyData beanPropertyData = props.computeIfAbsent(propertyName, BeanPropertyData::new);
                        configureDeclaringType(declaringTypeElement, beanPropertyData);
                        ClassElement propertyType = beanPropertyData.type;
                        if (propertyType != null) {
                            if (propertyType.getName().equals(setterParameterType.getName())) {
                                beanPropertyData.setter = executableElement;
                            }
                        } else {
                            beanPropertyData.setter = executableElement;
                        }
                    }
                }

                private void configureDeclaringType(TypeElement declaringTypeElement, BeanPropertyData beanPropertyData) {
                    if (beanPropertyData.declaringType == null && !classElement.equals(declaringTypeElement)) {
                        beanPropertyData.declaringType = mirrorToClassElement(declaringTypeElement.asType(), visitorContext, genericTypeInfo, true);
                    } else if (beanPropertyData.declaringType == null) {
                        beanPropertyData.declaringType = mirrorToClassElement(declaringTypeElement.asType(), visitorContext, genericTypeInfo, false);
                    }
                }
            }, null);
        }
        if (!props.isEmpty()) {
            this.beanProperties = new ArrayList<>(props.size());
            for (Map.Entry<String, BeanPropertyData> entry : props.entrySet()) {
                String propertyName = entry.getKey();
                BeanPropertyData value = entry.getValue();
                final VariableElement fieldElement = fields.get(propertyName);
                if (value.getter != null) {
                    final AnnotationMetadata annotationMetadata;
                    List<Element> parents = new ArrayList<>();
                    if (fieldElement != null) {
                        parents.add(fieldElement);
                    }
                    if (value.setter != null) {
                        parents.add(value.setter);
                    }
                    if (!parents.isEmpty()) {
                        annotationMetadata = visitorContext.getAnnotationUtils().getAnnotationMetadata(parents, value.getter);
                    } else {
                        annotationMetadata = visitorContext.getAnnotationUtils().newAnnotationBuilder().buildForMethod(value.getter);
                    }
                    JavaPropertyElement propertyElement = new JavaPropertyElement(value.declaringType == null ? this : value.declaringType, value.getter, annotationMetadata, propertyName, value.type, value.setter == null, visitorContext) {

                        @Override
                        public ClassElement getGenericType() {
                            TypeMirror propertyType = value.getter.getReturnType();
                            if (fieldElement != null) {
                                TypeMirror fieldType = fieldElement.asType();
                                if (visitorContext.getTypes().isAssignable(fieldType, propertyType)) {
                                    propertyType = fieldType;
                                }
                            }
                            Map<String, Map<String, TypeMirror>> declaredGenericInfo = getGenericTypeInfo();
                            return parameterizedClassElement(propertyType, visitorContext, declaredGenericInfo);
                        }

                        @Override
                        public Optional<String> getDocumentation() {
                            Elements elements = visitorContext.getElements();
                            String docComment = elements.getDocComment(value.getter);
                            return Optional.ofNullable(docComment);
                        }

                        @Override
                        public Optional<MethodElement> getWriteMethod() {
                            if (value.setter != null) {
                                return Optional.of(new JavaMethodElement(JavaClassElement.this, value.setter, visitorContext.getAnnotationUtils().newAnnotationBuilder().buildForMethod(value.setter), visitorContext));
                            }
                            return Optional.empty();
                        }

                        @Override
                        public Optional<MethodElement> getReadMethod() {
                            return Optional.of(new JavaMethodElement(JavaClassElement.this, value.getter, annotationMetadata, visitorContext));
                        }
                    };
                    beanProperties.add(propertyElement);
                }
            }
            this.beanProperties = Collections.unmodifiableList(beanProperties);
        } else {
            this.beanProperties = Collections.emptyList();
        }
    }
    return Collections.unmodifiableList(beanProperties);
}
Also used : ElementQuery(io.micronaut.inject.ast.ElementQuery) PackageElement(io.micronaut.inject.ast.PackageElement) AnnotationUtils(io.micronaut.annotation.processing.AnnotationUtils) Modifier(javax.lang.model.element.Modifier) FieldElement(io.micronaut.inject.ast.FieldElement) TypeElement(javax.lang.model.element.TypeElement) Internal(io.micronaut.core.annotation.Internal) WildcardElement(io.micronaut.inject.ast.WildcardElement) Elements(javax.lang.model.util.Elements) PublicMethodVisitor(io.micronaut.annotation.processing.PublicMethodVisitor) Map(java.util.Map) NameUtils(io.micronaut.core.naming.NameUtils) ClassUtils(io.micronaut.core.reflect.ClassUtils) GenericPlaceholderElement(io.micronaut.inject.ast.GenericPlaceholderElement) Predicate(java.util.function.Predicate) Collection(java.util.Collection) Set(java.util.Set) AccessorsStyle(io.micronaut.core.annotation.AccessorsStyle) Element(javax.lang.model.element.Element) Types(javax.lang.model.util.Types) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) StringUtils(io.micronaut.core.util.StringUtils) SuperclassAwareTypeVisitor(io.micronaut.annotation.processing.SuperclassAwareTypeVisitor) List(java.util.List) AnnotationUtil(io.micronaut.core.annotation.AnnotationUtil) ModelUtils(io.micronaut.annotation.processing.ModelUtils) MethodElement(io.micronaut.inject.ast.MethodElement) TypeVariable(javax.lang.model.type.TypeVariable) Optional(java.util.Optional) JavaModelUtils(io.micronaut.inject.processing.JavaModelUtils) VariableElement(javax.lang.model.element.VariableElement) ClassElement(io.micronaut.inject.ast.ClassElement) ConstructorElement(io.micronaut.inject.ast.ConstructorElement) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) PropertyElement(io.micronaut.inject.ast.PropertyElement) ArrayableClassElement(io.micronaut.inject.ast.ArrayableClassElement) DeclaredType(javax.lang.model.type.DeclaredType) ElementModifier(io.micronaut.inject.ast.ElementModifier) Name(javax.lang.model.element.Name) ElementKind(javax.lang.model.element.ElementKind) Iterator(java.util.Iterator) ExecutableElement(javax.lang.model.element.ExecutableElement) TypeParameterElement(javax.lang.model.element.TypeParameterElement) NonNull(io.micronaut.core.annotation.NonNull) TypeMirror(javax.lang.model.type.TypeMirror) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) Collections(java.util.Collections) Set(java.util.Set) PackageElement(io.micronaut.inject.ast.PackageElement) FieldElement(io.micronaut.inject.ast.FieldElement) TypeElement(javax.lang.model.element.TypeElement) WildcardElement(io.micronaut.inject.ast.WildcardElement) GenericPlaceholderElement(io.micronaut.inject.ast.GenericPlaceholderElement) Element(javax.lang.model.element.Element) MethodElement(io.micronaut.inject.ast.MethodElement) VariableElement(javax.lang.model.element.VariableElement) ClassElement(io.micronaut.inject.ast.ClassElement) ConstructorElement(io.micronaut.inject.ast.ConstructorElement) PropertyElement(io.micronaut.inject.ast.PropertyElement) ArrayableClassElement(io.micronaut.inject.ast.ArrayableClassElement) ExecutableElement(javax.lang.model.element.ExecutableElement) TypeParameterElement(javax.lang.model.element.TypeParameterElement) ExecutableElement(javax.lang.model.element.ExecutableElement) ArrayList(java.util.ArrayList) MethodElement(io.micronaut.inject.ast.MethodElement) ClassElement(io.micronaut.inject.ast.ClassElement) ArrayableClassElement(io.micronaut.inject.ast.ArrayableClassElement) VariableElement(javax.lang.model.element.VariableElement) Elements(javax.lang.model.util.Elements) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) LinkedHashMap(java.util.LinkedHashMap) TypeMirror(javax.lang.model.type.TypeMirror) TypeVariable(javax.lang.model.type.TypeVariable) List(java.util.List) ArrayList(java.util.ArrayList) TypeElement(javax.lang.model.element.TypeElement) Element(javax.lang.model.element.Element) AccessorsStyle(io.micronaut.core.annotation.AccessorsStyle) Map(java.util.Map) LinkedHashMap(java.util.LinkedHashMap) DeclaredType(javax.lang.model.type.DeclaredType)

Example 10 with MethodElement

use of io.micronaut.inject.ast.MethodElement 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);
}
Also used : ElementKind(javax.lang.model.element.ElementKind) ElementQuery(io.micronaut.inject.ast.ElementQuery) PackageElement(io.micronaut.inject.ast.PackageElement) AnnotationUtils(io.micronaut.annotation.processing.AnnotationUtils) Modifier(javax.lang.model.element.Modifier) FieldElement(io.micronaut.inject.ast.FieldElement) TypeElement(javax.lang.model.element.TypeElement) Internal(io.micronaut.core.annotation.Internal) WildcardElement(io.micronaut.inject.ast.WildcardElement) Elements(javax.lang.model.util.Elements) PublicMethodVisitor(io.micronaut.annotation.processing.PublicMethodVisitor) Map(java.util.Map) NameUtils(io.micronaut.core.naming.NameUtils) ClassUtils(io.micronaut.core.reflect.ClassUtils) GenericPlaceholderElement(io.micronaut.inject.ast.GenericPlaceholderElement) Predicate(java.util.function.Predicate) Collection(java.util.Collection) Set(java.util.Set) AccessorsStyle(io.micronaut.core.annotation.AccessorsStyle) Element(javax.lang.model.element.Element) Types(javax.lang.model.util.Types) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) StringUtils(io.micronaut.core.util.StringUtils) SuperclassAwareTypeVisitor(io.micronaut.annotation.processing.SuperclassAwareTypeVisitor) List(java.util.List) AnnotationUtil(io.micronaut.core.annotation.AnnotationUtil) ModelUtils(io.micronaut.annotation.processing.ModelUtils) MethodElement(io.micronaut.inject.ast.MethodElement) TypeVariable(javax.lang.model.type.TypeVariable) Optional(java.util.Optional) JavaModelUtils(io.micronaut.inject.processing.JavaModelUtils) VariableElement(javax.lang.model.element.VariableElement) ClassElement(io.micronaut.inject.ast.ClassElement) ConstructorElement(io.micronaut.inject.ast.ConstructorElement) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) PropertyElement(io.micronaut.inject.ast.PropertyElement) ArrayableClassElement(io.micronaut.inject.ast.ArrayableClassElement) DeclaredType(javax.lang.model.type.DeclaredType) ElementModifier(io.micronaut.inject.ast.ElementModifier) Name(javax.lang.model.element.Name) ElementKind(javax.lang.model.element.ElementKind) Iterator(java.util.Iterator) ExecutableElement(javax.lang.model.element.ExecutableElement) TypeParameterElement(javax.lang.model.element.TypeParameterElement) NonNull(io.micronaut.core.annotation.NonNull) TypeMirror(javax.lang.model.type.TypeMirror) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) Collections(java.util.Collections) Set(java.util.Set) PackageElement(io.micronaut.inject.ast.PackageElement) FieldElement(io.micronaut.inject.ast.FieldElement) TypeElement(javax.lang.model.element.TypeElement) WildcardElement(io.micronaut.inject.ast.WildcardElement) GenericPlaceholderElement(io.micronaut.inject.ast.GenericPlaceholderElement) Element(javax.lang.model.element.Element) MethodElement(io.micronaut.inject.ast.MethodElement) VariableElement(javax.lang.model.element.VariableElement) ClassElement(io.micronaut.inject.ast.ClassElement) ConstructorElement(io.micronaut.inject.ast.ConstructorElement) PropertyElement(io.micronaut.inject.ast.PropertyElement) ArrayableClassElement(io.micronaut.inject.ast.ArrayableClassElement) ExecutableElement(javax.lang.model.element.ExecutableElement) TypeParameterElement(javax.lang.model.element.TypeParameterElement) ExecutableElement(javax.lang.model.element.ExecutableElement) ArrayList(java.util.ArrayList) MethodElement(io.micronaut.inject.ast.MethodElement) FieldElement(io.micronaut.inject.ast.FieldElement) ClassElement(io.micronaut.inject.ast.ClassElement) ArrayableClassElement(io.micronaut.inject.ast.ArrayableClassElement) VariableElement(javax.lang.model.element.VariableElement) Elements(javax.lang.model.util.Elements) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) Predicate(java.util.function.Predicate) Name(javax.lang.model.element.Name) ElementQuery(io.micronaut.inject.ast.ElementQuery) TypeMirror(javax.lang.model.type.TypeMirror) ModelUtils(io.micronaut.annotation.processing.ModelUtils) JavaModelUtils(io.micronaut.inject.processing.JavaModelUtils) List(java.util.List) ArrayList(java.util.ArrayList) ConstructorElement(io.micronaut.inject.ast.ConstructorElement) TypeElement(javax.lang.model.element.TypeElement) ElementModifier(io.micronaut.inject.ast.ElementModifier) DeclaredType(javax.lang.model.type.DeclaredType)

Aggregations

MethodElement (io.micronaut.inject.ast.MethodElement)18 ClassElement (io.micronaut.inject.ast.ClassElement)14 ParameterElement (io.micronaut.inject.ast.ParameterElement)12 Map (java.util.Map)12 AnnotationMetadata (io.micronaut.core.annotation.AnnotationMetadata)11 FieldElement (io.micronaut.inject.ast.FieldElement)11 List (java.util.List)11 ArrayList (java.util.ArrayList)10 Collections (java.util.Collections)10 Set (java.util.Set)10 NonNull (io.micronaut.core.annotation.NonNull)9 ElementQuery (io.micronaut.inject.ast.ElementQuery)9 HashMap (java.util.HashMap)9 Type (org.objectweb.asm.Type)9 GeneratorAdapter (org.objectweb.asm.commons.GeneratorAdapter)9 Internal (io.micronaut.core.annotation.Internal)8 ConstructorElement (io.micronaut.inject.ast.ConstructorElement)8 Arrays (java.util.Arrays)8 HashSet (java.util.HashSet)8 ArrayUtils (io.micronaut.core.util.ArrayUtils)7