アノテーション付きの型(インターフェイスの場合もあります)とそのすべてのサブタイプをテストするアノテーションを作成し、テストされた型が引数なしのコンストラクターのない具象クラスである場合はコンパイルエラーをスローしたいと思います。実際に注釈が付けられているタイプをテストできますが、問題ありません。サブタイプのテストは私が迷っているところです。どうすればこれを達成できますか?以下のソースコード:
NoArgConstructorRequired.java
package mshare.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface NoArgConstructorRequired {
}
NoArgConststructorRequiredProcessor.java
package mshare.annotation;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeVisitor;
import javax.lang.model.util.SimpleTypeVisitor7;
import javax.tools.Diagnostic;
@SupportedAnnotationTypes("mshare.annotation.NoArgConstructorRequired")
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class NoArgConstructorRequiredProcessor extends AbstractProcessor {
// Tests if the visited type has no args
private static final TypeVisitor<Boolean, Void> NO_ARGS_VISITOR = new SimpleTypeVisitor7<Boolean, Void>() {
@Override
public Boolean visitExecutable(ExecutableType t, Void v) {
return Boolean.valueOf(t.getParameterTypes().isEmpty());
}
};
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
Messager messager = processingEnv.getMessager();
for (TypeElement typeElement : annotations) {
for (Element element : roundEnv.getElementsAnnotatedWith(typeElement)) {
if (!isOkay(element)) {
messager.printMessage(
Diagnostic.Kind.ERROR,
element.getSimpleName() + " lacks a no-arg constructor",
element
);
}
}
}
return true;
}
private static boolean isOkay(Element element) {
if (element.getModifiers().contains(Modifier.ABSTRACT)) {
// class is not concrete
return true;
}
for (Element subElement : element.getEnclosedElements()) {
if (subElement.getKind() == ElementKind.CONSTRUCTOR) {
if (subElement.asType().accept(NO_ARGS_VISITOR, null).booleanValue()) {
// has a no-arg constructor
return true;
}
}
}
return false;
}
}