7
import net.liftweb.json._
import net.liftweb.json.JsonParser._

object test02 extends App {
    implicit val formats = DefaultFormats
    case class User(
        id: Int = 0,
        name: String = "John Doe",
        gender: String = "M")

    val s1=""" {"id":1,"name":"Bill","gender":"M"} """
    var r1=Serialization.read[User](s1)
    println(r1)

    val s2=""" {"id":1} """
    var r2=Serialization.read[User](s2)
    println(r2)  

}

第二个 Serialization.read 导致异常:net.liftweb.json.MappingException:名称没有可用值。

我怎么可能将数据表单 json 读入案例类,但是如果某些字段丢失,它们会被案例类的默认值替换?

4

4 回答 4

6

看起来已经有很长一段时间了:https ://www.assembla.com/spaces/liftweb/tickets/534

同时,一种选择是使用Option

    case class User(
        id: Int = 0,
        name: Option[String],
        gender: Option[String]) {
      def defaults = copy(
        name   = name   orElse Some("John Doe"),
        gender = gender orElse Some("M"))
    }
    // ...        
    val s2=""" {"id":1} """
    var r2=Serialization.read[User](s2)
    println(r2)  

那应该给你:

 User(1,None,None)

你可以使用这样的东西来填写默认值:

 val r2 = Serialization.read[User](s2).defaults

 // r2: User = User(1,Some(John Doe),Some(M))

另一种选择是为您的案例类使用额外的构造函数:

 case class User(id: Int, name: String, gender: String)
 object User {
   def apply(id:Int): User = User(id, "John Doe", "M")
 }
于 2013-04-10T02:22:30.953 回答
5

如何使用 play json 库来做到这一点,但是,您必须在解析器中提供默认值,而不仅仅是值的默认值:

case class User(id: Int, name: String, gender: String)

import play.api.libs.json._
import play.api.libs.functional.syntax._

implicit val userReads: Reads[User] = (
  (__ \ "id").read[Int] and
  (__ \ "name").read[String].or(Reads.pure("John Doe")) and
  (__ \ "gender").read[String].or(Reads.pure("Male"))
)(User)

Json.fromJson[User](Json.parse("""{"id":1,"name":"Bill","gender":"M"}"""))

Json.fromJson[User](Json.parse("""{"id":1}"""))

Reads.pure我想您可以通过创建 User 的模板实例然后将每个字段的默认值传递给而不是在那里硬编码字符串来提供默认参数的默认值。

于 2014-07-03T08:41:10.650 回答
4

这是一个 Play 解决方案,它不需要您指定两次或在某个奇怪的地方指定默认值——它使用宏在编译时找到适当的默认值。

首先是案例类:

case class User(id: Int = 0, name: String = "John Doe", gender: String = "M")

接下来,您需要DefaultFinder按照我在这篇博文中的描述进行定义。然后你实际上完成了:

import DefaultFinder._

import play.api.libs.json._
import play.api.libs.functional.syntax._

implicit val userReads: Reads[User] = (
  (__ \ 'id).readNullable[Int] and
  (__ \ 'name).readNullable[String] and
  (__ \ 'gender).readNullable[String]
)((id, name, gender) => new User(
  id = if (id.isEmpty) default else id.get,
  name = if (name.isEmpty) default else name.get,
  gender = if (gender.isEmpty) default else gender.get
))

最后:

scala> Json.fromJson[User](Json.parse("""{ "id": 1, "name": "Foo McBar" }"""))
res0: play.api.libs.json.JsResult[User] = JsSuccess(User(1,Foo McBar,M),)

scala> Json.fromJson[User](Json.parse("""{ "id": 2, "gender": "X" }"""))
res1: play.api.libs.json.JsResult[User] = JsSuccess(User(2,John Doe,X),)

请注意,我没有使用getOrElse它是因为宏不支持它,但它可以很容易地变得更通用——它只是一个快速的概念验证。

于 2014-07-05T16:43:18.837 回答
0

大多数 scala JSON 库对此感到窒息。

我们使用内部 JSON 库,该库使用宏为缺失字段提供合理的默认值。(也将 Null 区分为 none 和 Undefined 作为默认值。因此,如果需要,您可以选择默认为 Some 的选项)

希望尽快开源。

编辑:基本上,我不知道有其他人这样做。但它是一个不断变化的生态系统,很想知道是否还有其他人解决了它

于 2014-07-02T22:25:36.637 回答