【问题标题】:Serializing case class with trait mixin using json4s使用 json4s 序列化带有 trait mixin 的案例类
【发布时间】:2014-07-25 17:22:52
【问题描述】:

我有一个案例类 Game,我可以使用 json4s 对它进行序列化/反序列化。

case class Game(name: String,publisher: String,website: String, gameType: GameType.Value)

在我的应用程序中,我使用 mapperdao 作为我的 ORM。因为Game 使用Surrogate Id 我没有id 有它的构造函数的一部分。

但是,当 mapperdao 从数据库返回一个实体时,它使用一个特征提供持久对象的 id。

Game with SurrogateIntId

特征的代码是

trait SurrogateIntId extends DeclaredIds[Int]
{
    def id: Int
}

trait DeclaredIds[ID] extends Persisted

trait Persisted
{
    @transient
    private var mapperDaoVM: ValuesMap = null
    @transient
    private var mapperDaoDetails: PersistedDetails = null
private[mapperdao] def mapperDaoPersistedDetails = mapperDaoDetails

private[mapperdao] def mapperDaoValuesMap = mapperDaoVM

private[mapperdao] def mapperDaoInit(vm: ValuesMap, details: PersistedDetails) {
    mapperDaoVM = vm
    mapperDaoDetails = details
}
.....
}

当我尝试序列化Game with SurrogateIntId 时返回空括号,我认为这是因为 json4s 不知道如何处理附加的特征。

我需要一种方法来序列化 game,只将 id 添加到其属性中,并且几乎与我将这些用于所有 T with SurrogateIntId 的方法一样重要我的域对象。

谁能帮帮我?

【问题讨论】:

  • 我相信这里的答案也应该适合你:stackoverflow.com/questions/22179915/…
  • @NickCecil 感谢您的回复!我认为你是对的,如果这只是一个特征问题,那么字段序列化就会起作用。我实际上需要更改标题并重新提出我的问题,因为这不是我遇到的实际问题(当时我自己并不理解)。我在下面的回答仍然是正确的解决方案,但我的问题实际上是处理我的 DO 被包裹在其中的一个抽象类。这是我使用 ORM 所付出的代价,它在引擎盖下隐藏了如此多的魔力 :)

标签: scala serialization case-class traits json4s


【解决方案1】:

所以这是一个非常具体的解决方案,因为我的问题的根源来自mapperDao 返回 DOs 的方式,但是它可能对一般用途有所帮助,因为我正在研究 json4s 中的custom serializers

关于这个问题的完整讨论可以found on the mapperDao google group

首先,我发现在任何持久化实体(从 mapperDao 返回)上调用 copy() 会返回我的 DO 的干净副本(只是案例类)——然后它可以由 json4s 序列化。但是,我不想在任何时候想序列化 DO 或处理映射列表等时都必须记得调用 copy(),因为这会很笨重并且容易出错。

所以,我创建了一个CustomSerializer,它围绕着返回的实体(案例类 DO + 特征作为一个对象),并使用隐式清单从泛型类型中收集类。使用这种方法,我然后对我的域对象进行模式匹配以确定传入的内容,然后使用Extraction.decompose(myDO.copy()) 序列化并返回干净的 DO。

// Entity[Int, Persisted, Class[T]] is how my DOs are returned by mapperDao

class EntitySerializer[T: Manifest] extends CustomSerializer[Entity[Int, Persisted, Class[T]]](formats =>(
  {PartialFunction.empty} //This PF is for extracting from JSON and not needed
,{
  case g: Game => //Each type is one of my DOs
    implicit val formats: Formats = DefaultFormats //include primitive formats for serialization
    Extraction.decompose(g.copy()) //get plain DO and then serialize with json4s
  case u : User =>
    implicit val formats: Formats = DefaultFormats + new LinkObjectEntitySerializer //See below for explanation on LinkObject
    Extraction.decompose(u.copy())
  case t : Team =>
    implicit val formats: Formats = DefaultFormats + new LinkObjectEntitySerializer
    Extraction.decompose(t.copy())
...
}

唯一需要单独的序列化程序的情况是,如果您将非基元作为正在序列化的案例类的参数,因为序列化程序不能使用自己进行序列化。在这种情况下,您为每个基本类创建一个序列化程序(即只有原语的 IE),然后将其包含到下一个序列化程序中,其中包含依赖于这些基本类的对象。

class LinkObjectEntitySerializer[T: Manifest] extends CustomSerializer[Entity[Int, Persisted, Class[T]]](formats =>(
  {PartialFunction.empty},{
         //Team and User have Set[TeamUser] parameters, need to define this "dependency"
         //so it can be included in formats
  case tu: TeamUser => 
    implicit val formats: Formats = DefaultFormats
    ("Team" ->                     //Using custom-built representation of object
      ("name" -> tu.team.name) ~
      ("id" -> tu.team.id) ~
      ("resource" -> "/team/") ~
      ("isCaptain" -> tu.isCaptain)) ~
    ("User" ->
      ("name" -> tu.user.globalHandle) ~
      ("id" -> tu.user.id) ~
      ("resource" -> "/user/") ~
      ("isCaptain" -> tu.isCaptain))
}
  ))

这个解决方案很难令人满意。最终我将需要替换 mapperDao 或 json4s(或两者)来找到更简单的解决方案。但是,就目前而言,它似乎是开销最少的修复方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-21
    • 2014-10-28
    • 1970-01-01
    • 2016-01-13
    • 1970-01-01
    • 2014-08-18
    相关资源
    最近更新 更多