关于 scala:使用 json4s 序列化带有 trait mixin 的案例类

Serializing case class with trait mixin using json4s

我有一个案例类 Game,使用 json4s 序列化/反序列化没有问题。

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

在我的应用程序中,我使用 mapperdao 作为我的 ORM。因为 Game 使用代理 ID,所以我没有 id 有其构造函数的一部分。

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

Game with SurrogateIntId

特征的代码是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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 执行此操作的方法几乎与我对所有域对象都使用这些方法一样重要。

谁能帮帮我?


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

关于这个问题的完整讨论可以在mapperDao google group上找到。

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 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),然后将其包含到下一个序列化程序中,其中包含依赖于这些基本类的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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(或两者)来找到更简单的解决方案。但是,就目前而言,它似乎是开销最少的修复方法。