2016-07-14 4 views
2

Я пытаюсь построить класс scala на основе некоторых классов 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] в качестве аргумента в аннотации, а затем сопоставить на c.macroApplication с Apply(Select(Apply(_, List(TypeApply(_, List(catalog)))), _), _) но типа я получаю это TypeApply(_, List(Trees$Ident), и я не вижу способа, чтобы получить класс оттуда (я предполагаю, что classOf [T] не является литералом).

В качестве альтернативы, я подумал, что попытаюсь извлечь тип, который я хочу, из свойства, что у меня есть объект. Я пробовал сопоставлять аннотацию с case List(q"object $name extends PlaceHolderTrait[$parent] { ..$body }"), но опять же в конечном итоге с деревьями $ Ident и не уверен, как получить класс, на который ссылаются.

Я понимаю, что я мог бы просто передать строчку полного имени и использовать отражение, чтобы получить класс, но я надеялся на лучшую альтернативу. Обратите внимание, что я не привязан к этим двум альтернативам для указания класса, это всего лишь два варианта, которые я смог придумать.

ответ

1

Ok, наконец-то работает, на основе https://github.com/scalamacros/paradise/issues/69 Я понял, что на сцене, в которой я бегу, типер не запустился и, следовательно, ожидал получить тип, это немного глупо. Макрос апи действительно обеспечивает typeCheck метод, однако, что позволяет запускать Typer на дереве, следующим образом:

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' –

Смежные вопросы