0

次のように定義されている JSON からケース クラス オブジェクトを作成するコンバーター関数があります。

object JSONConverter {
  import language.experimental.macros

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

JSON を含む String から同じオブジェクトを作成することにも興味があります。したがって、上記のスニペットを次のように変更して、元のメソッドをオーバーロードしました。

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()

最初のものは正しいですが、2 番目のものは代わりに 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)
}

別のマクロを作成せずに、私が望むものを達成することは可能ですか?

よろしくお願いします!

4

1 に答える 1

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)
}
于 2013-06-26T08:31:01.973 に答える