2017-08-03 86 views
0

我有一個頂層的Scala類類似下面:斯卡拉對象與ArrayBuffer - 反序列化問題,使用GSON

FinalOutput.scala:

class FinalOutput extends Serializable { 

    @BeanProperty 
    var userId: String = _ 

    @BeanProperty 
    var tenantId: String = _ 

    @BeanProperty 
    @SerializedName("type") 
    var dataType: String = _ 

    @BeanProperty 
    var data: FinalData = _ 

    @BeanProperty 
    var userCreatedDate: String = _ 
} 

FinalData.scala:

class FinalData extends Serializable { 

    @BeanProperty 
    var list1: ArrayBuffer[DataType1] = _ 

    @BeanProperty 
    var list2: ArrayBuffer[DataType2] = _ 

    @BeanProperty 
    var list3: ArrayBuffer[DataType3] = _ 

    @BeanProperty 
    var list4: ArrayBuffer[DataType4] = _ 

    .... 
    .... 

    @BeanProperty 
    var list15: ArrayBuffer[DataType15] = _ 

    @BeanProperty 
    var userName: String = _ 
} 

以及全部DataType*延伸的類BaseBean

我用this將Scala對象序列化成json字符串。

ArrayBufferSerializer.scala

class ArrayBufferSerializer[T: ClassTag] extends JsonSerializer[ArrayBuffer[T]] { 
    override def serialize(src: ArrayBuffer[T], typeOfSrc: Type, context: JsonSerializationContext): JsonElement = { 
    context.serialize(src.toArray[Any]) 
    } 
} 

然後序列化爲字符串中使用這樣的:

val gson = new GsonBuilder().registerTypeAdapter(classOf[ArrayBuffer[FinalData]], new ArrayBufferSerializer[FinalData]()).serializeNulls.create 
val data = gson.toJson(row) 

現在我想做的反序列化JSON字符串FinalOutput對象,所以我創建ArrayBufferDeSerializer東西像這樣

class ArrayBufferDeSerializer[T: ClassTag] extends JsonDeserializer[ArrayBuffer[T]] { 
    override def deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): ArrayBuffer[T] = { 
    context.deserialize(json, typeOfT) 
    } 
} 

然後調用下面deserialzie:

val gson = new GsonBuilder().registerTypeAdapter(classOf[ArrayBuffer[FinalData]], new ArrayBufferSerializer[FinalData]()).serializeNulls.create 
gson.fromJson(row, classOf[FinalLevelOneSmsOutput]) 

得到以下錯誤:

Exception in thread "main" org.apache.spark.SparkException: Job aborted due to stage failure: Task 0 in stage 2.0 failed 1 times, most recent failure: Lost task 0.0 in stage 2.0 (TID 3, localhost, executor driver): java.lang.StackOverflowError 
    at com.google.gson.internal.bind.TypeAdapters$29.read(TypeAdapters.java:720) 
    at com.google.gson.internal.bind.TypeAdapters$29.read(TypeAdapters.java:743) 
    at com.google.gson.internal.bind.TypeAdapters$29.read(TypeAdapters.java:735) 
    at com.google.gson.internal.bind.TypeAdapters$29.read(TypeAdapters.java:718) 
    at com.google.gson.internal.Streams.parse(Streams.java:48) 
    at com.google.gson.TreeTypeAdapter.read(TreeTypeAdapter.java:54) 
    at com.google.gson.Gson.fromJson(Gson.java:861) 
    at com.google.gson.Gson.fromJson(Gson.java:926) 
    at com.google.gson.Gson$1.deserialize(Gson.java:131) 
    at com.cv.util.ArrayBufferDeSerializer.deserialize(ArrayBufferDeSerializer.scala:15) 
    at com.cv.util.ArrayBufferDeSerializer.deserialize(ArrayBufferDeSerializer.scala:13) 
    at com.google.gson.TreeTypeAdapter.read(TreeTypeAdapter.java:58) 

回答

1

你解串器不只是委派反序列化回context使用相同的參數(相同的JSON和同類型),這會導致上下文再次調用解串行器 - 這會創建無限循環並生成StackOverflowError

解串器必須改進 - 因爲我們已經系列化ArrayBuffer s轉換「簡單」的陣列,我們必須反序列化他們相應。這裏有一種方法可以做到這一點:

import com.google.gson.reflect.TypeToken 

class ArrayBufferDeSerializer[T: ClassTag] extends JsonDeserializer[ArrayBuffer[T]] { 
    override def deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): ArrayBuffer[T] = { 
    // since we've serialized ArrayBuffers by converting them to simple Arrays, we deserialize the 
    // input as a simple Array first: 
    val array: util.ArrayList[T] = context.deserialize(json, new TypeToken[Array[T]](){}.getType) 

    // Then, we convert it back into an ArrayBuffer: 
    import collection.JavaConverters._ 
    ArrayBuffer[T](array.asScala: _*) 
    } 
} 
+0

感謝哥們,那完美的工作 –