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)
}
Second Serialization.read导致异常:net.liftweb.json.MappingException:名称没有可用值。
我怎么可能从json读取数据到case类,但如果缺少某些字段,它们会被case类的默认值替换?
答案 0 :(得分:5)
看起来很长一段时间都有这样的公开票: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")
}
答案 1 :(得分: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}"""))
我猜您可以通过创建User的模板实例,然后将每个字段的默认值传递给Reads.pure
而不是在那里对字符串进行硬编码来提供默认参数的默认值。
答案 2 :(得分:4)
这是一个Play解决方案,它不需要您指定默认值两次或在某个奇怪的地方 - 它使用宏来在编译时找到适当的默认值。
首先是案例类:
case class User(id: Int = 0, name: String = "John Doe", gender: String = "M")
接下来,您需要按我在this blog post中的描述定义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
因为宏不支持它,但它可以很容易地变得更加通用 - 它只是一个快速的概念验证。
答案 3 :(得分:0)
大多数scala JSON库都会对此产生影响。
我们使用内部JSON库,它使用宏为缺少的字段提供合理的默认值。 (也将Null区分为none,将Undefined区分为默认值。因此,如果需要,可以选择默认值为Some的选项)
希望尽快开源。
编辑:基本上,我不知道其他任何人这样做。但它是一个不断变化的生态系统,很想知道是否有其他人已经解决了它