2016-06-22 14 views
2

Ich habe einen Anwendungsfall, in dem ich eine User-Entity zu json serialisieren möchte. Diese Benutzereinheit enthält private Felder, die nicht angezeigt werden sollen, z. B. ein Kennwort.Serialize auf Json mit einer benutzerdefinierten Schreibt in Scala Play 2.4 gesetzt

Ich bin eine benutzerdefinierte OWrites mit damit umgehen, wenn ich einen einzelnen Benutzer zurück:

val userSafeWrites: OWrites[User] = (
     (__ \ EMAIL_FIELD).write[String] ~ 
     (__ \ FIRST_NAME_FIELD).write[String] ~ 
     (__ \ LAST_NAME_FIELD).write[String] ~ 
     (__ \ PHONE_NUMBER_FIELD).write[Option[String]] ~ 
     (__ \ ID_FIELD).write[Long] 
    )(p => (p.email, p.firstName, p.lastName, p.phoneNumber, p._id.get)) 

und ich das OWrites dann angeben, anstatt die impliziten verwenden:

Ok(Json.toJson(user)(User.userSafeWrites)) 

jedoch Ich muss jetzt eine Set[User] zurückgeben.

Wie kann ich das tun? Muss ich eine OWrites[Set[User]] implementieren? Ich kann verstehen, wie das zu tun, wenn ich mit den Ergebnissen, wie ein Objekt mit einem Feldnamen zurück war:

{ 
    "users": [{user1}, {user2}] 
} 

Allerdings möchte ich einfach ein Array zurück, mit dem Ausgang in anderen Endpunkten comform :

[{user1}, {user2}] 

Oder sollte ich jedes Element des Satzes auf einen JSObject und gelten die benutzerdefinierten OWrites jedem Objekt abbilden? Was wäre der effizienteste Weg, das zu tun?

Ich fühle das ist etwas ziemlich einfach und ich bin nur ein Trottel für nicht die Antwort selbst zu finden.

+0

Sie müssen Ihre 'OWrites [User]' im impliziten Bereich "exponieren" (entweder explizit importieren, oder im Companion-Objekt von 'User'). Dann werden die von Play bereitgestellten 'Schreibt [Set [T]] 'mit' T = User 'arbeiten, ohne dass mehr zu tun ist. – cchantep

+0

In diesem Fall kann ich die OWrites nicht als implizit haben, weil ich bereits einen anderen OWrites [Benutzer] im impliziten Bereich habe. Ich habe zwei verschiedene Serialisierungsanforderungen für diese Klasse. – redwulf

+0

Nichts hindert Sie, dieses als ein lokales implizites zu importieren (nur innerhalb des Bereichs einer Funktion, nicht für die ganze Klasse). – cchantep

Antwort

1

Sie schreibt für verfahrbaren Neuimplementierung, die trivial sowieso sind aber nach wie vor. Eine weitere Option ist die Wiederverwendung dass Writes

val users: Set[User] = ??? 
Json.toJson(users)(Writes.traversableWrites(userSafeWrites)) 

Writes für Traversable sind wie folgt definiert:

implicit def traversableWrites[A: Writes] = Writes[Traversable[A]] { as => 
    JsArray(as.map(toJson(_)).toSeq) 
} 

Welches ist genau das, was Sie getan haben.

Es dauert als impliziter Parameter des Typs Writes[A] und verwendet es, um jedes Mitglied zu schreiben. Sie können diesen Parameter explizit übergeben, um die gewünschte Writes zu erhalten.

Eine andere Option wie @cchantep erwähnt ist nur zu importieren, wo Sie es brauchen.

Zum Beispiel mit Standard einige Modell mit schreibt

case class User(num: Int) 

object User { 
    implicit val writes = Json.writes[User] 
} 

und ein weiteres Objekt mit dem benutzerdefinierten schreibt

object OtherWrites { 
    implicit val custom: Writes[User] = new Writes[User] { 
    override def writes(o: User): JsValue = JsNull 
    } 
} 

in der Klasse, die dem Kunden

object Client extends App { 
    val obj = List(User(1)) 
    print(Json.toJson(obj)) 
} 

möchten Sie get [{"num":1}] gedruckt als Standard-Schreibvorgänge sind im impliziten Bereich vorhanden, becau Sie sind in dem Begleitobjekt User definiert.

Sie importieren können benutzerdefinierte schreibt, wo Sie sie brauchen, und solche, die aus Begleiter Objekt

object Client extends App { 
    import test.OtherWrites._ 
    val obj = List(User(1)) 
    print(Json.toJson(obj)) 
} 

Und Sie erhalten gedruckt [null] außer Kraft gesetzt werden.

+0

Yep Json.toJson (Benutzer) (Writes.traversableWrites (userSafeWrites)) hat den Trick gemacht. Viel sauberere Lösung als meine. Tks – redwulf

+0

Beachten Sie, dass wenn Sie z. 'Map [String, List [Set [Option [User]]]]] es wäre schwierig,' Writes [User] 'zu übergeben, und dieser einfache Import könnte Sie davor retten. –

0

Meh, es ist so einfach wie:

Ok(JsArray(userSet.map(user => Json.toJson(user)(User.userSafeWrites)).toSeq)) 

Verbrauchte über eine Stunde googeln und zu versuchen, das Problem zu lösen in der lächerlichsten Art und Weise vor, die Frage der Veröffentlichung. Es wurde in einer Minute nach dem Posten der Frage gelöst.

Einen jener Tage ... , es sei denn es einen besseren Weg, es zu tun