出典、コップ本第2版P.552。
Scalaでは、アノテーションの引数に直接アノテーションを書くことができません。例えば、以下のようなアノテーションを用意して
src/main/java/Complex.java
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Complex { Value[] value(); }
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Value { String value() default "v"; String val1() default "v1"; String val2() default "v2"; }
こんな感じに使おうとすると、
src/main/scala/SampleClass.scala
@Complex(Array(@Value)) class SampleClass { }
コンパイルに失敗します。
[error] /xxxxx/src/main/scala/SampleClass.scala:3: illegal start of simple expression [error] @Complex(Array(@Value)) [error] ^
単純な式しか、そこは指定できませんよ、と。
これを回避するには、ちょっと奇妙ですがアノテーションをnewで指定します。
@Complex(Array(new Value)) class SampleClass { }
引数がある場合には、コンストラクタでキーワード引数として指定します。
@Complex(Array(new Value("simple-value"), new Value(val1 = "one", val2 = "two"))) class SampleClass { }
何も名前を与えないと、Javaと同様「value」を指定したものとして扱われるみたいです。
ちゃんと値も取れますよ、ということで。
import org.scalatest.FunSpec import org.scalatest.Matchers._ class SampleClassSpec extends FunSpec { describe("nested annotation") { it("get annotated value") { val comp = classOf[SampleClass].getAnnotation(classOf[Complex]) val values = comp.value values should have size 2 val v1 = values(0) v1.value should be ("simple-value") val v2 = values(1) v2.val1 should be ("one") v2.val2 should be ("two") } } }
Scalaを使っているとあんまりバシバシアノテーションを使わない気もするのですが、Java EEと合わせて使ってたりするとたまーにこういうのに遭遇します。
例えば、NamedQueriesなど。
*こちらはJavaコードです
@NamedQueries({ @NamedQuery(name="Country.findAll", query="SELECT c FROM Country c"), @NamedQuery(name="Country.findByName", query="SELECT c FROM Country c WHERE c.name = :name"), })
まあ、ぶつかった時は忘れていたわけですが…。