package io.micronaut.inject.annotation;
import io.micronaut.context.annotation.AliasFor;
import io.micronaut.context.annotation.Aliases;
import io.micronaut.context.annotation.DefaultScope;
import io.micronaut.core.annotation.*;
import io.micronaut.core.io.service.ServiceDefinition;
import io.micronaut.core.io.service.SoftServiceLoader;
import io.micronaut.core.naming.NameUtils;
import io.micronaut.core.util.CollectionUtils;
import io.micronaut.core.util.StringUtils;
import io.micronaut.core.value.OptionalValues;
import io.micronaut.inject.visitor.VisitorContext;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import javax.inject.Scope;
import java.lang.annotation.Annotation;
import java.lang.annotation.RetentionPolicy;
import java.util.*;
public abstract class AbstractAnnotationMetadataBuilder<T, A> {
private static final Map<String, List<AnnotationMapper<?>>> ANNOTATION_MAPPERS = new HashMap<>(10);
private static final Map<String, List<AnnotationTransformer<Annotation>>> ANNOTATION_TRANSFORMERS = new HashMap<>(5);
private static final Map<String, List<AnnotationRemapper>> ANNOTATION_REMAPPERS = new HashMap<>(5);
private static final Map<MetadataKey, AnnotationMetadata> MUTATED_ANNOTATION_METADATA = new HashMap<>(100);
private static final List<String> DEFAULT_ANNOTATE_EXCLUDES = Arrays.asList(Internal.class.getName(), Experimental.class.getName());
static {
SoftServiceLoader<AnnotationMapper> serviceLoader = SoftServiceLoader.load(AnnotationMapper.class, AbstractAnnotationMetadataBuilder.class.getClassLoader());
for (ServiceDefinition<AnnotationMapper> definition : serviceLoader) {
if (definition.isPresent()) {
AnnotationMapper mapper = definition.load();
try {
String name = null;
if (mapper instanceof TypedAnnotationMapper) {
name = ((TypedAnnotationMapper) mapper).annotationType().getName();
} else if (mapper instanceof NamedAnnotationMapper) {
name = ((NamedAnnotationMapper) mapper).getName();
}
if (StringUtils.isNotEmpty(name)) {
ANNOTATION_MAPPERS.computeIfAbsent(name, s -> new ArrayList<>(2)).add(mapper);
}
} catch (Throwable e) {
}
}
}
SoftServiceLoader<AnnotationTransformer> transformerSoftServiceLoader =
SoftServiceLoader.load(AnnotationTransformer.class, AbstractAnnotationMetadataBuilder.class.getClassLoader());
for (ServiceDefinition<AnnotationTransformer> definition : transformerSoftServiceLoader) {
if (definition.isPresent()) {
AnnotationTransformer transformer = definition.load();
try {
String name = null;
if (transformer instanceof TypedAnnotationTransformer) {
name = ((TypedAnnotationTransformer) transformer).annotationType().getName();
} else if (transformer instanceof NamedAnnotationTransformer) {
name = ((NamedAnnotationTransformer) transformer).getName();
}
if (StringUtils.isNotEmpty(name)) {
ANNOTATION_TRANSFORMERS.computeIfAbsent(name, s -> new ArrayList<>(2)).add(transformer);
}
} catch (Throwable e) {
}
}
}
SoftServiceLoader<AnnotationRemapper> remapperLoader = SoftServiceLoader.load(AnnotationRemapper.class, AbstractAnnotationMetadataBuilder.class.getClassLoader());
for (ServiceDefinition<AnnotationRemapper> definition : remapperLoader) {
if (definition.isPresent()) {
AnnotationRemapper mapper = definition.load();
try {
String name = mapper.getPackageName();
if (StringUtils.isNotEmpty(name)) {
ANNOTATION_REMAPPERS.computeIfAbsent(name, s -> new ArrayList<>(2)).add(mapper);
}
} catch (Throwable e) {
}
}
}
}
private boolean validating = true;
private final Set<T> erroneousElements = new HashSet<>();
protected AbstractAnnotationMetadataBuilder() {
}
public AnnotationMetadata buildDeclared(T element) {
final AnnotationMetadata existing = MUTATED_ANNOTATION_METADATA.get(element);
if (existing != null) {
return existing;
} else {
DefaultAnnotationMetadata annotationMetadata = new DefaultAnnotationMetadata();
try {
AnnotationMetadata metadata = buildInternal(null, element, annotationMetadata, true, true);
if (metadata.isEmpty()) {
return AnnotationMetadata.EMPTY_METADATA;
}
return metadata;
} catch (RuntimeException e) {
if ("org.eclipse.jdt.internal.compiler.problem.AbortCompilation".equals(e.getClass().getName())) {
return AnnotationMetadata.EMPTY_METADATA;
} else {
throw e;
}
}
}
}
public AnnotationMetadata buildOverridden(T element) {
final AnnotationMetadata existing = MUTATED_ANNOTATION_METADATA.get(new MetadataKey(getDeclaringType(element), element));
if (existing != null) {
return existing;
} else {
DefaultAnnotationMetadata annotationMetadata = new DefaultAnnotationMetadata();
try {
AnnotationMetadata metadata = buildInternal(null, element, annotationMetadata, false, false);
if (metadata.isEmpty()) {
return AnnotationMetadata.EMPTY_METADATA;
}
return metadata;
} catch (RuntimeException e) {
if ("org.eclipse.jdt.internal.compiler.problem.AbortCompilation".equals(e.getClass().getName())) {
return AnnotationMetadata.EMPTY_METADATA;
} else {
throw e;
}
}
}
}
public AnnotationMetadata build(T element) {
String declaringType = getDeclaringType(element);
return build(declaringType, element);
}
public AnnotationMetadata build(String declaringType, T element) {
final AnnotationMetadata existing = lookupExisting(declaringType, element);
if (existing != null) {
return existing;
} else {
DefaultAnnotationMetadata annotationMetadata = new DefaultAnnotationMetadata();
try {
AnnotationMetadata metadata = buildInternal(null, element, annotationMetadata, true, false);
if (metadata.isEmpty()) {
return AnnotationMetadata.EMPTY_METADATA;
}
return metadata;
} catch (RuntimeException e) {
if ("org.eclipse.jdt.internal.compiler.problem.AbortCompilation".equals(e.getClass().getName())) {
return AnnotationMetadata.EMPTY_METADATA;
} else {
throw e;
}
}
}
}
protected abstract boolean isMethodOrClassElement(T element);
protected abstract @NonNull String getDeclaringType(@NonNull T element);
public AnnotationMetadata buildForMethod(T element) {
String declaringType = getDeclaringType(element);
final AnnotationMetadata existing = lookupExisting(declaringType, element);
if (existing != null) {
return existing;
} else {
DefaultAnnotationMetadata annotationMetadata = new DefaultAnnotationMetadata();
return buildInternal(null, element, annotationMetadata, false, false);
}
}
public AnnotationMetadata buildForParent(T parent, T element) {
String declaringType = getDeclaringType(element);
return buildForParent(declaringType, parent, element);
}
public AnnotationMetadata buildForParent(String declaringType, T parent, T element) {
final AnnotationMetadata existing = lookupExisting(declaringType, element);
DefaultAnnotationMetadata annotationMetadata;
if (existing instanceof DefaultAnnotationMetadata) {
annotationMetadata = ((DefaultAnnotationMetadata) existing).clone();
} else if (existing instanceof AnnotationMetadataHierarchy) {
final AnnotationMetadata declaredMetadata = ((AnnotationMetadataHierarchy) existing).getDeclaredMetadata();
if (declaredMetadata instanceof DefaultAnnotationMetadata) {
annotationMetadata = ((DefaultAnnotationMetadata) declaredMetadata).clone();
} else {
annotationMetadata = new DefaultAnnotationMetadata();
}
} else {
annotationMetadata = new DefaultAnnotationMetadata();
}
return buildInternal(parent, element, annotationMetadata, false, false);
}
public AnnotationMetadata buildForParent(T parent, T element, boolean inheritTypeAnnotations) {
String declaringType = getDeclaringType(element);
final AnnotationMetadata existing = lookupExisting(declaringType, element);
DefaultAnnotationMetadata annotationMetadata;
if (existing instanceof DefaultAnnotationMetadata) {
annotationMetadata = ((DefaultAnnotationMetadata) existing).clone();
} else {
annotationMetadata = new DefaultAnnotationMetadata();
}
return buildInternal(parent, element, annotationMetadata, inheritTypeAnnotations, false);
}
protected abstract T getTypeForAnnotation(A annotationMirror);
protected abstract boolean hasAnnotation(T element, Class<? extends Annotation> annotation);
protected abstract String getAnnotationTypeName(A annotationMirror);
protected abstract String getElementName(T element);
protected abstract List<? extends A> getAnnotationsForType(T element);
protected abstract List<T> buildHierarchy(T element, boolean inheritTypeAnnotations, boolean declaredOnly);
protected abstract void readAnnotationRawValues(
T originatingElement,
String annotationName,
T member,
String memberName,
Object annotationValue,
Map<CharSequence, Object> annotationValues);
protected void validateAnnotationValue(T originatingElement, String annotationName, T member, String memberName, Object resolvedValue) {
if (!validating) {
return;
}
final AnnotatedElementValidator elementValidator = getElementValidator();
if (elementValidator != null && !erroneousElements.contains(member)) {
final boolean shouldValidate = !(annotationName.equals(AliasFor.class.getName())) &&
(!(resolvedValue instanceof String) || !resolvedValue.toString().contains("${"));
if (shouldValidate) {
AnnotationMetadata metadata;
try {
validating = false;
metadata = buildDeclared(member);
} finally {
validating = true;
}
final Set<String> errors = elementValidator.validatedAnnotatedElement(new AnnotatedElement() {
@NonNull
@Override
public String getName() {
return memberName;
}
@Override
public AnnotationMetadata getAnnotationMetadata() {
return metadata;
}
}, resolvedValue);
if (CollectionUtils.isNotEmpty(errors)) {
erroneousElements.add(member);
for (String error : errors) {
error = "@" + NameUtils.getSimpleName(annotationName) + "." + memberName + ": " + error;
addError(originatingElement, error);
}
}
}
}
}
protected @Nullable
AnnotatedElementValidator getElementValidator() {
return null;
}
protected abstract void addError(@NonNull T originatingElement, @NonNull String error);
protected abstract Object readAnnotationValue(T originatingElement, T member, String memberName, Object annotationValue);
protected abstract Map<? extends T, ?> readAnnotationDefaultValues(A annotationMirror);
protected abstract Map<? extends T, ?> readAnnotationDefaultValues(String annotationName, T annotationType);
protected abstract Map<? extends T, ?> readAnnotationRawValues(A annotationMirror);
protected abstract OptionalValues<?> getAnnotationValues(T originatingElement, T member, Class<?> annotationType);
protected abstract String getAnnotationMemberName(T member);
protected abstract @Nullable
String getRepeatableName(A annotationMirror);
protected abstract @Nullable
String getRepeatableNameForType(T annotationType);
protected io.micronaut.core.annotation.AnnotationValue readNestedAnnotationValue(T originatingElement, A annotationMirror) {
io.micronaut.core.annotation.AnnotationValue av;
Map<? extends T, ?> annotationValues = readAnnotationRawValues(annotationMirror);
final String annotationTypeName = getAnnotationTypeName(annotationMirror);
if (annotationValues.isEmpty()) {
av = new io.micronaut.core.annotation.AnnotationValue(annotationTypeName);
} else {
Map<CharSequence, Object> resolvedValues = new LinkedHashMap<>();
for (Map.Entry<? extends T, ?> entry : annotationValues.entrySet()) {
T member = entry.getKey();
OptionalValues<?> aliasForValues = getAnnotationValues(originatingElement, member, AliasFor.class);
Object annotationValue = entry.getValue();
Optional<?> aliasMember = aliasForValues.get("member");
Optional<?> aliasAnnotation = aliasForValues.get("annotation");
Optional<?> aliasAnnotationName = aliasForValues.get("annotationName");
if (aliasMember.isPresent() && !(aliasAnnotation.isPresent() || aliasAnnotationName.isPresent())) {
String aliasedNamed = aliasMember.get().toString();
readAnnotationRawValues(originatingElement, annotationTypeName, member, aliasedNamed, annotationValue, resolvedValues);
}
String memberName = getAnnotationMemberName(member);
readAnnotationRawValues(originatingElement, annotationTypeName, member, memberName, annotationValue, resolvedValues);
}
av = new io.micronaut.core.annotation.AnnotationValue(annotationTypeName, resolvedValues);
}
return av;
}
protected abstract Optional<T> getAnnotationMirror(String annotationName);
protected Map<CharSequence, Object> populateAnnotationData(
T originatingElement,
A annotationMirror,
DefaultAnnotationMetadata metadata,
boolean isDeclared,
RetentionPolicy retentionPolicy) {
String annotationName = getAnnotationTypeName(annotationMirror);
if (retentionPolicy == RetentionPolicy.RUNTIME) {
processAnnotationDefaults(originatingElement, annotationMirror, metadata, annotationName);
}
List<String> parentAnnotations = new ArrayList<>();
parentAnnotations.add(annotationName);
Map<? extends T, ?> elementValues = readAnnotationRawValues(annotationMirror);
Map<CharSequence, Object> annotationValues;
if (CollectionUtils.isEmpty(elementValues)) {
annotationValues = new LinkedHashMap<>(3);
} else {
annotationValues = new LinkedHashMap<>(5);
for (Map.Entry<? extends T, ?> entry : elementValues.entrySet()) {
T member = entry.getKey();
if (member == null) {
continue;
}
boolean isInstantiatedMember = hasAnnotation(member, InstantiatedMember.class);
Object annotationValue = entry.getValue();
if (isInstantiatedMember) {
final String memberName = getAnnotationMemberName(member);
final Object rawValue = readAnnotationValue(originatingElement, member, memberName, annotationValue);
if (rawValue instanceof AnnotationClassValue) {
AnnotationClassValue acv = (AnnotationClassValue) rawValue;
annotationValues.put(memberName, new AnnotationClassValue(acv.getName(), true));
}
} else {
handleAnnotationAlias(
originatingElement,
metadata,
isDeclared,
annotationName,
parentAnnotations,
annotationValues,
member,
annotationValue
);
}
}
}
List<AnnotationMapper<?>> mappers = getAnnotationMappers(annotationName);
if (mappers != null) {
AnnotationValue<?> annotationValue = new AnnotationValue(annotationName, annotationValues);
VisitorContext visitorContext = createVisitorContext();
for (AnnotationMapper mapper : mappers) {
List mapped = mapper.map(annotationValue, visitorContext);
if (mapped != null) {
for (Object o : mapped) {
if (o instanceof AnnotationValue) {
AnnotationValue av = (AnnotationValue) o;
retentionPolicy = av.getRetentionPolicy();
String mappedAnnotationName = av.getAnnotationName();
Optional<T> mappedMirror = getAnnotationMirror(mappedAnnotationName);
String repeatableName = mappedMirror.map(this::getRepeatableNameForType).orElse(null);
if (repeatableName != null) {
if (isDeclared) {
metadata.addDeclaredRepeatable(
repeatableName,
av,
retentionPolicy
);
} else {
metadata.addRepeatable(
repeatableName,
av,
retentionPolicy
);
}
} else {
Map<CharSequence, Object> values = av.getValues();
if (isDeclared) {
metadata.addDeclaredAnnotation(
mappedAnnotationName,
values,
retentionPolicy
);
} else {
metadata.addAnnotation(
mappedAnnotationName,
values,
retentionPolicy
);
}
}
RetentionPolicy finalRetentionPolicy = retentionPolicy;
mappedMirror.ifPresent(annMirror -> {
Map<CharSequence, Object> values = av.getValues();
values.forEach((key, value) -> {
T member = getAnnotationMember(annMirror, key);
if (member != null) {
handleAnnotationAlias(
originatingElement,
metadata,
isDeclared,
mappedAnnotationName,
Collections.emptyList(),
annotationValues,
member,
value
);
}
});
final Map<? extends T, ?> defaultValues = readAnnotationDefaultValues(mappedAnnotationName, annMirror);
if (finalRetentionPolicy == RetentionPolicy.RUNTIME) {
processAnnotationDefaults(originatingElement, metadata, mappedAnnotationName, defaultValues);
}
final ArrayList<String> parents = new ArrayList<>();
processAnnotationStereotype(
parents,
annMirror,
mappedAnnotationName,
metadata,
isDeclared);
});
}
}
}
}
}
return annotationValues;
}
private void handleAnnotationAlias(T originatingElement, DefaultAnnotationMetadata metadata, boolean isDeclared, String annotationName, List<String> parentAnnotations, Map<CharSequence, Object> annotationValues, T member, Object annotationValue) {
Optional<?> aliases = getAnnotationValues(originatingElement, member, Aliases.class).get("value");
if (aliases.isPresent()) {
Object value = aliases.get();
if (value instanceof AnnotationValue[]) {
AnnotationValue[] values = (AnnotationValue[]) value;
for (AnnotationValue av : values) {
OptionalValues<Object> aliasForValues = OptionalValues.of(Object.class, av.getValues());
processAnnotationAlias(
originatingElement,
annotationName,
member, metadata,
isDeclared,
parentAnnotations,
annotationValues,
annotationValue,
aliasForValues
);
}
}
readAnnotationRawValues(originatingElement, annotationName, member, getAnnotationMemberName(member), annotationValue, annotationValues);
} else {
OptionalValues<?> aliasForValues = getAnnotationValues(
originatingElement,
member,
AliasFor.class
);
processAnnotationAlias(
originatingElement,
annotationName,
member,
metadata,
isDeclared,
parentAnnotations,
annotationValues,
annotationValue,
aliasForValues
);
readAnnotationRawValues(originatingElement, annotationName, member, getAnnotationMemberName(member), annotationValue, annotationValues);
}
}
protected abstract @Nullable T getAnnotationMember(T originatingElement, CharSequence member);
protected @NonNull List<AnnotationMapper<? extends Annotation>> getAnnotationMappers(@NonNull String annotationName) {
return ANNOTATION_MAPPERS.get(annotationName);
}
protected abstract VisitorContext createVisitorContext();
private void processAnnotationDefaults(T originatingElement, A annotationMirror, DefaultAnnotationMetadata metadata, String annotationName) {
Map<? extends T, ?> elementDefaultValues = readAnnotationDefaultValues(annotationMirror);
processAnnotationDefaults(originatingElement, metadata, annotationName, elementDefaultValues);
}
private void processAnnotationDefaults(T originatingElement, DefaultAnnotationMetadata metadata, String annotationName, Map<? extends T, ?> elementDefaultValues) {
if (elementDefaultValues != null) {
Map<CharSequence, Object> defaultValues = new LinkedHashMap<>();
for (Map.Entry<? extends T, ?> entry : elementDefaultValues.entrySet()) {
T member = entry.getKey();
String memberName = getAnnotationMemberName(member);
if (!defaultValues.containsKey(memberName)) {
Object annotationValue = entry.getValue();
readAnnotationRawValues(originatingElement, annotationName, member, memberName, annotationValue, defaultValues);
}
}
metadata.addDefaultAnnotationValues(annotationName, defaultValues);
Map<String, Object> annotationDefaults = new HashMap<>(defaultValues.size());
for (Map.Entry<CharSequence, Object> entry : defaultValues.entrySet()) {
annotationDefaults.put(entry.getKey().toString(), entry.getValue());
}
DefaultAnnotationMetadata.registerAnnotationDefaults(annotationName, annotationDefaults);
} else {
metadata.addDefaultAnnotationValues(annotationName, Collections.emptyMap());
}
}
private AnnotationMetadata lookupExisting(String declaringType, T element) {
return MUTATED_ANNOTATION_METADATA.get(new MetadataKey(declaringType, element));
}
private void processAnnotationAlias(
T originatingElement, String annotationName,
T member,
DefaultAnnotationMetadata metadata,
boolean isDeclared,
List<String> parentAnnotations,
Map<CharSequence, Object> annotationValues,
Object annotationValue,
OptionalValues<?> aliasForValues) {
Optional<?> aliasAnnotation = aliasForValues.get("annotation");
Optional<?> aliasAnnotationName = aliasForValues.get("annotationName");
Optional<?> aliasMember = aliasForValues.get("member");
if (aliasAnnotation.isPresent() || aliasAnnotationName.isPresent()) {
if (aliasMember.isPresent()) {
String aliasedAnnotationName;
if (aliasAnnotation.isPresent()) {
aliasedAnnotationName = aliasAnnotation.get().toString();
} else {
aliasedAnnotationName = aliasAnnotationName.get().toString();
}
String aliasedMemberName = aliasMember.get().toString();
Object v = readAnnotationValue(originatingElement, member, aliasedMemberName, annotationValue);
if (v != null) {
Optional<T> annotationMirror = getAnnotationMirror(aliasedAnnotationName);
RetentionPolicy retentionPolicy = RetentionPolicy.RUNTIME;
if (annotationMirror.isPresent()) {
final T annotationTypeMirror = annotationMirror.get();
final Map<? extends T, ?> defaultValues = readAnnotationDefaultValues(aliasedAnnotationName, annotationTypeMirror);
processAnnotationDefaults(originatingElement, metadata, aliasedAnnotationName, defaultValues);
retentionPolicy = getRetentionPolicy(annotationTypeMirror);
}
if (isDeclared) {
metadata.addDeclaredStereotype(
parentAnnotations,
aliasedAnnotationName,
Collections.singletonMap(aliasedMemberName, v),
retentionPolicy
);
} else {
metadata.addStereotype(
parentAnnotations,
aliasedAnnotationName,
Collections.singletonMap(aliasedMemberName, v),
retentionPolicy
);
}
annotationMirror.ifPresent(annMirror -> processAnnotationStereotype(
parentAnnotations,
annMirror,
aliasedAnnotationName,
metadata,
isDeclared
));
}
}
} else if (aliasMember.isPresent()) {
String aliasedNamed = aliasMember.get().toString();
Object v = readAnnotationValue(originatingElement, member, aliasedNamed, annotationValue);
if (v != null) {
annotationValues.put(aliasedNamed, v);
}
readAnnotationRawValues(originatingElement, annotationName, member, aliasedNamed, annotationValue, annotationValues);
}
}
protected abstract @NonNull
RetentionPolicy getRetentionPolicy(@NonNull T annotation);
private AnnotationMetadata buildInternal(T parent, T element, DefaultAnnotationMetadata annotationMetadata, boolean inheritTypeAnnotations, boolean declaredOnly) {
List<T> hierarchy = buildHierarchy(element, inheritTypeAnnotations, declaredOnly);
if (parent != null) {
final List<T> parentHierarchy = buildHierarchy(parent, inheritTypeAnnotations, declaredOnly);
hierarchy.addAll(0, parentHierarchy);
}
Collections.reverse(hierarchy);
for (T currentElement : hierarchy) {
if (currentElement == null) {
continue;
}
List<? extends A> annotationHierarchy = getAnnotationsForType(currentElement);
if (annotationHierarchy.isEmpty()) {
continue;
}
boolean isDeclared = currentElement == element;
for (A annotationMirror : annotationHierarchy) {
String annotationName = getAnnotationTypeName(annotationMirror);
if (AnnotationUtil.INTERNAL_ANNOTATION_NAMES.contains(annotationName)) {
continue;
}
final T annotationType = getTypeForAnnotation(annotationMirror);
RetentionPolicy retentionPolicy = getRetentionPolicy(annotationType);
Map<CharSequence, Object> annotationValues = populateAnnotationData(currentElement, annotationMirror, annotationMetadata, isDeclared, retentionPolicy);
String repeatableName = getRepeatableName(annotationMirror);
String packageName = NameUtils.getPackageName(annotationName);
List<AnnotationRemapper> annotationRemappers = ANNOTATION_REMAPPERS.get(packageName);
List<AnnotationTransformer<Annotation>> annotationTransformers = ANNOTATION_TRANSFORMERS.get(annotationName);
boolean remapped = CollectionUtils.isNotEmpty(annotationRemappers);
boolean transformed = CollectionUtils.isNotEmpty(annotationTransformers);
if (repeatableName != null) {
if (!remapped && !transformed) {
io.micronaut.core.annotation.AnnotationValue av = new io.micronaut.core.annotation.AnnotationValue(annotationName, annotationValues);
if (isDeclared) {
annotationMetadata.addDeclaredRepeatable(repeatableName, av);
} else {
annotationMetadata.addRepeatable(repeatableName, av);
}
} else if (remapped) {
AnnotationValue repeatableAnn = new AnnotationValue(repeatableName);
VisitorContext visitorContext = createVisitorContext();
io.micronaut.core.annotation.AnnotationValue av = new io.micronaut.core.annotation.AnnotationValue(annotationName, annotationValues);
for (AnnotationRemapper annotationRemapper : annotationRemappers) {
List<AnnotationValue<?>> remappedRepeatable = annotationRemapper.remap(repeatableAnn, visitorContext);
List<AnnotationValue<?>> remappedValue = annotationRemapper.remap(av, visitorContext);
if (CollectionUtils.isNotEmpty(remappedRepeatable)) {
for (AnnotationValue<?> repeatable : remappedRepeatable) {
for (AnnotationValue<?> rmv : remappedValue) {
if (isDeclared) {
annotationMetadata.addDeclaredRepeatable(repeatable.getAnnotationName(), rmv);
} else {
annotationMetadata.addRepeatable(repeatable.getAnnotationName(), rmv);
}
}
}
}
}
} else {
AnnotationValue<Annotation> repeatableAnn = new AnnotationValue<>(repeatableName);
VisitorContext visitorContext = createVisitorContext();
io.micronaut.core.annotation.AnnotationValue<Annotation> av =
new io.micronaut.core.annotation.AnnotationValue<>(annotationName, annotationValues);
final List<AnnotationTransformer<Annotation>> repeatableTransformers = ANNOTATION_TRANSFORMERS.get(repeatableName);
if (CollectionUtils.isNotEmpty(repeatableTransformers)) {
for (AnnotationTransformer<Annotation> repeatableTransformer : repeatableTransformers) {
final List<AnnotationValue<?>> transformedRepeatable = repeatableTransformer.transform(repeatableAnn, visitorContext);
for (AnnotationValue<?> annotationValue : transformedRepeatable) {
for (AnnotationTransformer<Annotation> transformer : annotationTransformers) {
final List<AnnotationValue<?>> tav = transformer.transform(av, visitorContext);
for (AnnotationValue<?> value : tav) {
if (isDeclared) {
annotationMetadata.addDeclaredRepeatable(annotationValue.getAnnotationName(), value);
} else {
annotationMetadata.addRepeatable(annotationValue.getAnnotationName(), value);
}
}
}
}
}
} else {
for (AnnotationTransformer<Annotation> transformer : annotationTransformers) {
final List<AnnotationValue<?>> tav = transformer.transform(av, visitorContext);
for (AnnotationValue<?> value : tav) {
if (isDeclared) {
annotationMetadata.addDeclaredRepeatable(repeatableName, value);
} else {
annotationMetadata.addRepeatable(repeatableName, value);
}
}
}
}
}
} else {
if (!remapped && !transformed) {
if (isDeclared) {
annotationMetadata.addDeclaredAnnotation(annotationName, annotationValues, retentionPolicy);
} else {
annotationMetadata.addAnnotation(annotationName, annotationValues, retentionPolicy);
}
} else if (remapped) {
io.micronaut.core.annotation.AnnotationValue av = new io.micronaut.core.annotation.AnnotationValue(annotationName, annotationValues);
VisitorContext visitorContext = createVisitorContext();
for (AnnotationRemapper annotationRemapper : annotationRemappers) {
List<AnnotationValue<?>> remappedValues = annotationRemapper.remap(av, visitorContext);
if (CollectionUtils.isNotEmpty(remappedValues)) {
for (AnnotationValue<?> annotationValue : remappedValues) {
if (isDeclared) {
annotationMetadata.addDeclaredAnnotation(annotationValue.getAnnotationName(), annotationValue.getValues());
} else {
annotationMetadata.addAnnotation(annotationValue.getAnnotationName(), annotationValue.getValues());
}
}
}
}
} else {
io.micronaut.core.annotation.AnnotationValue<Annotation> av =
new io.micronaut.core.annotation.AnnotationValue<>(annotationName, annotationValues);
VisitorContext visitorContext = createVisitorContext();
for (AnnotationTransformer<Annotation> annotationTransformer : annotationTransformers) {
final List<AnnotationValue<?>> transformedValues = annotationTransformer.transform(av, visitorContext);
for (AnnotationValue<?> transformedValue : transformedValues) {
if (isDeclared) {
annotationMetadata.addDeclaredAnnotation(
transformedValue.getAnnotationName(),
transformedValue.getValues(),
transformedValue.getRetentionPolicy()
);
} else {
annotationMetadata.addAnnotation(
transformedValue.getAnnotationName(),
transformedValue.getValues(),
transformedValue.getRetentionPolicy()
);
}
}
}
}
}
}
for (A annotationMirror : annotationHierarchy) {
String annotationTypeName = getAnnotationTypeName(annotationMirror);
String packageName = NameUtils.getPackageName(annotationTypeName);
if (!AnnotationUtil.STEREOTYPE_EXCLUDES.contains(packageName)) {
processAnnotationStereotype(annotationMirror, annotationMetadata, isDeclared);
}
}
}
if (!annotationMetadata.hasDeclaredStereotype(Scope.class) && annotationMetadata.hasDeclaredStereotype(DefaultScope.class)) {
Optional<String> value = annotationMetadata.stringValue(DefaultScope.class);
value.ifPresent(name -> annotationMetadata.addDeclaredAnnotation(name, Collections.emptyMap()));
}
return annotationMetadata;
}
private void buildStereotypeHierarchy(List<String> parents, T element, DefaultAnnotationMetadata metadata, boolean isDeclared, List<String> excludes) {
List<? extends A> annotationMirrors = getAnnotationsForType(element);
if (!annotationMirrors.isEmpty()) {
List<A> topLevel = new ArrayList<>();
for (A annotationMirror : annotationMirrors) {
String annotationName = getAnnotationTypeName(annotationMirror);
if (annotationName.equals(getElementName(element))) {
continue;
}
if (!AnnotationUtil.INTERNAL_ANNOTATION_NAMES.contains(annotationName) && !excludes.contains(annotationName)) {
final T annotationTypeMirror = getTypeForAnnotation(annotationMirror);
final RetentionPolicy retentionPolicy = getRetentionPolicy(annotationTypeMirror);
topLevel.add(annotationMirror);
Map<CharSequence, Object> data = populateAnnotationData(element, annotationMirror, metadata, isDeclared, retentionPolicy);
String repeatableName = getRepeatableName(annotationMirror);
if (repeatableName != null) {
io.micronaut.core.annotation.AnnotationValue av = new io.micronaut.core.annotation.AnnotationValue(annotationName, data);
if (isDeclared) {
metadata.addDeclaredRepeatableStereotype(parents, repeatableName, av);
} else {
metadata.addRepeatableStereotype(parents, repeatableName, av);
}
} else {
if (isDeclared) {
metadata.addDeclaredStereotype(parents, annotationName, data, retentionPolicy);
} else {
metadata.addStereotype(parents, annotationName, data, retentionPolicy);
}
}
}
}
for (A annotationMirror : topLevel) {
processAnnotationStereotype(parents, annotationMirror, metadata, isDeclared);
}
}
}
private void processAnnotationStereotype(A annotationMirror, DefaultAnnotationMetadata annotationMetadata, boolean isDeclared) {
T annotationType = getTypeForAnnotation(annotationMirror);
String parentAnnotationName = getAnnotationTypeName(annotationMirror);
if (!parentAnnotationName.endsWith(".Nullable")) {
processAnnotationStereotypes(annotationMetadata, isDeclared, annotationType, parentAnnotationName, Collections.emptyList());
}
}
private void processAnnotationStereotypes(DefaultAnnotationMetadata annotationMetadata, boolean isDeclared, T annotationType, String annotationName, List<String> excludes) {
List<String> parentAnnotations = new ArrayList<>();
parentAnnotations.add(annotationName);
buildStereotypeHierarchy(
parentAnnotations,
annotationType,
annotationMetadata,
isDeclared,
excludes
);
}
private void processAnnotationStereotype(List<String> parents, A annotationMirror, DefaultAnnotationMetadata metadata, boolean isDeclared) {
T typeForAnnotation = getTypeForAnnotation(annotationMirror);
String annotationTypeName = getAnnotationTypeName(annotationMirror);
processAnnotationStereotype(parents, typeForAnnotation, annotationTypeName, metadata, isDeclared);
}
private void processAnnotationStereotype(List<String> parents, T annotationType, String annotationTypeName, DefaultAnnotationMetadata metadata, boolean isDeclared) {
List<String> stereoTypeParents = new ArrayList<>(parents);
stereoTypeParents.add(annotationTypeName);
buildStereotypeHierarchy(stereoTypeParents, annotationType, metadata, isDeclared, Collections.emptyList());
}
@Internal
public static void addMutatedMetadata(String declaringType, Object element, AnnotationMetadata metadata) {
if (element != null && metadata != null) {
MUTATED_ANNOTATION_METADATA.put(new MetadataKey(declaringType, element), metadata);
}
}
@Internal
public static boolean isMetadataMutated(String declaringType, Object element) {
if (element != null) {
return MUTATED_ANNOTATION_METADATA.containsKey(new MetadataKey(declaringType, element));
}
return false;
}
@Internal
public static void clearMutated() {
MUTATED_ANNOTATION_METADATA.clear();
}
@Internal
public static boolean isAnnotationMapped(@Nullable String annotationName) {
return annotationName != null && ANNOTATION_MAPPERS.containsKey(annotationName);
}
@Internal
public static Set<String> getMappedAnnotationNames() {
return ANNOTATION_MAPPERS.keySet();
}
public <A2 extends Annotation> AnnotationMetadata annotate(
AnnotationMetadata annotationMetadata,
AnnotationValue<A2> annotationValue) {
String annotationName = annotationValue.getAnnotationName();
if (annotationMetadata instanceof DefaultAnnotationMetadata) {
final Optional<T> annotationMirror = getAnnotationMirror(annotationName);
final DefaultAnnotationMetadata defaultMetadata = (DefaultAnnotationMetadata) annotationMetadata;
defaultMetadata.addDeclaredAnnotation(
annotationName,
annotationValue.getValues()
);
annotationMirror.ifPresent(annotationType -> {
final Map<? extends T, ?> defaultValues = readAnnotationDefaultValues(annotationName, annotationType);
processAnnotationDefaults(
annotationType,
defaultMetadata,
annotationName,
defaultValues
);
processAnnotationStereotypes(
defaultMetadata,
true,
annotationType,
annotationName,
DEFAULT_ANNOTATE_EXCLUDES
);
});
} else if (annotationMetadata instanceof AnnotationMetadataHierarchy) {
AnnotationMetadataHierarchy hierarchy = (AnnotationMetadataHierarchy) annotationMetadata;
AnnotationMetadata declaredMetadata = annotate(hierarchy.getDeclaredMetadata(), annotationValue);
return hierarchy.createSibling(
declaredMetadata
);
} else if (annotationMetadata == AnnotationMetadata.EMPTY_METADATA) {
final Optional<T> annotationMirror = getAnnotationMirror(annotationName);
final Map<CharSequence, Object> values = annotationValue.getValues();
final Map<String, Map<CharSequence, Object>> declared = new HashMap<>(1);
declared.put(annotationName, values);
final DefaultAnnotationMetadata newMetadata = new DefaultAnnotationMetadata(
declared,
null,
null,
declared,
null
);
annotationMirror.ifPresent(annotationType ->
processAnnotationStereotypes(
newMetadata,
true,
annotationType,
annotationName,
DEFAULT_ANNOTATE_EXCLUDES
)
);
return newMetadata;
}
return annotationMetadata;
}
private static class MetadataKey<T> {
final String declaringName;
final T element;
MetadataKey(String declaringName, T element) {
this.declaringName = declaringName;
this.element = element;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
MetadataKey that = (MetadataKey) o;
return declaringName.equals(that.declaringName) &&
element.equals(that.element);
}
@Override
public int hashCode() {
return Objects.hash(declaringName, element);
}
}
}