io.micronaut.annotation.processing.MixinVisitorProcessor Maven / Gradle / Ivy
/*
* Copyright 2017-2025 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.annotation.processing;
import io.micronaut.annotation.processing.visitor.JavaClassElement;
import io.micronaut.annotation.processing.visitor.JavaElementFactory;
import io.micronaut.annotation.processing.visitor.JavaNativeElement;
import io.micronaut.context.annotation.Mixin;
import io.micronaut.context.visitor.VisitorUtils;
import io.micronaut.core.annotation.AnnotationValue;
import io.micronaut.core.annotation.Generated;
import io.micronaut.inject.annotation.AbstractAnnotationMetadataBuilder;
import io.micronaut.inject.processing.ProcessingException;
import io.micronaut.inject.visitor.ElementPostponedToNextRoundException;
import io.micronaut.inject.visitor.VisitorContext;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedOptions;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
/**
* The annotation processed used to process the mixins first.
*
* @author Denis Stepanov
* @since 4.9
*/
@SupportedOptions({
AbstractInjectAnnotationProcessor.MICRONAUT_PROCESSING_INCREMENTAL,
AbstractInjectAnnotationProcessor.MICRONAUT_PROCESSING_ANNOTATIONS,
VisitorContext.MICRONAUT_PROCESSING_PROJECT_DIR,
VisitorContext.MICRONAUT_PROCESSING_GROUP,
VisitorContext.MICRONAUT_PROCESSING_MODULE
})
public class MixinVisitorProcessor extends AbstractInjectAnnotationProcessor {
@Override
public Set getSupportedAnnotationTypes() {
return Set.of(Mixin.class.getName());
}
@Override
public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (!(annotations.size() == 1 && Generated.class.getName().equals(annotations.iterator().next().getQualifiedName().toString()))) {
for (Object nativeType : postponedTypes.values()) {
AbstractAnnotationMetadataBuilder.clearMutated(nativeType);
}
var elements = new LinkedHashSet();
postponedTypes.keySet().stream().map(elementUtils::getTypeElement).filter(Objects::nonNull).forEach(elements::add);
postponedTypes.clear();
JavaElementFactory elementFactory = javaVisitorContext.getElementFactory();
JavaElementAnnotationMetadataFactory elementAnnotationMetadataFactory = javaVisitorContext.getElementAnnotationMetadataFactory();
for (TypeElement annotation : annotations) {
modelUtils.resolveTypeElements(
roundEnv.getElementsAnnotatedWith(annotation)
).forEach(elements::add);
}
List javaClassElements = elements.stream()
.map(typeElement -> elementFactory.newSourceClassElement(typeElement, elementAnnotationMetadataFactory))
.toList();
for (JavaClassElement mixin : javaClassElements) {
try {
AnnotationValue mixinAnnotation = mixin.getAnnotation(Mixin.class);
if (mixinAnnotation == null) {
continue;
}
String target = mixinAnnotation.stringValue("target").orElse(mixinAnnotation.stringValue().orElse(null));
if (target == null || Object.class.getName().equals(target)) {
continue;
}
TypeElement targetTypeElement = elementUtils.getTypeElement(target);
if (targetTypeElement == null) {
continue;
}
JavaClassElement mixinTarget = elementFactory.newSourceClassElement(targetTypeElement, elementAnnotationMetadataFactory);
VisitorUtils.applyMixin(mixinAnnotation, mixin, mixinTarget);
} catch (ProcessingException e) {
var originatingElement = (JavaNativeElement) e.getOriginatingElement();
if (originatingElement == null) {
originatingElement = mixin.getNativeType();
}
error(originatingElement.element(), e.getMessage());
} catch (PostponeToNextRoundException e) {
postponedTypes.put(mixin.getCanonicalName(), e.getNativeErrorElement());
} catch (ElementPostponedToNextRoundException e) {
Object nativeType = e.getOriginatingElement().getNativeType();
Element element = PostponeToNextRoundException.resolvedFailedElement(nativeType);
if (element != null) {
postponedTypes.put(mixin.getCanonicalName(), element);
} else {
// should never happen.
throw e;
}
}
}
}
if (roundEnv.processingOver()) {
javaVisitorContext.finish();
}
return false;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy