Scalaで、アノテーションを読みたくていろいろ試行錯誤していると、ネットで、
Scalaで作られたクラスをダンプするコードを見つけました。
オリジナルのコードでは読み取れる情報が少ないので、機能拡張したのが以下のコードです。
チェックしたいScalaクラスをListの要素に書けば、フィールドとメソッドをreflectして、アノテーションを読みだしてくれます。
package seedo import scala.collection.JavaConversions._ object DumpClass { def check() { List( classOf[seedo.MASTER] , classOf[seedo.MASTER1] ).foreach(cl => { println(cl.getName) // Field cl.getDeclaredFields.foreach(f => { val annotations = java.util.Arrays.asList(f.getAnnotations: _*).map("@" + _.annotationType.getSimpleName).mkString(" "); println(" field " + annotations + " [" + f.getName + "] GenericType [" + f.getGenericType + "] [" + f.getType.getSimpleName + "]") f.getDeclaredAnnotations.foreach(g => { println(" fieldAnnotation [" + g.annotationType + "] SimpleName [" + g.annotationType.getSimpleName+ "]") }) }) // Methods cl.getDeclaredMethods.foreach(m => { val annotations = java.util.Arrays.asList(m.getReturnType.getAnnotations: _*).map("@" + _.annotationType.getSimpleName).mkString(" "); println(" method [" + annotations + "] [" + m.getName + "]") m.getParameterTypes.foreach(p =>{ println(" ParameterType [" + p + "] [" + p.getSimpleName + "]") }) }) println }) } def main(args : Array[String]) : Unit = { println("DumpClass World ----") check } }
以前、Scalaで作った Bean クラスのMASTERクラスを指定して実行すると、以下のようにダンプします。
DumpClass World seedo.MASTER field [TABLE] GenericType [class java.lang.String] [String] field [PRIMARY_KEY] GenericType [class java.lang.String] [String] field [timestamp_COLUMN] GenericType [class java.lang.String] [String] field [RENTALODRID] GenericType [class java.math.BigDecimal] [BigDecimal] field [CUSTOMERID] GenericType [class java.lang.Integer] [Integer] ・・・ method [] [RENTALODRID] method [] [CUSTOMERID] method [] [DLVTYPCODE] ・・・
さらに、このBeanクラスに@でJavaで定義したアノテーションを付けて、DumpClassクラスで使えばクラス情報を読むことができます。
class MASTER1 { @Id var RENTALODRID:BigDecimal = null @Column var CUSTOMERID:Integer = null @Column var SALESPRICE:BigDecimal = null @Column var DLVFEETAX:BigDecimal = null @Column var DLVFEE:BigDecimal = null ・・・
次の、MASTER2クラスのようにコンストラクタ引数で、メンバーを宣言した場合、
ここのメンバーに@アノテーションを付けても、この部分を読み取ることができません。
Javaクラスのようにクラスのなかのメンバーしかダメです。
class MASTER2 ( @BeanProperty @Id var RENTALODRID:BigDecimal , @BeanProperty var CUSTOMERID:Integer , @BeanProperty var SALESPRICE:BigDecimal , @BeanProperty var DLVFEETAX:BigDecimal ・・・
それと、Scalaで定義したアノテーションは読むことができないです。
現状はScalaの処理系の中からしか使えないのでしょう。
アノテーションは、やはりJavaで作らないとダメです。
Javaでアノテーションを定義するには、JavaでClassファイルを作って、Jar化してScalaのビルドパスに追加します。
Javaでふつうに、Annotation を定義すればいいです。
package seedo; 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 Id { }
package seedo; 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.TYPE }) public @interface Table { String name(); String value(); }
package seedo; 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 Column {}
ClassDumpクラスに、以下のコードを コード下にある単独println の上の行に挿入すると、Javaで定義したTableアノテーションのname値とvalue値が読めます。
// Static Annotation val annotations = java.util.Arrays.asList(cl.getAnnotations: _*).map("@" + _.annotationType.getSimpleName).mkString(" ") cl.getAnnotations.foreach(aa => { val an = aa.annotationType.getSimpleName println(" annotation SimpleName=" + an) if("Table".equals(an)){ val tb = aa.asInstanceOf[Table] println(" Table =" + tb.name + " value="+ tb.value) } }) println(" annotation " + annotations)
Scalaのクラスを覗いてみると、細かい違いが見えてきます。
Beanで、ScalaのDouble / Float / Int と java.lang.Double の浮動小数点型をメンバーにして定義すると、
reflectした結果は、Double / Float / IntはClassではないと表示されます。Javaのプリミティブの double / float / int です。
メソッドの引数にIntと定義しても、java.lang.Integerで実際には受け渡ししています。Java6と同じです。
var RATE:java.lang.Double = null var RATE1:Double = 0.0 var RATE2:Float = 0.0F var RATE3:Int = 0 field [RATE] GenericType [class java.lang.Double] [Double] field [RATE1] GenericType [double] [double] field [RATE2] GenericType [float] [float] field [RATE3] GenericType [int] [int]
純粋に、Scalaの世界でアノテーションはどうやって使うのでしょう???
コメントを残す
コメントを投稿するにはログインしてください。