Search in sources :

Example 1 with FieldElement

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

the class BeanDefinitionWriter method visitBeanDefinitionConstructorInternal.

private void visitBeanDefinitionConstructorInternal(GeneratorAdapter staticInit, Object constructor, boolean requiresReflection) {
    if (constructor instanceof MethodElement) {
        MethodElement methodElement = (MethodElement) constructor;
        AnnotationMetadata constructorMetadata = methodElement.getAnnotationMetadata();
        DefaultAnnotationMetadata.contributeDefaults(this.annotationMetadata, constructorMetadata);
        DefaultAnnotationMetadata.contributeRepeatable(this.annotationMetadata, methodElement.getGenericReturnType());
        ParameterElement[] parameters = methodElement.getParameters();
        List<ParameterElement> parameterList = Arrays.asList(parameters);
        applyDefaultNamedToParameters(parameterList);
        pushNewMethodReference(staticInit, JavaModelUtils.getTypeReference(methodElement.getDeclaringType()), methodElement, requiresReflection, false, false);
    } else if (constructor instanceof FieldElement) {
        FieldElement fieldConstructor = (FieldElement) constructor;
        pushNewFieldReference(staticInit, JavaModelUtils.getTypeReference(fieldConstructor.getDeclaringType()), fieldConstructor, constructorRequiresReflection);
    } else {
        throw new IllegalArgumentException("Unexpected constructor: " + constructor);
    }
    staticInit.putStatic(beanDefinitionType, FIELD_CONSTRUCTOR, Type.getType(AbstractInitializableBeanDefinition.MethodOrFieldReference.class));
    GeneratorAdapter publicConstructor = new GeneratorAdapter(classWriter.visitMethod(ACC_PUBLIC, CONSTRUCTOR_NAME, DESCRIPTOR_DEFAULT_CONSTRUCTOR, null, null), ACC_PUBLIC, CONSTRUCTOR_NAME, DESCRIPTOR_DEFAULT_CONSTRUCTOR);
    publicConstructor.loadThis();
    publicConstructor.push(beanType);
    publicConstructor.getStatic(beanDefinitionType, FIELD_CONSTRUCTOR, Type.getType(AbstractInitializableBeanDefinition.MethodOrFieldReference.class));
    publicConstructor.invokeConstructor(superBeanDefinition ? superType : beanDefinitionType, PROTECTED_ABSTRACT_BEAN_DEFINITION_CONSTRUCTOR);
    publicConstructor.visitInsn(RETURN);
    publicConstructor.visitMaxs(5, 1);
    publicConstructor.visitEnd();
    if (!superBeanDefinition) {
        // create protected constructor for subclasses of AbstractBeanDefinition
        GeneratorAdapter protectedConstructor = new GeneratorAdapter(classWriter.visitMethod(ACC_PROTECTED, PROTECTED_ABSTRACT_BEAN_DEFINITION_CONSTRUCTOR.getName(), PROTECTED_ABSTRACT_BEAN_DEFINITION_CONSTRUCTOR.getDescriptor(), null, null), ACC_PROTECTED, PROTECTED_ABSTRACT_BEAN_DEFINITION_CONSTRUCTOR.getName(), PROTECTED_ABSTRACT_BEAN_DEFINITION_CONSTRUCTOR.getDescriptor());
        AnnotationMetadata annotationMetadata = this.annotationMetadata != null ? this.annotationMetadata : AnnotationMetadata.EMPTY_METADATA;
        protectedConstructor.loadThis();
        // 1: beanType
        protectedConstructor.loadArg(0);
        // 2: `AbstractBeanDefinition2.MethodOrFieldReference.class` constructor
        protectedConstructor.loadArg(1);
        // 3: annotationMetadata
        if (this.annotationMetadata == null) {
            protectedConstructor.push((String) null);
        } else {
            protectedConstructor.getStatic(getTypeReferenceForName(getBeanDefinitionReferenceClassName()), AbstractAnnotationMetadataWriter.FIELD_ANNOTATION_METADATA, Type.getType(AnnotationMetadata.class));
        }
        // 4: `AbstractBeanDefinition2.MethodReference[].class` methodInjection
        if (allMethodVisits.isEmpty()) {
            protectedConstructor.push((String) null);
        } else {
            protectedConstructor.getStatic(beanDefinitionType, FIELD_INJECTION_METHODS, Type.getType(AbstractInitializableBeanDefinition.MethodReference[].class));
        }
        // 5: `AbstractBeanDefinition2.FieldReference[].class` fieldInjection
        if (fieldInjectionPoints.isEmpty()) {
            protectedConstructor.push((String) null);
        } else {
            protectedConstructor.getStatic(beanDefinitionType, FIELD_INJECTION_FIELDS, Type.getType(AbstractInitializableBeanDefinition.FieldReference[].class));
        }
        // 6: `ExecutableMethod[]` executableMethods
        if (executableMethodsDefinitionWriter == null) {
            protectedConstructor.push((String) null);
        } else {
            protectedConstructor.newInstance(executableMethodsDefinitionWriter.getClassType());
            protectedConstructor.dup();
            protectedConstructor.invokeConstructor(executableMethodsDefinitionWriter.getClassType(), METHOD_DEFAULT_CONSTRUCTOR);
        }
        // 7: `Map<String, Argument<?>[]>` typeArgumentsMap
        if (!hasTypeArguments()) {
            protectedConstructor.push((String) null);
        } else {
            protectedConstructor.getStatic(beanDefinitionType, FIELD_TYPE_ARGUMENTS, Type.getType(Map.class));
        }
        // 8: `Optional` scope
        String scope = annotationMetadata.getAnnotationNameByStereotype(AnnotationUtil.SCOPE).orElse(null);
        if (scope != null) {
            protectedConstructor.push(scope);
            protectedConstructor.invokeStatic(TYPE_OPTIONAL, METHOD_OPTIONAL_OF);
        } else {
            protectedConstructor.invokeStatic(TYPE_OPTIONAL, METHOD_OPTIONAL_EMPTY);
        }
        // 9: `boolean` isAbstract
        protectedConstructor.push(isAbstract);
        // 10: `boolean` isProvided
        protectedConstructor.push(annotationMetadata.hasDeclaredStereotype(Provided.class));
        // 11: `boolean` isIterable
        protectedConstructor.push(isIterable(annotationMetadata));
        // 12: `boolean` isSingleton
        protectedConstructor.push(isSingleton(scope));
        // 13: `boolean` isPrimary
        protectedConstructor.push(annotationMetadata.hasDeclaredStereotype(Primary.class));
        // 14: `boolean` isConfigurationProperties
        protectedConstructor.push(isConfigurationProperties);
        // 15: isContainerType
        protectedConstructor.push(isContainerType());
        // 16: requiresMethodProcessing
        protectedConstructor.push(preprocessMethods);
        protectedConstructor.invokeConstructor(isSuperFactory ? TYPE_ABSTRACT_BEAN_DEFINITION : superType, BEAN_DEFINITION_CLASS_CONSTRUCTOR);
        protectedConstructor.visitInsn(RETURN);
        protectedConstructor.visitMaxs(20, 1);
        protectedConstructor.visitEnd();
    }
}
Also used : MethodElement(io.micronaut.inject.ast.MethodElement) FieldElement(io.micronaut.inject.ast.FieldElement) MutableAnnotationMetadata(io.micronaut.inject.annotation.MutableAnnotationMetadata) DefaultAnnotationMetadata(io.micronaut.inject.annotation.DefaultAnnotationMetadata) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) AbstractInitializableBeanDefinition(io.micronaut.context.AbstractInitializableBeanDefinition) Primary(io.micronaut.context.annotation.Primary) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) ParameterElement(io.micronaut.inject.ast.ParameterElement) Map(java.util.Map) LinkedHashMap(java.util.LinkedHashMap) HashMap(java.util.HashMap) Provided(io.micronaut.context.annotation.Provided)

Example 2 with FieldElement

use of io.micronaut.inject.ast.FieldElement 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 3 with FieldElement

use of io.micronaut.inject.ast.FieldElement 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 4 with FieldElement

use of io.micronaut.inject.ast.FieldElement 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 5 with FieldElement

use of io.micronaut.inject.ast.FieldElement 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

FieldElement (io.micronaut.inject.ast.FieldElement)6 MethodElement (io.micronaut.inject.ast.MethodElement)6 AnnotationMetadata (io.micronaut.core.annotation.AnnotationMetadata)5 LinkedHashMap (java.util.LinkedHashMap)5 Map (java.util.Map)5 Internal (io.micronaut.core.annotation.Internal)4 NonNull (io.micronaut.core.annotation.NonNull)4 ClassElement (io.micronaut.inject.ast.ClassElement)4 ConstructorElement (io.micronaut.inject.ast.ConstructorElement)4 ElementModifier (io.micronaut.inject.ast.ElementModifier)4 ElementQuery (io.micronaut.inject.ast.ElementQuery)4 ArrayList (java.util.ArrayList)4 BeanElementBuilder (io.micronaut.inject.ast.beans.BeanElementBuilder)3 Collections (java.util.Collections)3 Iterator (java.util.Iterator)3 List (java.util.List)3 Set (java.util.Set)3 Predicate (java.util.function.Predicate)3 AnnotationUtils (io.micronaut.annotation.processing.AnnotationUtils)2 ModelUtils (io.micronaut.annotation.processing.ModelUtils)2