2016-01-26 2 views
0

У меня есть контактный класс,
он читает (JsPath \ "contact_name" \ "first_name") до firstName, но (JsPath \ "contact_name") может быть пустым.
Кто-нибудь знает, как сделать Reader для этого класса?PlayJson Scala Read Nullable Fields

case class Contact(var firstName: Option[String], 
        var lastName: Option[String]) 

И мой контакт Json является:

{ 
    "contact_name": { 
    "first_name": "hello", 
    "last_name": "world" 
    }, 
    "phone_number": "1231231234", 
    "email": "[email protected]" 
} 

Контакт Json без "CONTACT_NAME":

{ 
    "phone_number": "1231231234", 
    "email": "[email protected]" 
} 

Я хочу, чтобы оба Json, чтобы иметь возможность читать Контакт объекты. Спасибо.

ответ

1

Предположим, что ваш номер телефона и адрес электронной почты являются частью контактной информации, вот один, который работает (вы можете использовать \\ для поиска путей в глубину):

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

case class Contact(firstName: Option[String], lastName: Option[String], 
        phone: String, email: String) 

val contactReads: Reads[Contact] = (
    (__ \\ "first_name").readNullable[String] and 
    (__ \\ "last_name").readNullable[String] and 
    (__ \ "phone_number").read[String] and 
    (__ \ "email").read[String] 
)(Contact.apply _) 

val json1 = """{ 
    | "contact_name": { 
    | "first_name": "hello", 
    | "last_name": "world" 
    | }, 
    | "phone_number": "1231231234", 
    | "email": "[email protected]" 
    |}""".stripMargin 

Json.parse(json1).validate[Contact](contactReads) 
// JsSuccess(Contact(Some(hello),Some(world),1231231234,[email protected]),) 

val json2 = """{ 
    | "phone_number": "1231231234", 
    | "email": "[email protected]" 
    |}""".stripMargin 

Json.parse(json2).validate[Contact](contactReads) 
// JsSuccess(Contact(None,None,1231231234,[email protected]),) 
0

я пишу пост о том, что - http://pedrorijo.com/blog/scala-json/

Подходит к тому, как читать классы json для классов. В частности, чтение необязательных полей из json, в последнем примере:

case class User(username: String, friends: Int, enemies: Int, isAlive: Option[Boolean]) 

object User { 

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

    implicit val userReads: Reads[User] = (
     (JsPath \ "username").read[String] and 
     (JsPath \ "friends").read[Int] and 
     (JsPath \ "enemies").read[Int] and 
     (JsPath \ "is_alive").readNullable[Boolean] 
    ) (User.apply _) 
} 

Этого должно быть достаточно, чтобы вы это сделали. Кроме того, если json является строка с нужными полями, вы можете просто написать:

Json.parse(json) 

так, если fullJson является полным объектом Json (с этими нежелательными полями), можно просто извлечь ПгвЬЫате и LastName с fullJson \ "contact_name"

0

чтобы упростить вещи, которые я сделал что-то вроде этого (хотя это создать много классов):

Предположения: CONTACT_NAME не является обязательным, и вы хотите, чтобы свернуть все это в одном случае класса Contact.

{ 
    "contact_name": { 
    "first_name": "hello", 
    "last_name": "world" 
    }, 
    "phone_number": "1231231234", 
    "email": "[email protected]" 
} 


case class Contact(firstName: Optional[String], lastName: Optional[String], phoneNumber: String, email: String) 

case class RawContactName(firstName: String, lastName: String) 
case class RawContact(contactName: Optional[RawContactName], phoneNumber: String, email: String) 

implicit val rawContactReads: Reads[RawContact] = (
     (JsPath \ "contact_name").readNullable[RawContactName] and 
     (JsPath \ "phone_number").read[String] and 
     (JsPath \ "email").read[String] 
    ) (RawContact.apply _) 

implicit val rawContactNameReads: Reads[RawContactName] = (
     (JsPath \ "first_name").read[String] and 
     (JsPath \ "last_name").read[String] 
    ) (RawContactName.apply _) 

def transformContact(rawContact: RawContact): Contact = { 
    val (maybeFirstName, maybeLastName) = rawContact.contactName match { 
     case Some(RawContactName(firstName, lastName)) => (Some(firstName), Some(lastName)) 
     case None => (None, None) 
    } 
    Contact(maybeFirstName, maybeLastName, rawContact.phoneNumber, rawContact.email) 
} 

Эффективен, у меня есть отдельные классы тематических для представления каждого из JSON узлов и функции трансформатора, чтобы преобразовать представление Scala JSON в мой класс модели. Это действует, если у вас есть повторяющиеся значения (например, несколько объектов-контактов в одном документе JSON, поэтому появятся несколько элементов first_name). Хотя в вашем конкретном примере может быть лучше пропустить классы Raw и создать два класса case внутри вашей модели: Contact и ContactName, но я хотел продемонстрировать общее решение, которое отделяет модель View (Raw...) от внутренней модели.