2014-02-13 5 views
4

Я пытаюсь найти некоторую помощь для применения JsonFormat, расширенного по умолчаниюJsonProtocol , к классу, содержащему последовательность объектов.Предоставление JsonFormat для последовательности объектов

Таким образом, для классов:

class Person(val name: String, [......], val adresses: Seq[Adress]) 
class Adress(val streetname: String, val plz: BigDecimal, val city: String) 

Теперь я хотел бы применить свои JsonFormat:

object PersonJsonProtocol extends DefaultJsonProtocol { 
    implicit object PersonJsonFormat extends RootJsonFormat[Person] { 
    def write(pers: Person) = JsObject(
    "name" -> JsString(pers.name), 
    [......], 
    "adresses" -> JsArray(pers.adresses) 
) 
def read(value: JsValue) = {...} 
} 

Но на самом деле я не знаю, как это сделать. Я просмотрел документацию по распылению и joun, google, stackoverflow & Co. Я совершенно не знаком с Scala/Spray и, возможно, просто не понимаю смысла. Так что, возможно, кто-то здесь так добр, чтобы помочь мне. Без последовательности адреса я буду работать.

С JsArray, как представлено в примере, я получаю несоответствие типа. Он просматривает список [JsValue], но также преобразует его в список несоответствий.

Я также попытался вставляет отдельную AdressJsonProtocol и включить его с помощью: «адреса» -> AdressJsonFormat.write (pers.adresses), но еще раз это последовательность ...

ответ

2

Посмотрите на источник spray.json.CollectionFormats.

Вот работоспособная реализация:

import spray.json._ 

class Adress(val streetname: String, val plz: BigDecimal, val city: String) 

class Person(val name: String, val adresses: Seq[Adress]) 

object PersonJsonProtocol extends DefaultJsonProtocol { 
    implicit object AdressJsonFormat extends RootJsonFormat[Adress] { 
    def write(addr: Adress) = JsObject(Map(
     "streetname" -> JsString(addr.streetname), 
     "plz" -> JsNumber(addr.plz), 
     "city" -> JsString(addr.city) 
    )) 
    def read(value: JsValue): Adress = ??? 
    } 
    implicit object PersonJsonFormat extends RootJsonFormat[Person] { 
    def write(pers: Person) = JsObject(Map(
     "name" -> JsString(pers.name), 
     "adresses" -> JsArray(pers.adresses.map(_.toJson).toList) 
    )) 
    def read(value: JsValue): Person = ??? 
    } 
} 

object Main extends App { 
    import PersonJsonProtocol._ 
    val person = new Person("joe", Seq(new Adress("street", 123, "city"))) 
    println("poso's default toString: %s".format(person)) 
    val personJVal = person.toJson 
    println("JValue's toString: %s".format(personJVal)) 
    val personJson = personJVal.prettyPrint 
    println("pretty-printing: %s".format(personJson)) 
} 

, который дает:

poso's default toString: [email protected] 
JValue's toString: {"name":"joe","adresses":[{"streetname":"street","plz":123,"city":"city"}]} 
pretty-printing: { 
    "name": "joe", 
    "adresses": [{ 
    "streetname": "street", 
    "plz": 123, 
    "city": "city" 
    }] 
} 
+0

Спасибо за подсказку с "spray.json.CollectionFormats" и JsArray (pers.adresses.map (_. ToJson) .toList) сделал трюк! Спасибо огромное! – Klink

8

Вам не нужно написать DefaultJsonProtocol для каждого класса case, за исключением случаев, когда вам нужна специальная логика (форматирование, фильтрация ...)

Вы пытались просто использовать сериализацию класса case по умолчанию?

implicit val formatPerson = jsonFormat6(Adress) 
implicit val formatAddress = jsonFormat3(Adress) 

Число в jsonFormat «числа» означает количество членов в вашем случае класса.

Тогда спрей-джсон позаботится о вашей вложенной коллекции адресов при сериализации лица.

+1

Спасибо я уверен, что это будет работать тоже, но я хотел бы использовать DefaultJsonProtocol для доступа к списку имен JSon и предоставленных значения напрямую и отдельно от первоначального класса. Я должен был сказать это в оригинальной записи. Извините, я хочу проголосовать за ваш ответ, но у меня еще нет репутации. Но спасибо вам также! – Klink

+0

@Klink: Что вы имеете в виду, когда говорите: «Я хотел использовать DefaultJsonProtocol для доступа к именам Json и предоставленным значениям напрямую и отдельно от исходного класса»? –

+0

@DaveSwartz Извините, что снова неясно. Поэтому я имел в виду, что расширение DefaultJsonProtocol позволяет мне обрабатывать информацию, предоставленную в результате Json. Например: «имя» -> JsString (имя): также может быть «имя» -> JsString (pers.name + "," + pers.title) или "person-name" -> JsString (pers .name) – Klink