2016-07-14 12 views
2

サードパーティの注釈プリプロセッサで生成されたいくつかのJavaクラスに基づいてスカラークラスを構築しようとしています。マクロ注釈の引数としてクラスを取ることができます

私は、例えば注釈付きオブジェクトからクラスへの「点」のことができるようにしたい:私は実際のマクロの実装によ一度

@MyAnnotation(classOf[GeneratedJavaClass]) object MyObject 

または

@MyAnnotation object MyObject extends PlaceHolderTrait[GeneratedJavaClass] 

私はGeneratedJavaClassを反映して、MyObjectの実装を構築するために使用するメンバーを探したいと思います。

これまでのところ、私の出発点はhttps://github.com/travisbrown/type-provider-examples/blob/master/rdfs-public/src/main/scala/public/PrefixGenerator.scalaに基づいています。

私は、アノテーションの引数としてクラス[T]を取り、その後、Apply(Select(Apply(_, List(TypeApply(_, List(catalog)))), _), _)c.macroApplicationに一致する可能性がどのように理解しようとしましたが、私が得るタイプがTypeApply(_, List(Trees$Ident)であると私は取得する方法が表示されませんそこからのクラス(classOf [T]はリテラルではないと仮定します)。

代わりに、私は、私がオブジェクトを拡張している特性から私が望むタイプを抽出しようとしていると思った。私はcase List(q"object $name extends PlaceHolderTrait[$parent] { ..$body }")に対してannoteeをマッチさせようとしましたが、再びTree $ Identで終わり、参照されているクラスを取得する方法がわかりません。

おそらく、完全修飾名の文字列を渡してクラスを取得するためにリフレクションを使用することができたことがわかりましたが、私はより良い方法を望んでいました。私はクラスを指定するための2つの選択肢に縛られていないことに注意してください。これは私が思いついた2つの選択肢です。

答えて

1

[OK]を、最終的には何かの作業を持って、に基づいて私は、タイアで走っている段階で走っていないので、タイプが与えられることを期待していることが少しばかげていることに気付きました。次のようなマクロAPIは、あなたが木の上タイパーを実行することができますしかしtypeCheck方法を提供します:

class AnnotationArgument[T] extends StaticAnnotation { 
    def macroTransform(annottees: Any*): Any = macro AnnotationArgumentImpl.impl 
} 

class AnnotationArgumentImpl(val c: blackbox.Context) { 

    import c.universe._ 

    def impl(annottees: c.Expr[Any]*): c.Tree = { 
     val macroTypeWithArguments = c.typeCheck(q"${c.prefix.tree}").tpe // my.package.AnnotationArgument[my.package.MyClass] 
     val annotationClass: ClassSymbol = macroTypeWithArguments.typeSymbol.asClass // my.package.AnnotationArgument 
     val annotationTypePlaceholder: Type = annotationClass.typeParams.head.asType.toType // T 
     val argumentType: Type = annotationTypePlaceholder.asSeenFrom(args, annotationClass) // my.package.MyClass 

     println(s"the argument's type is $argumentType") 


    q"..${annottees}" 
    } 
} 

import my.package.MyClass 
@AnnotationArgument[MyClass] 
class AnnotationArgumentTestClass 
+0

誰かがこれを行う方法が醜い人なら、私は自分の答えを受け入れずに受け入れますが、私の場合はうまくいく。 –

0

別の思考:

使用別のクラスの注釈が保存クラス情報

class AnnotationArgumentClass[T](clazz: Class[T]) extends StaticAnnotation 

class AnnotationArgument extends StaticAnnotation { 
    def macroTransform(annottees: Any*): Any = macro AnnotationArgumentImpl.impl 
} 

class AnnotationArgumentImpl(val c: blackbox.Context) { 

    import c.universe._ 

    def impl(annottees: c.Expr[Any]*): c.Tree = { 
    val classValue = annottees.head.tree match { 
     case x: MemberDefApi => x.mods.annotations collectFirst { 
     case q"new $annotation($classValue)" => classValue 
     } 
    } 

    /*edit :*/ 
    val x = (c.eval(c.Expr[Type](c.typecheck(classValue.get)))) 
    println(x.typeSymbol.fullName) 

    q"..${annottees}" 
    } 
} 

テスト:

package aaa 
class AAA 

//

import aaa.AAA 
@AnnotationArgument 
@AnnotationArgumentClass(classOf[AAA]) 
class AnnotationArgumentTestClass 
+0

は、私が見つかりません。 '取得:タイプMyType'をマクロを実行しようとすると、おそらくあなたの例があるために働きました'Int'はインポートする必要はありませんか? –

+0

):はい、それは 'Int'がインポートを必要としないので、' typecheck'を必要とします。 –

関連する問題