AnnotationSource.java
/*
* 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.core.annotation;
import io.micronaut.core.util.ArgumentUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.util.Optional;
/**
* <p>A source of annotations. This API provides an alternative to Java's {@link java.lang.reflect.AnnotatedElement} that uses the compile time produced data
* from Micronaut. This is the parent interface of the {@link AnnotationMetadata} which provides event more methods to read annotations values and compute {@link java.lang.annotation.Repeatable} annotations.</p>
*
* <p>Note that this interface also includes methods such as {@link #synthesize(Class)} that allows materializing an instance of an annotation by producing a runtime proxy. These methods are a last resort if no other option is possible and should generally be avoided as they require the use of runtime reflection and proxying which hurts performance and memory consumption.</p>
*
* @see AnnotationMetadata
* @author Graeme Rocher
* @since 1.0
*/
public interface AnnotationSource {
/**
* An empty annotation source.
*/
AnnotationSource EMPTY = new AnnotationSource() {
};
/**
* Synthesizes a new annotation from the metadata for the given annotation type. This method works
* by creating a runtime proxy of the annotation interface and should be avoided in favour of
* direct use of the annotation metadata and only used for unique cases that require integrating third party libraries.
*
* @param annotationClass The annotation class
* @param <T> The annotation generic type
* @return The annotation or null if it doesn't exist
*/
default @Nullable <T extends Annotation> T synthesize(@NonNull Class<T> annotationClass) {
ArgumentUtils.requireNonNull("annotationClass", annotationClass);
return null;
}
/**
* Synthesizes a new annotation for the given annotation type using the member values of the given source annotation.
*
* <p>This method allows supporting synthesizing annotations that have been renamed, for example a {@code jakarta.inject.Named} annotation an be synthesized from the metadata of the a {@code jakarta.inject.Named} annotation.</p>
*
* @param annotationClass The annotation class
* @param sourceAnnotation The source annotation that provides the member values
* @param <T> The annotation generic type
* @return The annotation or null if it doesn't exist
* @since 3.0.0
*/
default @Nullable <T extends Annotation> T synthesize(
@NonNull Class<T> annotationClass,
@NonNull String sourceAnnotation) {
ArgumentUtils.requireNonNull("annotationClass", annotationClass);
ArgumentUtils.requireNonNull("sourceAnnotation", sourceAnnotation);
return null;
}
/**
* Synthesizes a new annotation declared for the given annotation type using the member values of the given source annotation.
*
* <p>This method allows supporting synthesizing annotations that have been renamed, for example a {@code jakarta.inject.Named} annotation an be synthesized from the metadata of the a {@code jakarta.inject.Named} annotation.</p>
*
* @param annotationClass The annotation class
* @param sourceAnnotation The source annotation that provides the member values
* @param <T> The annotation generic type
* @return The annotation or null if it doesn't exist
* @since 3.0.0
*/
default @Nullable <T extends Annotation> T synthesizeDeclared(
@NonNull Class<T> annotationClass,
@NonNull String sourceAnnotation) {
ArgumentUtils.requireNonNull("annotationClass", annotationClass);
ArgumentUtils.requireNonNull("sourceAnnotation", sourceAnnotation);
return null;
}
/**
* Synthesizes a new annotation from the metadata for the given annotation type. This method works
* by creating a runtime proxy of the annotation interface and should be avoided in favour of
* direct use of the annotation metadata and only used for unique cases that require integrating third party libraries.
* <p>
* This method ignores inherited annotations. (Returns null if no
* annotations are directly present on this element.)
*
* @param annotationClass The annotation class
* @param <T> The annotation generic type
* @return The annotation or null if it doesn't exist
*/
default @Nullable <T extends Annotation> T synthesizeDeclared(@NonNull Class<T> annotationClass) {
ArgumentUtils.requireNonNull("annotationClass", annotationClass);
return null;
}
/**
* Synthesizes a new annotations from the metadata. This method works
* by creating a runtime proxy of the annotation interface and should be avoided in favour of
* direct use of the annotation metadata and only used for unique cases that require integrating third party libraries.
*
* @return All the annotations
*/
default @NonNull Annotation[] synthesizeAll() {
return AnnotationUtil.ZERO_ANNOTATIONS;
}
/**
* Synthesizes a new annotations from the metadata. This method works
* by creating a runtime proxy of the annotation interface and should be avoided in favour of
* direct use of the annotation metadata and only used for unique cases that require integrating third party libraries.
*
* @return All declared annotations
*/
default @NonNull Annotation[] synthesizeDeclared() {
return AnnotationUtil.ZERO_ANNOTATIONS;
}
/**
* Synthesizes a new annotations from the metadata for the given type. This method works
* by creating a runtime proxy of the annotation interface and should be avoided in favour of
* direct use of the annotation metadata and only used for unique cases that require integrating third party libraries.
*
* @param annotationClass The annotation type
* @param <T> The annotation generic type
* @return All annotations by the given type
*/
@SuppressWarnings("unchecked")
default @NonNull <T extends Annotation> T[] synthesizeAnnotationsByType(@NonNull Class<T> annotationClass) {
ArgumentUtils.requireNonNull("annotationClass", annotationClass);
return (T[]) Array.newInstance(annotationClass, 0);
}
/**
* Synthesizes a new annotations from the metadata for the given type. This method works
* by creating a runtime proxy of the annotation interface and should be avoided in favour of
* direct use of the annotation metadata and only used for unique cases that require integrating third party libraries.
*
* @param annotationClass The annotation type
* @param <T> The annotation generic type
* @return Declared annotations by the given type
*/
@SuppressWarnings("unchecked")
default @NonNull <T extends Annotation> T[] synthesizeDeclaredAnnotationsByType(@NonNull Class<T> annotationClass) {
ArgumentUtils.requireNonNull("annotationClass", annotationClass);
return (T[]) Array.newInstance(annotationClass, 0);
}
/**
* Find an {@link AnnotationValue} for the given annotation name.
*
* @param annotation The annotation name
* @param <T> The annotation type
* @return A {@link AnnotationValue} instance
*/
default @NonNull <T extends Annotation> Optional<AnnotationValue<T>> findAnnotation(@NonNull String annotation) {
ArgumentUtils.requireNonNull("annotation", annotation);
return Optional.empty();
}
/**
* Find an {@link AnnotationValue} for the given annotation type.
*
* @param annotationClass The annotation
* @param <T> The annotation type
* @return A {@link AnnotationValue} instance
*/
default @NonNull <T extends Annotation> Optional<AnnotationValue<T>> findAnnotation(@NonNull Class<T> annotationClass) {
ArgumentUtils.requireNonNull("annotationClass", annotationClass);
return Optional.empty();
}
/**
* Get all values for the given annotation that are directly declared on the annotated element.
*
* @param annotation The annotation name
* @param <T> The annotation type
* @return A {@link AnnotationValue} instance
*/
default @NonNull <T extends Annotation> Optional<AnnotationValue<T>> findDeclaredAnnotation(@NonNull String annotation) {
ArgumentUtils.requireNonNull("annotation", annotation);
return Optional.empty();
}
/**
* Get all values for the given annotation that are directly declared on the annotated element.
*
* @param annotationClass The annotation name
* @param <T> The annotation type
* @return A {@link AnnotationValue} instance
*/
default @NonNull <T extends Annotation> Optional<AnnotationValue<T>> findDeclaredAnnotation(@NonNull Class<T> annotationClass) {
ArgumentUtils.requireNonNull("annotationClass", annotationClass);
return Optional.empty();
}
/**
* Find an {@link AnnotationValue} for the given annotation name.
*
* @param annotation The annotation name
* @param <T> The annotation type
* @return A {@link AnnotationValue} instance or null
*/
default @Nullable <T extends Annotation> AnnotationValue<T> getAnnotation(@NonNull String annotation) {
ArgumentUtils.requireNonNull("annotation", annotation);
return this.<T>findAnnotation(annotation).orElse(null);
}
/**
* Find an {@link AnnotationValue} for the given annotation name.
*
* @param annotationClass The annotation name
* @param <T> The annotation type
* @return A {@link AnnotationValue} instance or null
*/
default @Nullable <T extends Annotation> AnnotationValue<T> getAnnotation(@NonNull Class<T> annotationClass) {
ArgumentUtils.requireNonNull("annotationClass", annotationClass);
return this.findAnnotation(annotationClass).orElse(null);
}
/**
* Get all values for the given annotation that are directly declared on the annotated element.
*
* @param annotation The annotation name
* @param <T> The annotation type
* @return A {@link AnnotationValue} instance
*/
default @Nullable <T extends Annotation> AnnotationValue<T> getDeclaredAnnotation(@NonNull String annotation) {
ArgumentUtils.requireNonNull("annotation", annotation);
return this.<T>findDeclaredAnnotation(annotation).orElse(null);
}
/**
* Find an {@link AnnotationValue} for the given annotation name.
*
* @param annotationClass The annotation name
* @param <T> The annotation type
* @return A {@link AnnotationValue} instance or null
*/
default @Nullable <T extends Annotation> AnnotationValue<T> getDeclaredAnnotation(@NonNull Class<T> annotationClass) {
ArgumentUtils.requireNonNull("annotationClass", annotationClass);
return this.findDeclaredAnnotation(annotationClass).orElse(null);
}
/**
* Return whether an annotation is present.
*
* @param annotationClass The annotation class
* @return True if it is
*/
default boolean isAnnotationPresent(@NonNull Class<? extends Annotation> annotationClass) {
ArgumentUtils.requireNonNull("annotationClass", annotationClass);
return false;
}
/**
* Variation of {@link #isAnnotationPresent(Class)} for declared annotations.
*
* @param annotationClass The annotation class
* @return True if it is
*/
default boolean isDeclaredAnnotationPresent(@NonNull Class<? extends Annotation> annotationClass) {
ArgumentUtils.requireNonNull("annotationClass", annotationClass);
return false;
}
/**
* Return whether an annotation is present.
*
* @param annotationName The annotation name
* @return True if it is
*/
default boolean isAnnotationPresent(@NonNull String annotationName) {
ArgumentUtils.requireNonNull("annotationClass", annotationName);
return false;
}
/**
* Variation of {@link #isAnnotationPresent(String)} for declared annotations.
*
* @param annotationName The annotation name
* @return True if it is
*/
default boolean isDeclaredAnnotationPresent(@NonNull String annotationName) {
ArgumentUtils.requireNonNull("annotationClass", annotationName);
return false;
}
/**
* Unwraps possible delegate or provider.
* @return unwrapped
* @since 4.0.0
*/
default AnnotationSource getTargetAnnotationMetadata() {
return this;
}
}