先日、
@ Messageのついたunpack対象のclassの定義に public staticとつけていないのが原因だった。
— Kumazaki Hiroki (@kumagi) 2014, 2月 28
@komamitsu_tw これ、コンパイル時に怒らせる事ってできないんでしょうか。できないんですよねリフレクションだから…
— Kumazaki Hiroki (@kumagi) 2014, 2月 28
という事例を聞いたので何とかコンパイル時に検知出来ないかぼーっと考えてて、プリプロセス的にチェックできないか思いついたので試してみました。
#ちなみにTweet上ではリフレクションとあったけど、多分実際はJavassistを使ってる気がする
今回サンプルとして動かしてみたのは、@Helloというannotationがついたクラスはstaticじゃないとエラーにするやつ。
org.komamitsu.pptest.annotation.Hello
package org.komamitsu.pptest.annotation; import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) public @interface Hello {}
org.komamitsu.pptest.Main
package org.komamitsu.pptest; import org.komamitsu.pptest.annotation.Hello; public class Main { @Hello static class A { } @Hello class B { } public static void main(String argv[]) { System.out.println("helloworld"); } }
こんな感じになっている場合に、コンパイル時にclass Bをエラーとしたい。
で、プリプロセス的なタイミングでチェックするやつがこれ
org.komamitsu.pptest.preprocessor.Hello
package org.komamitsu.pptest.preprocessor; import java.util.Set; import javax.lang.model.element.Element; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.annotation.processing.*; import javax.tools.Diagnostic.*; @SupportedAnnotationTypes(value= {"*"}) public class Hello extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { for (Element elm : roundEnv.getElementsAnnotatedWith(org.komamitsu.pptest.annotation.Hello.class)) { Set<Modifier> modifiers = elm.getModifiers(); if (!modifiers.contains(Modifier.STATIC)) { processingEnv.getMessager().printMessage(Kind.ERROR, "@Hello: Only accepts static class. " + elm); } } return true; } }
一応、これも。
pom.xml
<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>org.komamitsu</groupId> <artifactId>pptest</artifactId> <version>0.0.1-SNAPSHOT</version> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> </plugins> </build> </project>
Main classとかをコンパイルするときにorg.komamitsu.pptest.preprocessor.Helloを挟んであげれば良さそうなのだけど、スマートな方法が思いつかず以下のような手順で...
$ pwd /Users/komamitsu/Dev/workspace/pptest $ mvn clean package : $ cd src/main/java/ $ javac -cp ../../../target/pptest-0.0.1-SNAPSHOT.jar -processor error: @Hello: Only accepts static class. org.komamitsu.pptest.Main.B 1 error
本当はちょこっとwarningが出てるんだけど、見辛いし本筋と関係ないので省略。
とまあ、こんな感じでコンパイル時にチェックできそうなんだけども、これをどうmsgpackに組み込むか(ユーザーが特に何もせずに当該チェックが作動するか)が思いついてない...