Scala Gson, cannot serialize Option[Blob]

我与影子孤独终老i 提交于 2021-02-08 11:27:29

问题


I managed to extend Gson to handle Scala's Option and Blob types, but I have trouble with the combined Option[java.sql.Blob].

My test says

[info] - should serialize an Option - OK

[info] - should serialize a Blob - OK

[info] - should serialize an Option[Blob] * FAILED *

[info] {"x":{"buf":[97,115,100,102],"len":4,"origLen":4}} was not equal to {"x":"asdf"}

Can you please tell me what this {"buf": [...]} object is, and possibly why Gson is doing that? My serializer (below) definitely tells him to make a String from it, yet this object is even unquoted.

FWIW, trying to serialize real-life objects (database rows) that have Option[Blob] fields with real Blobs, I even get a StackOverflow error.

Here is how I wrote the serializers:

class OptionSerializer extends JsonSerializer[Option[Any]] {
  def serialize(src: Option[Any], typeOfSrc: Type, context: JsonSerializationContext): JsonElement = {
    src match {
      case None => JsonNull.INSTANCE
      case Some(v) => context.serialize(v)
    }
  }
}

class BlobSerializer extends JsonSerializer[java.sql.Blob] {
  override def serialize(src: java.sql.Blob, typeOfSrc: Type, context: JsonSerializationContext): JsonElement = {
    val s: String = utils.blob2String(v)
    context.serialize(s)
  }
}

class BlobOptionSerializer extends JsonSerializer[Option[java.sql.Blob]] {
  override def serialize(src: Option[java.sql.Blob], typeOfSrc: Type, context: JsonSerializationContext): JsonElement = {
    src match {
      case None => JsonNull.INSTANCE
      case Some(v: java.sql.Blob) =>
        val s: String = utils.blob2String(v)
        context.serialize(s)
    }
  }
}

private val builder = new GsonBuilder()
builder.registerTypeAdapter(classOf[java.sql.Blob], new BlobSerializer)
builder.registerTypeAdapter(classOf[Option[java.sql.Blob]], new BlobOptionSerializer)
builder.registerTypeAdapter(classOf[Option[Any]], new OptionSerializer)
val gson = builder.create()

The tests that produce the above result:

case class B(x: Option[Int], y: String)
case class C(x: java.sql.Blob)
case class D(x: Option[java.sql.Blob])

"serialize options" in {
  val b = B(Some(1), "asdf")
  gson.toJson(b) must be ("{\"x\":1,\"y\":\"asdf\"}")
}

"serialize a Blob" in {
  val c = C(utils.string2Blob("asdf"))
  gson.toJson(c) must be ("{\"x\":\"asdf\"}")
}

"serialize an Option[Blob]" in {
  val d = D(Some(utils.string2Blob("asdf")))
  gson.toJson(d) must be ("{\"x\":\"asdf\"}")
}

And my conversion methods from and to Blob, just in case:

def string2Blob(s: String) = {
  new SerialBlob(s.getBytes)
}

def blob2String(blob: java.sql.Blob): String = {
  if (blob.length == 0)
    return ""  // Array[Byte]()
  val b: Array[Byte] = blob.getBytes(1, blob.length.toInt)
  blob.free
  new String(b)
}

回答1:


Found the solution, special-casing the Blob type inside the serializer for Option[Any]:

class OptionSerializer extends JsonSerializer[Option[Any]] {
  def serialize(src: Option[Any], typeOfSrc: Type, context: JsonSerializationContext): JsonElement = {
    src match {
      case None => JsonNull.INSTANCE
      case Some(b: java.sql.Blob) => context.serialize(utils.Sql.blob2String(b))
      case Some(v) => context.serialize(v)
    }
  }
}


来源:https://stackoverflow.com/questions/41833279/scala-gson-cannot-serialize-optionblob

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!