Skip to content

Commit

Permalink
Support type annotations for Java & Groovy (#8764)
Browse files Browse the repository at this point in the history
Introduced a way to access type annotations on ClassElement#getTypeAnnotationMetadata. To do that the native type has to carry the actual type mirror (for Java). If the type mirror is present that indicates that ClassElement supports type annotations and the actual annotation metadata of the class is a hierarchy of both. Modifying annotation metadata of such class will modify the type annotations, modifying the actual class annotation can be done on the #getType class element.

The type annotations are now the ones that are persisted for an executable method's return type, parameters, and type parameters. There is no need for hacks to persist generic type annotations in some cases.

There is some modification to how the generic placeholders are preserved bound to make sure everything works correctly.

Added a lot of tests to test annotating methods, return types, parameters, fields, and field types.
  • Loading branch information
dstepanov authored Feb 15, 2023
1 parent 2be0a44 commit 74e32c1
Show file tree
Hide file tree
Showing 103 changed files with 6,696 additions and 1,150 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import io.micronaut.core.type.DefaultArgument;
import io.micronaut.core.util.ArgumentUtils;
import io.micronaut.core.util.CollectionUtils;
import io.micronaut.inject.ast.annotation.MutableAnnotationMetadataDelegate;
import io.micronaut.inject.ast.beans.BeanElementBuilder;

import java.lang.reflect.GenericArrayType;
Expand Down Expand Up @@ -67,6 +68,20 @@ public interface ClassElement extends TypedElement {
*/
ClassElement[] ZERO_CLASS_ELEMENTS = new ClassElement[0];

/**
* Returns the type annotations.
* Added by:
* - The declaration of the type variable {@link java.lang.annotation.ElementType#TYPE_PARAMETER}
* - The use of the type {@link java.lang.annotation.ElementType#TYPE}
* @return the type annotations
* @since 4.0.0
*/
@Experimental
@NonNull
default MutableAnnotationMetadataDelegate<AnnotationMetadata> getTypeAnnotationMetadata() {
return (MutableAnnotationMetadataDelegate<AnnotationMetadata>) MutableAnnotationMetadataDelegate.EMPTY;
}

/**
* Tests whether one type is assignable to another.
*
Expand Down Expand Up @@ -457,6 +472,30 @@ default List<FieldElement> getFields() {
return getEnclosedElements(ElementQuery.ALL_FIELDS);
}

/**
* Find an instance/static field with a name in this class, super class or an interface.
*
* @param name The field name
* @return The field
* @since 4.0.0
*/
@Experimental
@NonNull
default Optional<FieldElement> findField(String name) {
return getEnclosedElement(ElementQuery.ALL_FIELDS.named(name));
}

/**
* Find an instance/static method with a name in this class, super class or an interface.
*
* @return The methods
* @since 4.0.0
*/
@NonNull
default List<MethodElement> getMethods() {
return getEnclosedElements(ElementQuery.ALL_METHODS);
}

/**
* Find a method with a name.
*
Expand All @@ -465,6 +504,7 @@ default List<FieldElement> getFields() {
* @since 4.0.0
*/
@NonNull
@Experimental
default Optional<MethodElement> findMethod(String name) {
return getEnclosedElement(ElementQuery.ALL_METHODS.named(name));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
*/
package io.micronaut.inject.ast;

import io.micronaut.core.annotation.AnnotationMetadata;
import io.micronaut.core.annotation.Experimental;
import io.micronaut.inject.ast.annotation.MutableAnnotationMetadataDelegate;
import org.jetbrains.annotations.NotNull;

/**
Expand All @@ -40,4 +42,17 @@ default Object getGenericNativeType() {
return getNativeType();
}

/**
* Returns the type parameter annotations.
* Added to this generic element by:
* - The declaration of the type variable {@link java.lang.annotation.ElementType#TYPE_PARAMETER}
* - The use of the type {@link java.lang.annotation.ElementType#TYPE}
* @return the type annotations
*/
@Experimental
@NotNull
default MutableAnnotationMetadataDelegate<AnnotationMetadata> getGenericTypeAnnotationMetadata() {
return (MutableAnnotationMetadataDelegate<AnnotationMetadata>) MutableAnnotationMetadataDelegate.EMPTY;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,24 @@ public interface GenericPlaceholderElement extends GenericElement {
* @return The element declaring this variable, if it can be determined. Must be either a method or a class.
*/
Optional<Element> getDeclaringElement();

/**
* @return The required element declaring this variable, if it can be determined. Must be either a method or a class. Or throws an exception.
* @since 4.0.0
*/
@NonNull
default Element getRequiredDeclaringElement() {
return getDeclaringElement().orElseThrow(() -> new IllegalStateException("Declared element is not present!"));
}

/**
* In some cases the class element can be a resolved placeholder.
* We want to keep the placeholder to reference the type annotations etc.
*
* @return The resolved value of the placeholder.
* @since 4.0.0
*/
default Optional<ClassElement> getResolved() {
return Optional.empty();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2017-2020 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.inject.ast.annotation;

import io.micronaut.core.annotation.AnnotationMetadata;
import io.micronaut.core.annotation.Internal;

/**
* Mutable annotation metadata provider.
*
* @author Denis Stepanov
* @since 4.0.0
*/
@Internal
public abstract class AbstractElementAnnotationMetadata
extends AbstractMutableAnnotationMetadata<AnnotationMetadata>
implements ElementAnnotationMetadata {
}
Loading

0 comments on commit 74e32c1

Please sign in to comment.