Scala Gson,无法序列化Option [Blob]
我设法扩展了Gson以处理Scala的 Option
和 Blob
类型,但是我对合并的 Option [java.sql.Blob] 遇到麻烦代码>.
I managed to extend Gson to handle Scala's Option
and Blob
types, but I have trouble with the combined Option[java.sql.Blob]
.
我的测试说
[info]-应该序列化一个选项-确定
[info] - should serialize an Option - OK
[info]-应该序列化Blob-确定
[info] - should serialize a Blob - OK
[info]-应该序列化Option [Blob] *失败*
[info] - should serialize an Option[Blob] * FAILED *
[info] {"x":{"buf":[97,115,100,102],"len":4,"origLen":4}}不等于{"x":"asdf"}
[info] {"x":{"buf":[97,115,100,102],"len":4,"origLen":4}} was not equal to {"x":"asdf"}
能否请您告诉我这个 {"buf":[...]}
对象是什么,以及为什么Gson会这样做?我的序列化程序(如下))绝对告诉他用它创建一个String,但该对象甚至没有被引用.
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,尝试用真实的Blob序列化具有Option [Blob]字段的真实对象(数据库行),我什至会收到*错误.
FWIW, trying to serialize real-life objects (database rows) that have Option[Blob] fields with real Blobs, I even get a * 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()
产生以上结果的测试:
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\"}")
}
还有我从Blob到Blob的转换方法,以防万一:
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)
}
找到了解决方案,在Option [Any]的序列化程序内对Blob类型进行了特殊封装:
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)
}
}
}