2013-04-10 29 views
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) 

} 

Thứ hai serialization.read nguyên nhân ngoại lệ: net.liftweb.json.MappingException: Không có giá trị có thể sử dụng cho tên.Làm thế nào để điền vào trường hợp lớp từ json với một phần dữ liệu?

Làm cách nào tôi có thể đọc biểu mẫu dữ liệu vào lớp chữ thường, nhưng nếu một số trường bị thiếu, chúng sẽ được thay thế bằng giá trị mặc định từ lớp chữ thường?

+0

Trả lời cách thực hiện việc này với thư viện json chơi cũng được chấp nhận. – codez

Trả lời

5

Hình như đã có một sự vé mở cho điều này cho khá trong một: https://www.assembla.com/spaces/liftweb/tickets/534

Trong khi đó, một lựa chọn là sử dụng một 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) 

Điều đó sẽ cung cấp cho bạn:

User(1,None,None) 

Và bạn có thể sử dụng một cái gì đó như thế này để điền vào các giá trị mặc định:

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

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

Các tùy chọn khác là sử dụng nhà thầu bổ sung cho lớp trường hợp của bạn:

case class User(id: Int, name: String, gender: String) 
object User { 
    def apply(id:Int): User = User(id, "John Doe", "M") 
} 
0

Hầu hết các thư viện scala JSON nghẹt thở về điều này.

Chúng tôi sử dụng thư viện JSON nội bộ sử dụng macro để cung cấp mặc định sane cho các trường bị thiếu. (cũng phân biệt giữa Null là không có, và không xác định là mặc định. Vì vậy, bạn có thể có một tùy chọn với một mặc định của một số nếu bạn muốn)

Hy vọng sẽ mở nó sớm.

EDIT: về cơ bản, tôi không biết bất kỳ người nào khác làm điều này. nhưng nó là một hệ sinh thái luôn thay đổi, tò mò muốn xem liệu có ai khác đã giải quyết nó chưa

5

Làm thế nào để thực hiện nó với thư viện json, mặc dù bạn phải cung cấp mặc định trong trình phân tích cú pháp. giá trị:

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}""")) 

tôi đoán bạn có thể cung cấp giá trị mặc định từ tham số mặc định bằng cách tạo ra một mẫu thể hiện của người dùng và sau đó đi qua các mặc định từ từng lĩnh vực để Reads.pure thay vì hardcoding một chuỗi đó.

4

Đây là giải pháp Play không yêu cầu bạn chỉ định mặc định hai lần hoặc ở một số nơi lạ — nó sử dụng macro để tìm mặc định thích hợp lúc biên dịch.

đầu tiên cho lớp trường hợp:

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

Tiếp theo, bạn cần phải xác định DefaultFinder như tôi mô tả trong this blog post. Sau đó, bạn đang thực tế thực hiện:

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 
)) 

Và cuối cùng:

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),) 

Lưu ý rằng tôi không sử dụng getOrElse vì vĩ mô không hỗ trợ nó, nhưng nó có thể dễ dàng được thực hiện hơn General- đó chỉ là một chứng minh khái niệm nhanh.

+2

Không có bình luận về ý tưởng của '" M "' như giới tính mặc định, bằng cách này. –

+0

Nó sẽ là tốt đẹp, nếu vĩ mô có thể tạo ra toàn bộ đọc không chỉ giá trị mặc định duy nhất, nhưng bây giờ nó là giải pháp tốt nhất. – codez

+0

@codez: bạn có thể viết một macro có thể (đó là những gì Play's Inception thực hiện, mặc dù nó không cung cấp chức năng này). Điều tốt đẹp về cách tiếp cận này là nó tổng quát hơn nhiều - bạn có thể sử dụng 'default' theo cách này với bất kỳ thư viện JSON nào. –

Các vấn đề liên quan