3

Lift-json を使用して、JSON 文字列を逆シリアル化して Scala ケース クラスに変換しています。私が解析している JSON には共通の構造があります。データ、成功、およびエラー フィールドで、データには興味深いビットが含まれています。この構造を考慮して APIResponse クラスを作成し、「データ」に含まれるオブジェクトの型の型パラメーターを受け取る単純な解析メソッドを作成しました。

import net.liftweb.json.Serialization.read
import net.liftweb.json.DefaultFormats

object JSONParseTest extends App {
  implicit val formats = DefaultFormats

  def parse[T: Manifest](json: String) = {
    read[APIResponse[T]](json)
  }

  val resultA = parse[TypeA](""" { "data": { "foo": "string" }, "success": true } """)
  println(resultA)
  val resultB = parse[TypeB](""" { "data": { "bar": "string" }, "success": true } """)
  println(resultB)
}

case class TypeA(foo: String)
case class TypeB(bar: String)

case class APIResponse[D](data: D, success: Boolean, error: Option[String]) {
  override def toString: String =
    if(success) {
      "SUCCESSFUL: " + data.toString
    } else {
      "ERROR: " + error.get
    }
}

すべてがうまく機能します...最初に解析されたオブジェクトに対して。しかし、なんらかの理由で、解析された 2 番目のオブジェクトが「スタック」したように見え、2 番目の型パラメーターではなく最初の型パラメーターが渡されたかのように動作します。以下の出力でわかるように、lift-json は JSON 文字列で「foo」フィールドを探していますが、見つかりません。「foo」は TypeA には存在しますが、TypeB には存在しません。parse メソッドでマニフェストを確認しましたが、そこに適切な型があります。最初の解析/印刷をコメントアウトすると、2 番目が機能し始めます。これが期待どおりに動作しない理由についての指針はありますか? これはちょっと頭がおかしいです。

SUCCESSFUL: TypeA(string)

Exception in thread "main" net.liftweb.json.MappingException: No usable value for data
No usable value for foo
Did not find value which can be converted into java.lang.String
    at net.liftweb.json.Meta$.fail(Meta.scala:191)
    at net.liftweb.json.Extraction$.mkValue$1(Extraction.scala:357)
    at net.liftweb.json.Extraction$.build$1(Extraction.scala:317)
    at net.liftweb.json.Extraction$$anonfun$12.apply(Extraction.scala:253)
    at net.liftweb.json.Extraction$$anonfun$12.apply(Extraction.scala:253)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:233)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:233)
    at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
    at scala.collection.immutable.List.foreach(List.scala:76)
    at scala.collection.TraversableLike$class.map(TraversableLike.scala:233)
    at scala.collection.immutable.List.map(List.scala:76)
    at net.liftweb.json.Extraction$.instantiate$1(Extraction.scala:253)
    at net.liftweb.json.Extraction$.newInstance$1(Extraction.scala:286)
    at net.liftweb.json.Extraction$.build$1(Extraction.scala:315)
    at net.liftweb.json.Extraction$.net$liftweb$json$Extraction$$extract0(Extraction.scala:366)
    at net.liftweb.json.Extraction$.net$liftweb$json$Extraction$$extract0(Extraction.scala:199)
    at net.liftweb.json.Extraction$.extract(Extraction.scala:43)
    at net.liftweb.json.JsonAST$JValue.extract(JsonAST.scala:300)
    at net.liftweb.json.Serialization$.read(Serialization.scala:58)
    at jmullin.api.Test$.parse(API.scala:11)
    at jmullin.api.Test$delayedInit$body.apply(API.scala:16)
    at scala.Function0$class.apply$mcV$sp(Function0.scala:34)
    at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
    at scala.App$$anonfun$main$1.apply(App.scala:60)
    at scala.App$$anonfun$main$1.apply(App.scala:60)
    at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
    at scala.collection.immutable.List.foreach(List.scala:76)
    at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:30)
    at scala.App$class.main(App.scala:60)
    at jmullin.api.Test$.main(API.scala:7)
    at jmullin.api.Test.main(API.scala)
Caused by: net.liftweb.json.MappingException: No usable value for foo
Did not find value which can be converted into java.lang.String
    at net.liftweb.json.Meta$.fail(Meta.scala:191)
    at net.liftweb.json.Extraction$.mkValue$1(Extraction.scala:357)
    at net.liftweb.json.Extraction$.build$1(Extraction.scala:317)
    at net.liftweb.json.Extraction$$anonfun$12.apply(Extraction.scala:253)
    at net.liftweb.json.Extraction$$anonfun$12.apply(Extraction.scala:253)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:233)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:233)
    at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
    at scala.collection.immutable.List.foreach(List.scala:76)
    at scala.collection.TraversableLike$class.map(TraversableLike.scala:233)
    at scala.collection.immutable.List.map(List.scala:76)
    at net.liftweb.json.Extraction$.instantiate$1(Extraction.scala:253)
    at net.liftweb.json.Extraction$.newInstance$1(Extraction.scala:286)
    at net.liftweb.json.Extraction$.build$1(Extraction.scala:315)
    at net.liftweb.json.Extraction$.mkValue$1(Extraction.scala:351)
    ... 29 more
Caused by: net.liftweb.json.MappingException: Did not find value which can be converted into java.lang.String
    at net.liftweb.json.Meta$.fail(Meta.scala:191)
    at net.liftweb.json.Extraction$.convert(Extraction.scala:403)
    at net.liftweb.json.Extraction$.build$1(Extraction.scala:314)
    at net.liftweb.json.Extraction$.mkValue$1(Extraction.scala:351)
    ... 42 more
4

1 に答える 1

3

Lift-json は、型引数を無視して、舞台裏でクラスからコンストラクターへのマッピングのメモ化を行っていることがわかりました。異なる型パラメーターを持つ同じクラスに対してルックアップが実行されると、古いコンストラクターが返されるため、ここで見られる混乱が生じます。謎が解けました(問題は解決しませんでしたが)。

于 2013-03-08T19:17:13.987 に答える