2013-06-25 98 views
0

我有一個創建從JSON,其定義如下的情況下,類對象轉換器功能:斯卡拉宏:方法重載

object JSONConverter { 
    import language.experimental.macros 

    def modelFromJson[T <: Model](json: JsValue):T = macro modelFromJson_impl[T] 
} 

我感興趣的創建從包含JSON字符串相同的對象也是。因此,我已改變上面的代碼如下重載原來的方法:

object JSONConverter { 
    import language.experimental.macros 

    // Using Play Framework library to parse a String to JSON 
    def modelFromJson[T <: Model](json: JsValue):T = macro modelFromJson_impl[T] 

    def modelFromJson[T <: Model](jsonString: String):T = { 
    val json: JsValue = Json.parse(jsonString) 
    modelFromJson[T](json) 
    } 
} 

但我收到此錯誤信息:

[error] ... not found: value T 
[error]  modelFromJson[T](json) 
[error]     ^

所以對於下面的配置

case class User(name: String, age: Int, posts:String, score: Double, lastLogin: DateTime) extends Model 

// First case 
JSONConverter.modelFromJson[User](someJsValueObject) 

// Second case 
JSONConverter.modelFromJson[User](someJsonString) 

宏試圖返回以下表達式:

User.apply(json.$bslash("name").as[String], json.$bslash("age").as[Int], json.$bslash("posts").as[String], json.$bslash("score").as[Double], new DateTime(json.$bslash("lastLogin").as[Long])) 

T.apply() 

第一個是正確的,而第二個嘗試訪問T。

宏基本實現如下:

def modelFromJson_impl[T: c.WeakTypeTag](c: Context)(json: c.Expr[JsValue]): c.Expr[T] = { 
    import c.universe._ 
    val tpe = weakTypeOf[T] 

    // Case class constructor 
    val generation = Select(Ident(newTermName(tpe.typeSymbol.name.decoded)), newTermName("apply")) 

    // Generate stuff like json.\("fieldName").as[String] 
    val fields = tpe.declarations collect { 
     ... 
    } 

    val s = Apply(generation, fields.toList) 

    // Display results above for debugging 
    println(show(s)) 

    c.Expr[T](s) 
} 

是否可以達到我想要的不進行其他宏?

非常感謝!

+1

我不認爲這是可能的。不幸的是,在運行時,至少不能在Scala中抽象宏。 –

+0

再次感謝尤金。 – Emre

+0

以後有沒有計劃支持這個? – Emre

回答

0

我通過移動東西來解決問題,以編譯時間。我將另一個宏定義爲

def modelFromJsonString[T <: Model](jsonString: String):T = macro convertFromJsonString_impl[T] 

def convertFromJsonString_impl[T: c.WeakTypeTag](c: Context)(jsonString: c.Expr[String]): c.Expr[T] = { 
    import c.universe._ 
    val conversion = c.Expr[JsValue](reify(Json.parse(jsonString.splice)).tree) 

    convertFromJson_impl[T](c)(conversion) 
}