如何使用play-json忽略空对象?

时间:2018-11-21 19:01:58

标签: scala serialization playframework case-class play-json

我是Scala和函数式编程的新手,所以这个问题可能有一个非常简单的答案。但是,我无法弄清楚,所以在这里:

我有一个案例类层次结构,它表示编译器中的抽象语法树。在某个时候,我有List[Statement]形式的语句列表。这将使用对象的Json数组进行序列化,其中每个对象代表一条语句。但是,某些类型的语句是多余的,因此我不想序列化它们。例如,返回void。以下代码有望澄清这一点:

sealed trait Statement

sealed trait Expression

case object Empty extends Expression

case class Return(e: Expression) extends Statement

我想要的是根本不序列化Return(Empty)。现在我得到类似的东西:

"Return": {}

如何简单地忽略Return(Empty)? 使它更通用。我不想像{}这样的json中有空对象。我如何确定他们没有将其添加到我的json中?

这是我到目前为止尝试过的(但没有成功):

implicit val statementListWrites = StatementListWrites

object StatementListWrites extends Writes[List[Statement]] {
  override def writes(stms: List[Statement]) =
    JsArray(stms.filter(stm => {
      stm match {
        case Return(Empty) => false
        case _ => true
      }
    }).map(s => Json.toJson(s)))
}

也许上述技术可行,但由于某种原因,据我所知,甚至还没有开始。

1 个答案:

答案 0 :(得分:0)

在这种情况下,您应该小心,因为您具有封闭的特质,因此您应该有条理地工作。

让我们将问题分解为较小的问题,假设您只想将对象写入json。那么我们就可以解决删除空对象的问题。

我添加了更多的类来澄清这个想法:

sealed trait Expression
case object Empty extends Expression
case class NonEmptyExpression(x: Int) extends Expression

sealed trait Statement
case class Return(e: Expression) extends Statement
case class NoReturn(x: Int) extends Statement

第一步(提供Expresion的作者):

要执行此操作,您必须为EmptyNonEmptyExpression创建作家,因此我们可以通过以下方式做到这一点:

val emptyExpressionWrites = new Writes[Empty.type] {
  override def writes(e: Empty.type) = Json.obj()
}

val nonEmptyExpressionWrites = Json.writes[NonEmptyExpression]

implicit val expressionWrites = new Writes[Expression] {
  override def writes(exp: Expression) = {
    exp match {
      case Empty => emptyExpressionWrites.writes(Empty)
      case nonEmptyExpression: NonEmptyExpression => nonEmptyExpressionWrites.writes(nonEmptyExpression)
    }
  }
}

第二步(声明的提供者):

您必须提供ReturnNoReturn的作家。请注意,因为我将Return定义为Expression,所以play能够知道如何为expressionWriter创建作者,并且它具有implicit。因此它知道如何立即序列化Expression

val returnWrites = Json.writes[Return]
val noReturnWrites = Json.writes[NoReturn]

val statementWrites = new Writes[Statement] {
  override def writes(s: Statement) = {
    s match {
      case r: Return => returnWrites.writes(r)
      case nr: NoReturn => noReturnWrites.writes(nr)
    }
  }
}

让我们对其进行测试以确保其工作正常:

val statementWithNonEmpty = Return(NonEmptyExpression(100))
println(s"statementWithNonEmpty Json: ${statementWrites.writes(statementWithNonEmpty).toString()}")

val statementWithEmpty = Return(Empty)
println(s"statementWithEmpty Json: ${statementWrites.writes(statementWithEmpty).toString()}")

输出为:

  

statementWithNonEmpty Json:{“ e”:{“ x”:100}}

     

statementWithEmpty Json:{“ e”:{}}

最终步骤(创建没有空白的列表编写器):

val listStatementWrites = new Writes[Seq[Statement]] {
  override def writes(o: Seq[Statement]) = {
    val listWithoutEmpty = o.filter {
      case Return(Empty) => false
      case _ => true
    }

    JsArray(listWithoutEmpty.map(statementWrites.writes))
  }
}

让我们尝试一下:

val listOfStatements = List(Return(NonEmptyExpression(100)), Return(Empty), Return(NonEmptyExpression(200)))
println(s"listOfStatements: ${listStatementWrites.writes(listOfStatements).toString()}")

输出为:

  

listOfStatements:[{“ e”:{“ x”:100}},{“ e”:{“ x”:200}}]