注解处理器编译时未触发,存在注解误用类
自定义注解处理器未触发问题
我在练习自定义数据结构时,定义了Implementation注解,用于标记抽象实现类或具体实现类:当标记为具体实现时,要求类继承AbstractDataEngine并提供实现Iterator的内部类。
1. Implementation注解定义
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * A marker annotation, forces the class which is to be defined as a data engine, to * extend {@code AbstractDataEngine} or any of its subclasses and provide an {@code Iterator} * implementation. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Implementation { ImplementationType value(); enum ImplementationType { ABSTRACTION, IMPLEMENTATION; @Override public String toString() { return switch (this){ case ABSTRACTION -> "abstraction"; case IMPLEMENTATION -> "implementation"; }; } } }
2. AbstractDataEngine类定义
import java.util.concurrent.atomic.AtomicReference; /** * This class defines methods, that will be common to every single data engine, irrespective of type of * data structure, or its implementation * @param <E> Type of data being stored */ @Implementation(Implementation.ImplementationType.ABSTRACTION) public abstract class AbstractDataEngine<E> implements DataEngine<E>, Iterable<E>{ //The golden ratio,, generally used as a growth factor for determining new size protected final double GOLDEN_RATIO = 1.61803398875; //Only for array-based protected final double DEFAULT_CAPACITY = 16; protected final double GROWTH_LOAD_FACTOR = 0.75; protected final double SHRINK_LOAD_FACTOR = 0.25; protected int activeSize; protected int maxCapacity; protected AbstractDataEngine(int activeSize, int maxCapacity){ this.activeSize = activeSize; this.maxCapacity = maxCapacity; } /** * When invoked on a data engine that implements an underlying array, will shift all the elements * to the beginning, i.e. a sparsely populated array can be so adjusted that all the elements * get move to the front * */ protected abstract void compress(); /** * When the {@code activeSize} is less than {@code SHRINK_LOAD_FACTOR * maxCapacity}, for an * underlying array it will end up shrinking by {@code maxCapacity - Math.floor(GOLDEN_RATIO * maxCapacity)} * Cam have an asynchronous implementation in thread-safe data engines. * */ protected abstract void shrink(); /** * When the {@code activeSize} is greater than {@code GROWTh_LOAD_FACTOR * maxCapacity}, for an * underlying array it will end up growing by {@code maxCapacity - Math.floor(GOLDEN_RATIO * maxCapacity)} * Cam have an asynchronous implementation in thread-safe data engines. * */ protected abstract void grow(); /** * @return Returns true, if the invoking data engine is empty, false otherwise */ @Override public boolean isEmpty() { return this.activeSize == 0; } /** * @return Returns max capacity of the data engine, or the max size before growth */ @Override public int maxCapacity() { return this.maxCapacity; } /** * @return Returns current size of data engine */ @Override public int getActiveSize() { return this.activeSize; } /** * Generates an {@code AtomicReference} of the data engine. Useful when the object has to be * used in a thread blocking context without making the data engine asynchronous. * * @return Returns an {@code AtomicReference} of the invoking data engine * @throws UnsupportedOperationException Will throw an exception when the invoking data engine is * already {@code Thread-Mutable} */ @Override @SuppressWarnings("unchecked") public <T extends DataEngine<E>> AtomicReference<T> createThreadSafeImage() { return new AtomicReference<>((T)this); } /** * The method reverses the invoking data engine when implemented. * * @throws UnsupportedOperationException Thrown when it is unimplemented. */ public abstract void reverse(); }
3. 注解处理器代码
package data.core; import com.google.auto.service.AutoService; import javax.annotation.processing.*; import javax.lang.model.SourceVersion; import javax.lang.model.element.TypeElement; import javax.lang.model.element.Element; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.tools.Diagnostic; import java.util.Iterator; import java.util.Set; import javax.lang.model.element.Modifier; @AutoService(javax.annotation.processing.Processor.class) @SupportedAnnotationTypes("de.core.Implementation") @SupportedSourceVersion(SourceVersion.RELEASE_17) public class ImplementationAnnotationProcessor extends AbstractProcessor { private Messager messager; // Initialize core components to be used during processing @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); messager = processingEnv.getMessager(); } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { messager.printMessage(Diagnostic.Kind.NOTE, "Hitting the processor"); for (Element element : roundEnv.getElementsAnnotatedWith(Implementation.class)) { //If the element annotated is not a class type if(!element.getKind().isClass()) { messager.printMessage(Diagnostic.Kind.ERROR, "Implementation must be used on a class", element); return true; }else if(element.getAnnotation(Implementation.class).value() .equals(Implementation.ImplementationType.ABSTRACTION) & !element.getModifiers().contains(Modifier.ABSTRACT)){ //Invalid abstraction definition messager.printMessage(Diagnostic.Kind.ERROR, "An Implementation defined as an ABSTRACTION" + "must be declared abstract", element); return true; }else if(element.getAnnotation(Implementation.class).value() .equals(Implementation.ImplementationType.IMPLEMENTATION) & element.getModifiers().contains(Modifier.ABSTRACT)){ //Invalid implementation definition messager.printMessage(Diagnostic.Kind.ERROR, "An implementation defined as an IMPLEMENTATION" + "cannot be declared abstract", element); return true; }else if(element.getAnnotation(Implementation.class).value() .equals(Implementation.ImplementationType.IMPLEMENTATION)){ //All exceptional conditions removed, now checking the specifics //If the class does not extend an abstraction if(!isSubClassOf((TypeElement) element)){ messager.printMessage(Diagnostic.Kind.ERROR, "An implementation must extend "+ AbstractDataEngine.class + " to be considered a valid implementation", element); return true; } if(!hasEnclosedIterator((TypeElement) element)){ messager.printMessage(Diagnostic.Kind.ERROR, "Implementation does not contain a" + "Iterator implementation", element); return true; } } } return true; } private boolean isSubClassOf(TypeElement element) { TypeMirror superClassType = element.getSuperclass(); while (superClassType.getKind() != TypeKind.NONE){ if(AbstractDataEngine.class.toString().equals(superClassType.getClass().toString())){ return true; } superClassType = ((TypeElement) processingEnv.getTypeUtils().asElement(superClassType)) .getSuperclass(); } return false; } private boolean hasEnclosedIterator(TypeElement element) { for (Element enclosedElement : element.getEnclosedElements()) { if (enclosedElement.getKind().isClass()) { for (TypeMirror inf : element.getInterfaces()) { if (inf.toString().equals(Iterator.class.getCanonicalName())) return true; } } } return false; } }
4. 测试类(应触发异常的AbstractList)
package engine.core; import data.core.Implementation; /** * The top-level abstract class for all List implementations, including thread-safe * implementations. It defines methods specific to the behaviour of a list, unique value lists are also considered. * @param <E> */ @Implementation(Implementation.ImplementationType.ABSTRACTION) public class AbstractList<E> { }
问题现状
我使用AutoService注册处理器,采用Maven构建(IntelliJ环境)。最初所有文件在一个项目中,配置Maven在编译时引入处理器,但编译无错误;后来将核心文件拆分到独立模块编译为Jar,在另一个模块引用,处理器仍未触发。
内容的提问来源于stack exchange,提问作者DevSw
相关产品推荐
相关产品推荐

