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

アノテーションを付与したenum定数を色々いじってみる

はてな始めて最初のJavaエントリです。
今日アノテーションが付与されたenum定数をリフレクションで色々といじくっていたのですが、少しハマりました。

enum定数に付与するためのアノテーションHogeMarkerを作ります。
ElementTypeはFIELDを指定します。


package sandbox;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface HogeMarker {

String value();
}

次に、HogeHogeというenum型を用意してHogeMarkerを適当なenum定数に付与します。


package sandbox;

public enum HogeHoge {

@HogeMarker("ほげ1")
HOGE1 {
@Override
public String getValue() {
return null;
}
},

@HogeMarker("ほげ2")
HOGE2 {
@Override
public String getValue() {
return null;
}
};

public abstract String getValue();
}

次に、enum定数に付与されたHogeMarkerのvalue要素から値を取ろうと思いまして・・・


@Test
public void test1() {
Class hogehoge = HogeHoge.class;
for (Field field : hogehoge.getFields()) {
HogeMarker marker = field.getAnnotation(HogeMarker.class);
HogeHoge hoge = (HogeHoge) field.get(null);
System.out.print("name = " + hoge.name() + ", value = ");
if (marker != null) {
System.out.println(marker.value());
} else {
System.out.println("null");
}
}
} 

これを実行すると


name = HOGE1, value = ほげ1
name = HOGE2, value = ほげ2

が表示されます。

enum定数に付与されたアノテーションも、定数自身も取得できてめでたしめでたしなんですがJavadocを斜め読みしてみると・・・


java.lang.Class
public T[] getEnumConstants()

こんなメソッドが存在することを初めて知りましたw 早速使ってみましょう。


@Test
public void test2() {
Class hogehoge = HogeHoge.class;
for (Enum hoge : hogehoge.getEnumConstants()) {
HogeMarker marker = hoge.getClass().getAnnotation(HogeMarker.class);
System.out.print("name = " + hoge.name() + ", value = ");
if (marker != null) {
System.out.println(marker.value());
} else {
System.out.println("null");
}
}
}


name = HOGE1, value = null
name = HOGE2, value = null

あれっ、付与されたアノテーションが取得できていない・・・
hoge.getClass().getName()が返す値を見てみると・・・


hoge.getClass().getName() = sandbox.HogeHoge$1
hoge.getDeclaringClass().getName() = sandbox.HogeHoge

どうやら宣言クラスのField(enum定数)に対してgetAnnotationする必要があるようで・・・
仕方なく次のようにしてやりました。


@Test
public void test3() throws Exception {
Class hogehoge = HogeHoge.class;
for (Enum hoge : hogehoge.getEnumConstants()) {
Field field = hoge.getDeclaringClass().getDeclaredField(hoge.name());
HogeMarker marker = field.getAnnotation(HogeMarker.class);
System.out.print("name = " + hoge.name() + ", value = ");
if (marker != null) {
System.out.println(marker.value());
} else {
System.out.println("null");
}
}
}


name = HOGE1, value = ほげ1
name = HOGE2, value = ほげ2

出た出た。しかし、enum値自体は取得できているのに、そこからさらに宣言クラス→Fieldまで辿ってアノテーションを取得するのは微妙ですね・・・


ついでに色々試してみると以下のような結果になりました。


hoge.getClass().getSuperclass().getName() = sandbox.HogeHoge
Modifier.isAbstract(hoge.getClass().getModifiers()) = false
Modifier.isAbstract(hoge.getDeclaringClass().getModifiers()) = true

まだまだ知らないことが多い若輩者ですw