2016-11-23 7 views
2

java注釈プロセッサを使用して実行されるいくつかのチェックがありますが、注釈のない型のチェックも行いたいと思います。注釈のないjava型の処理

例えば、私が@Responsible(name="xyz")のような注釈を持っているとすれば、コンパイルプロセスにフックして注釈がすべてのトップレベルタイプに対して存在するように強制する最良の方法は何ですか?

私の現在の実装では、2つの注釈、予想される注釈とパッケージレベルの注釈を使用します。後者は、注釈が存在しなくても注釈プロセッサを「起動」するために使用されます。 起動アノテーションプロセッサの中で、ディスク上の&フィルタJavaファイル(コンパイラに渡された引数を使用)を検索して、処理するすべてのファイルを収集し、javaファイルがプロセッサの注釈付きタイプ取り扱い。誰かが注釈を指定せずに新しいファイルをコミットした場合、ビルドは失敗します。

「アノテーションなし」タイプを見つけるためのよりクリーンな方法はありませんか?

答えて

2

*を使用してプロセッサがすべてを処理すると宣言されていた場合、私が探していた要素のリストはRoundEnvironment#getRootElements()でした。

だから、すべてのタイプが、私は問題はエレメント#getEnclosedElements`はサブパッケージを通過することはできません `、私はと多くを調べるだろうということである

@AutoService(Processor.class) 
public class ResponsibleAnnotationProcessor extends AbstractProcessor { 
    @Override 
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) { 
      List<ElementKind> typeKinds = Arrays.asList(ElementKind.ENUM, ElementKind.INTERFACE, ElementKind.CLASS); 
      // let's gather all types we are interrested in 
      Set<String> allElements = env.getRootElements() 
        .stream() 
        .filter(e -> typeKinds.contains(e.getKind())) // keep only interesting elements 
        .map(e -> e.asType().toString())    // get their full name 
        .collect(Collectors.toCollection(() -> new HashSet<>())); 
      Set<String> typesWithResponsible = new HashSet<>(); 

      annotations.forEach(te -> { 
       if (Responsible.class.getName().equals(te.asType().toString())) { 
        // We collect elements with an already declared ownership 
        env.getElementsAnnotatedWith(te).forEach(e -> typesWithResponsible.add(e.asType().toString())); 
       } 
      }); 

      allElements.removeAll(typesWithResponsible); 
      allElements.forEach(cname -> processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, cname + " must be annotated with @" + Responsible.class.getName() + " to declare a ownership")); 
      return false; 
    } 

    @Override 
    public SourceVersion getSupportedSourceVersion() { 
     return SourceVersion.latestSupported(); 
    } 

    @Override 
    public Set<String> getSupportedAnnotationTypes() { 
     // We want to process all elements 
     return Collections.singleton("*"); 
    } 
} 
3

注釈を使用してプロセッサを実行する必要はありません。 the documentationで説明したように本なし注釈タイプが存在しない

場合、注釈処理は、依然として「*」注釈型の(空の)セットを請求することができる処理をサポートするだけユニバーサルプロセッサを生じます。

あなたのクラスを見つける方法はちょっと面倒です。代わりに、パッケージとクラス間の親子関係に依存することができます:興味深いクラスを含む最上位のパッケージ要素の名前を調べ、Element#getEnclosedElementsを使用してそのパッケージ(および/またはそのサブパッケージ)に下ります。あるいは、そのパッケージ内に単一のクラスを配置してから、Element#getEnclosingElementを使用して最上位のパッケージに昇格することもできます。パッケージオブジェクトはElements#getPackageElementを使用して名前で取得でき、クラスオブジェクトはElements#getTypeElementを使用して名前で取得できます。

ファイルやディレクトリとの手動でのやりとりと比較して、はるかに脆弱ではなく、ソースファイルが移動されたり、ディレクトリ間で分割されたりすると壊れません。

封筒の注文は"a single package" -> "class" -> "method" -> ...であり、すべてのパッケージの親はパッケージそのものではなく、親パッケージではありません(net.examplenetに含まれていません)。

+0

になってしまった@Responsibleで注釈されたことを確認するために、 "*"プロセッサーと 'roundEnv.getRootElements()' –

+0

@MatthieuBROUILLARDはい、これはまさに上記の意味です。幸いにも、 'String#split'を使用してあなた自身がサブパッケージを取得するのを止めるものは何もありません:) – user1643723

+0

" * "を使用していただきありがとうございました。 –

関連する問題