読者です 読者をやめる 読者になる 読者になる

システム開発で思うところ

JavaEEを主にシステム開発をしながら思うところをツラツラを綴る

Netbeans で Pluggable Annotation Processing API

Java Annotation

こちらの記事のNetBeans版のようなものです。

d.hatena.ne.jp

AnnotationProcessorが動くまでのところのチュートリアル的にやってみようと思ってやってみたところ、少し躓いたところもあったので誰かの参考になればと思い、まとめてみました。事例のベースもリンク元と同じなので詳細は上述のリンクを確認ください。本記事では動くまでの流れを中心にします。

はじめに

NetBeansのビルドではなくmavenプロジェクトで実施しています。試してはいませんがNetBeansに強依存はしていないとは思います。
実行環境はJava8です。

新規プロジェクト(Processor提供側)を作る

mavenプロジェクトを作成する

f:id:vermeer-1977:20170102233832p:plain f:id:vermeer-1977:20170102233833p:plain

提供側ソース

package com.mycompany.annotationprocessor;

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.TypeElement;
import javax.tools.Diagnostic.Kind;

@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes("java.lang.SuppressWarnings")
public class SuppressWarningsProcessor extends AbstractProcessor {

    @Override
    public boolean process(Set<? extends TypeElement> annotations,
                           RoundEnvironment roundEnv) {
        Messager messager = processingEnv.getMessager();
        for (TypeElement annotation : annotations) {
            for (Element element : roundEnv
                    .getElementsAnnotatedWith(annotation)) {
                messager.printMessage(Kind.WARNING, "@SuppressWarningsしちゃだめ",
                                      element);
            }
        }
        return true;
    }
}

サービスプロバイダーコンフィギュレーションファイルの保存先作成

このフォルダの作成自体がポイントです。*1

f:id:vermeer-1977:20170102233835p:plain f:id:vermeer-1977:20170102233836p:plain f:id:vermeer-1977:20170102233837p:plain f:id:vermeer-1977:20170102233838p:plain

サービスプロバイダーコンフィギュレーションファイルを作成

f:id:vermeer-1977:20170102233839p:plain f:id:vermeer-1977:20170102233840p:plain ファイル名:javax.annotation.processing.Processorを作成し、AnnotationProcessorを登録する

com.mycompany.annotationprocessor.SuppressWarningsProcessor

今回は1つですが複数のAnnotationProcessorがある場合 改行区切りで登録できます。

最終的なフォルダ構成

├─src
│  └─main
│      ├─java
│      │  └─com
│      │      └─mycompany
│      │          └─annotationprocessor
│      │                  SuppressWarningsProcessor.java
│      │                  
│      └─resources
│          └─META-INF
│              └─services
│                      javax.annotation.processing.Processor

pom.xmlの編集

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mycompany</groupId>
    <artifactId>AnnotationProcessor</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <!-- Disable annotation processing for ourselves. -->
                    <compilerArgument>-proc:none</compilerArgument>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

ポイントはコンパイルオプションのところ-proc:noneです。またpom.xmlgroupIdは次の利用側で参照します。ただし、今回は「同一プロジェクトグループ」という形で参照します。

新規プロジェクト(Processor利用側)を作る

mavenプロジェクトを作成する

プロジェクト名samplesで作成。作成手順は上述の通りなので省略。
既存のmavenプロジェクトがあれば新規作成は不要です。

利用側プログラム

package com.mycompany.samples;

import java.util.ArrayList;
import java.util.List;

@SuppressWarnings("unchecked")
public class Sample {

    void hoge() {
        List list = new ArrayList<>();
        list.add("");
        System.out.println(list.size());
    }
}

pom.xmlの編集

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mycompany</groupId>
    <artifactId>samples</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <!-- for my group annotation processor start -->
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>AnnotationProcessor</artifactId>
            <version>${project.version}</version>
            <type>jar</type>
        </dependency>
        <!-- for my group annotation processor end -->
    </dependencies>

</project>

今回はgroupIdは、提供側と同じなので${project.groupId}と指定しています。

適用された結果

f:id:vermeer-1977:20170102233841p:plain

警告を見ると適用されていることが分かります。

さいごに

他に参考にさせていただいた情報だともっと面倒な印象でしたが、結果としてmavenの設定だけで大きな手間も無く動くところまで確認できて良かったです。

今回の記事とは関係ないですがmavenプロジェクトを個別に作成をして依存を定義するというのは、自分のシステムでレイヤー間の依存関係を明確にするために使っています。
プロジェクトで分割しておくことで、うっかりController層のクラスを誤ってService層で参照しないように強制させることが出来ます。*2

*1:私が躓いたところです。当初、場所が正しくなく参照されませんでした。

*2:Java9のJigsawがリリースされるまでの工夫といったところでしょうか