简体   繁体   English

Play Framework 2.3 Scala-使用隐式Writes转换器将嵌套对象序列化为JSon

[英]Play Framework 2.3 Scala - Serialize nested objects to JSon with implicit Writes converters

I need for a frontend jquery-component a specific json object like this (ajax response): 我需要一个前端jquery-component一个像这样的特定json对象(ajax响应):

[
    {"division":"IT", "contacts":[
        {“firstname”:”Carl”, “surname”:”Smith”, “empID”:1},
        {“firstname”:”Henry”, “surname”:”Miller”, “empID”:2}
]}, 
    {"division":"Sales", "contacts":[
        {“firstname”:”Nancy”, “surname”:”McDonald”, “empID”:3},
        {“firstname”:”Susan”, “surname”:”McBright”, “empID”:4}
]}
]

In Backend the data is read via anorm (MySQL) and transformed in following object: 在后端中,数据是通过anorm(MySQL)读取的,并转换为以下对象:

List(Map("division" -> "IT", "contacts" -> List(c3,c4)), Map("division" -> "Sales",          "contacts" -> List(c3,c4)))

Then I try to serialize the Object to JSon but without success (including implicit Writes converters). 然后,我尝试将Object序列化为JSon,但没有成功(包括隐式Writes转换器)。 Below I made a simplified test case Idea-Worksheet in the same manner: 下面,我以相同的方式制作了一个简化的测试用例Idea-Worksheet:

import play.api.libs.json.{JsValue, Json, Writes}

case class Contact(firstname: String, surname: String, empID: Option[Int])

case class ContactDivisionList(division: String, contacts: Seq[Contact])

implicit val ctWrites = new Writes[Contact] {
  def writes(ct: Contact) = Json.obj(
    "firstname" -> ct.firstname,
    "surname" -> ct.surname,
    "empid" -> ct.empID
  )
}

implicit val sdlWrites = new Writes[ContactDivisionList] {
  def writes(dlist: ContactDivisionList) = Json.obj(
    "division" -> dlist.division,
    "contacts" -> Json.toJson(dlist.contacts)
  )
}


/*
Example
*/
val c1 = Contact("Carl","Smith",Option(1))
val c2 = Contact("Henry","Miller",Option(2))
val c3 = Contact("Nancy","McDonald",Option(3))
val c4 = Contact("Susan","McBright",Option(4))

//Test case 1 ->OK
Json.toJson(List(c1,c2,c3,c4))

//Test case 2 ->OK
val c_comp1=List(Map("contacts" -> List(c1,c2)),Map("contacts" -> List(c3,c4)))
//RESULT --> c_comp1: List[scala.collection.immutable.Map[String,List[Contact]]] =     List(Map(contacts -> List(Contact(Carl,Smith,Some(1)), Contact(Henry,Miller,Some(2)))),   Map(contacts -> List(Contact(Nancy,McDonald,Some(3)), Contact(Susan,McBright,Some(4)))))
Json.toJson(c_comp1)
//res1: play.api.libs.json.JsValue = [{"contacts":    [{"firstname":"Carl","surname":"Smith","empid":1},{"firstname":"Henry","surname":"Miller","empid":2}]},{"contacts":[{"firstname":"Nancy","surname":"McDonald","empid":3},{"firstname":"Susan","surname":"McBright","empid":4}]}]


//Test case 3 ->Fail!!!
val c_comp2 = List(Map("division" -> "IT", "contacts" -> List(c1,c2)),Map("division" ->  "Sales", "contacts" -> List(c3,c4)))
//sdlWrites: play.api.libs.json.Writes[ContactDivisionList]{def writes(dlist:    ContactDivisionList): play.api.libs.json.JsObject} = $anon$2@3738baec

Json.toJson(c_comp2)
//!!!!!Error messages
/*Error:(39, 13) No Json serializer found for type     List[scala.collection.immutable.Map[String,java.io.Serializable]]. Try to implement an    implicit Writes or Format for this type.
Json.toJson(c_comp2)
^

Error:(39, 13) not enough arguments for method toJson: (implicit tjs:    play.api.libs.json.Writes[List[scala.collection.immutable.Map[String,java.io.Serializable]]    ])play.api.libs.json.JsValue.
Unspecified value parameter tjs.
Json.toJson(c_comp2)
^
*/

At the end of the script you can see "Test case 3" that got an error when i execute Json.toJson(c_comp2) -->"No Json serializer found for type..". 在脚本的结尾,您可以看到“测试案例3”,当我执行Json.toJson(c_comp2)时出现错误->“未找到类型的Json序列化器。”。 I try a lot of things but i don't get it right. 我尝试了很多事情,但我做得不好。 The only difference to successful "Test case 2" is that i extend the Map with a String-Tuppel. 成功完成“测试用例2”的唯一区别是,我使用String-Tuppel扩展了Map。

I hope sombody can help me with that issue, Thx 我希望有人可以帮助我解决这个问题,Thx

Best regards Karsten 最好的问候卡斯滕

Your problem is that the Map you have there is mapping String to the least upper bound of String (your division name) and List[Contact] , which happens to be java.io.Serializable . 您的问题是您那里的MapString映射到String (您的部门名称)和List[Contact]的最小上限,后者恰好是java.io.Serializable

scala> case class Contact(firstname: String, surname: String, empID: Option[Int])
defined class Contact

scala> case class ContactDivisionList(division: String, contacts: Seq[Contact])
defined class ContactDivisionList

scala> val c1 = Contact("Carl","Smith",Option(1))
c1: Contact = Contact(Carl,Smith,Some(1))

scala> val c2 = Contact("Henry","Miller",Option(2))
c2: Contact = Contact(Henry,Miller,Some(2))

scala> val c3 = Contact("Nancy","McDonald",Option(3))
c3: Contact = Contact(Nancy,McDonald,Some(3))

scala> val c4 = Contact("Susan","McBright",Option(4))
c4: Contact = Contact(Susan,McBright,Some(4))

scala> Map("division" -> "IT", "contacts" -> List(c1,c2))
res10: scala.collection.immutable.Map[String,java.io.Serializable] = Map(division -> IT, contacts -> List(Contact(Carl,Smith,Some(1)), Contact(Henry,Miller,Some(2))))

I'm not entirely sure the nature of your problem, but if you already have List[ContactDivisionList] , it's pretty straightforward to serialize that to JSON: 我不确定您问题的性质,但是如果您已经有了List[ContactDivisionList] ,将其序列化为JSON很简单:

scala> implicit val contactWrites = Json.writes[Contact]
contactWrites: play.api.libs.json.OWrites[Contact] = play.api.libs.json.OWrites$$anon$2@3676af92

scala> implicit val contactDivisionListWrites = Json.writes[ContactDivisionList]
contactDivisionListWrites: play.api.libs.json.OWrites[ContactDivisionList] = play.api.libs.json.OWrites$$anon$2@2999d17d

scala> Json.toJson(List(ContactDivisionList("IT", List(c1,c2)), ContactDivisionList("Sales", List(c3, c4))))
res2: play.api.libs.json.JsValue = [{"division":"IT","contacts":[{"firstname":"Carl","surname":"Smith","empID":1},{"firstname":"Henry","surname":"Miller","empID":2}]},{"division":"Sales","contacts":[{"firstname":"Nancy","surname":"McDonald","empID":3},{"firstname":"Susan","surname":"McBright","empID":4}]}]

It seems to me that you should avoid having that Map in the first place. 在我看来,您应该首先避免使用该Map I've never worked with anorm before, but I think where you need to be looking at is the code that data structure, because at that point, you've lost typesafety. 我以前从未使用过anorm,但是我认为您需要查看的是数据结构的代码,因为到那时,您已经失去了类型安全性。 You should ideally work with ContactDivisionList or construct your object using the JsValue cases directly. 理想情况下,您应该使用ContactDivisionList或直接使用JsValue案例构造对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM