2017-10-05 8 views
1

jackson-module-Scalaを使用して、としてLongを使用して内部マップを使用してオブジェクトをシリアル化および逆シリアル化しようとしましたが、 Stringとして宣言し、クラスで定義された型をlong型としてデシリアライズしません。 これはバグですか?私は何か間違っているのですか?jackson-module-scalaは、マップの文字列として長整数型のキーを返します

import com.fasterxml.jackson.databind.ObjectMapper 
import com.fasterxml.jackson.module.scala.DefaultScalaModule 
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper 

case class InnerMap(map: Map[Long, Long]) 

object CrazyJackson { 

    def main(args: Array[String]): Unit = { 
    val mapper = new ObjectMapper() with ScalaObjectMapper 
    mapper.registerModule(DefaultScalaModule) 

    val innerMap = InnerMap(Map(1L->1L)) 
    val serialized = mapper.writeValueAsString(innerMap) 
    val newObj = mapper.readValue(serialized, classOf[InnerMap]) 
    println(serialized) // Why the key is serialized as a String? 
    println(innerMap) 
    println(newObj) 
    assert(newObj == innerMap) 
    } 

} 

アサートに失敗したとのprintlnの出力(シリアル化された)文は次のとおりです。

{"map":{"1":1}} 

NEWOBJとinnerMapを印刷することは同じであることが奇妙である:

InnerMap(Map(1 -> 1)) 
InnerMap(Map(1 -> 1)) 

として@ヴァーレンは、問題は本当に主張していると言います。しかし:

import com.fasterxml.jackson.databind.ObjectMapper 
import com.fasterxml.jackson.module.scala.DefaultScalaModule 
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper 
import org.scalatest.FunSuite 

class CrazyJacksonTest extends FunSuite { 
    test("test json comparision") { 
    val mapper = new ObjectMapper() with ScalaObjectMapper 
    mapper.registerModule(DefaultScalaModule) 

    val innerMap = InnerMap(Map(1L->1L)) 
    val serialized = mapper.writeValueAsString(innerMap) 
    val newObj = mapper.readValue(serialized, classOf[InnerMap]) 
    assert(newObj.map == innerMap.map) 
    } 
} 

アサート結果:

Map("1" -> 1) did not equal Map(1 -> 1) 
ScalaTestFailureLocation: CrazyJacksonTest$$anonfun$1 at (CrazyJacksonTest.scala:17) 
Expected :Map(1 -> 1) 
Actual :Map("1" -> 1) 

私は失われています! マップは地図[Long、Long]でなければなりません!

  • スカラ2.11.11
  • ジャクソン・モジュール・スカラ座2.6.5をしても同じ結果にバージ​​ョン2.9.1でテスト:

    ため、私はスパークの依存関係のこのバージョンを使用する必要があります。

その他の情報:

答えて

0

JSONは、キー名は文字列だけにすることができます。 ECMA-404 The JSON Data Interchange Standard

オブジェクト構造は、ゼロまたはそれ以上の名前/値のペアを囲む中括弧トークン の組として表現されます。 名前は文字列です。

あなたは正しく、アサーションの問題はジャクソンから来ています。 enter image description here classOf[InnerMap]は実際にMap<Object, Object>InnerMapにマップされていますが、このマップのtypeinfoをjacksonに提出して正しく逆シリアル化する必要があります。それはthis documentationで説明されており、それに応じて、あなただけのマップ内のキーの種類を推測することはありません

case class InnerMap(@JsonDeserialize(keyAs = classOf[java.lang.Long]) 
        map: Map[Long, Long]) 
+0

したがって、問題はアサートにあります。私は、ケースクラスがequalsとhashCodeを実装していると考えました。実際には、なぜ "assert(InnerMap(Map(1L-> 1L))== InnerMap(Map(1L-> 1L))))"のようになりますか? – angelcervera

+0

私の新しい例を確認できますか?私は何かを欠いている。 caseクラスがMap [Long、Long]として定義されている場合、アサルトがMap [String、Long]として内部オブジェクトを管理する方法は可能です – angelcervera

+0

「Scalaでオブジェクトが等しいかどうかを比較する方法」へのリンク。別のケースです。なぜなら、クラスとケースクラスを比較しているからです。 – angelcervera

0

Scalaのジャクソンモジュールを使用することができます。 @Varrenが応答として、ソリューションは、ジャクソンの注釈をモデルに注釈を付けることであるが、このように:

  • モデルは、特定のパーサー(モデル定義におけるジャクソン注釈)に関連付けられています。
  • コードは明確ではありません。

だから私はCirceにジャクソンから移動し、クリーンなコードを維持するために注釈を削除することを決めました。 これは、構文解析し、正しくunparsingされていることを証明するテストです:これは誰にとっても最善の解決策であることを意味していません

test("test json circe comparision") { 

    import io.circe._ 
    import io.circe.generic.auto._ 
    import io.circe.parser._ 
    import io.circe.syntax._ 

    val innerMap = InnerMap(Map(1L -> 1L)) 

    val jsonStr = innerMap.asJson.noSpaces 
    decode[InnerMap](jsonStr) match { 
     case Right(innerMap2) => assert(innerMap2 == innerMap) 
     case Left(error) => fail(error) 
    } 

    } 

CirceにはJacksonパーサーと組み合わせて使用​​するプラグインがありますが、テストしませんでした。

関連する問題