Groovyでアノテーションを扱う方法

アノテーション定義はGroovy1.6以降

Groovy1.6以上でないと Groovy でアノテーションの定義はできません。*1
でも、使うだけならOKです。

サンプル

漠然とアノテーションを使ってみても面白みが無いので、以下のようなありがちな状況を想定。

  • クラスのフィールドに対して、DB上の型を定義するアノテーションを付加する。
  • Userクラスを作成し、その name フィールドの値をDB上では text 形にする。(1)
  • ORマッパーが、そのBeanのアノテーションを見て、DB上の型を判断。(2)
// 必要なクラスのインポート
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy

// アノテーションの作成(ランタイムでも取得できるようにRetention.RUNTIMEで設定)
@Retention(RetentionPolicy.RUNTIME)
@interface Type { String value() }

// アノテーションを使用したクラスの作成
class User {
    @Type("text") // (1)
    String name
}

// アノテーションを使用したクラスから、アノテーションを取得
Object annotation = User.getDeclaredField("name").getAnnotations()[0]

// アノテーションの型が Type 型であることを確認
assert annotation instanceof Type

// アノテーションの value() の値が "text" であることを確認。
assert ((Type)annotation).value() == "text"  // (2)


Groovy からも簡単にアノテーションが使えますねー (`・ω・´)

おまけ:Groovy1.5でアノテーション定義した場合のエラー

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed, Script0: 6: Unknown type: ANNOTATION_DEF at line: 6 column: 1. File: Script0 @ line 6, column 1.
1 error

        at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:296)
        at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:787)
        at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:438)
        at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:281)
        at groovy.lang.GroovyShell.parseClass(GroovyShell.java:572)
        at groovy.lang.GroovyShell.parse(GroovyShell.java:584)
        at groovy.lang.GroovyShell.parse(GroovyShell.java:564)
        at groovy.lang.GroovyShell.evaluate(GroovyShell.java:542)
        at groovy.lang.GroovyShell.evaluate(GroovyShell.java:484)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:912)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:756)
        at org.codehaus.groovy.runtime.InvokerHelper.invokePogoMethod(InvokerHelper.java:778)
        at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:758)
        at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:170)
        at groovy.ui.Console$_runScriptImpl_closure5.doCall(Console.groovy:497)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230)
        at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:248)
        at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnCurrentN(ScriptBytecodeAdapter.java:78)
        at groovy.ui.Console$_runScriptImpl_closure5.doCall(Console.groovy)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230)
        at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:248)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:756)
        at groovy.lang.Closure.call(Closure.java:292)
        at groovy.lang.Closure.call(Closure.java:287)
        at groovy.lang.Closure.run(Closure.java:368)
        at java.lang.Thread.run(Thread.java:619)

*1:「Groovy1.5でアノテーション定義した場合のエラー」の項参照のこと