2014-04-24 8 views
11

Załóżmy, że mam klasy etui z następującej konfiguracji:Łączenie typu i terenowych serializers

case class Place(id:java.util.UUID, name:String) 

mogę napisać (działa!) Serializatora dla tego typu w następujący sposób:

class placeSerializer extends CustomSerializer[Place](format => (
     { 
      case JObject(JField("id", JString(s)) :: JField("name",JString(x)) :: Nil) => 
       Place(UUID.fromString(s), x) 
     }, 
     { 
      case x:Place => 
       JObject(
        JField("id", JString(x.id.toString())) :: 
        JField("name", JString(x.name)) :: Nil) 
     } 
     ) 
    ) 

Ale zakładając, że moja klasa przypadków ma w końcu znacznie więcej pól, może to doprowadzić do wyliczenia całej struktury obiektu za pomocą AST, tworząc coś, co jest bardzo szczegółowe, aby zakodować prymitywy.

json4s wydaje się mieć serializatory pola, które mogą działać tylko w określonych polach, z dołączonymi metodami, które pozwalają łatwo przekształcać nazwy i odrzucić pola. Te jednak mają następujący podpis dla swoich serialize i deserialize funkcja częściowa:

case class FieldSerializer[A: Manifest](
    serializer: PartialFunction[(String, Any), Option[(String, Any)]] = Map(), 
    deserializer: PartialFunction[JField, JField] = Map() 
) 

Rejestracja JField (typ że representes klucz -> val z JSON) jest jego własny rodzaj i nie podklasą JValue, jak połączyć te dwa typy serializerów, aby poprawnie zakodować klucz id według nazwy na UUID, zachowując domyślną obsługę pozostałych pól (które są typami pierwotnymi).

Zasadniczo chciałbym, aby łańcuch formatu rozumiał pole w zakresie Place to UUID, bez konieczności określania struktury AST dla wszystkich pól, które można już obsłużyć w przypadku pól, które DefaultFormats.

To, czego szukam, to naśladować wzór podobny do JSONEncoder and JSONDecoder interfaces in python, który może wykorzystywać nazwę klucza oraz typ wartości, aby określić, w jaki sposób obsłużyć układanie pola.

+6

Downvotes bez komentarzy mnie smutno :( – DeaconDesperado

+0

sprawdź również http://stackoverflow.com/questions/23977779/is-there-an-out-of-the-box-format-for-uuid-in-json4s dla specyficzny numer UUID – iwein

Odpowiedz

5

Sztuką jest, aby nie napisać serializatora dla danego typu, ale dla typu, który używasz wewnątrz (w tym przypadku java.util.UUID)

Następnie można dodać, że serializatora do przybornika i Odtąd każdy rodzaj używając UUID będzie działać dokładnie tak, jak przy użyciu obsługiwanych typów pól DefaultSerializer zrobił:

case object UUIDSerialiser extends CustomSerializer[UUID](format => (
    { 
     case JString(s) => UUID.fromString(s) 
     case JNull => null 
    }, 
    { 
     case x: UUID => JString(x.toString) 
    } 
) 
) 

implicit val json4sFormats = Serialization.formats(NoTypeHints) + UUIDSerialiser 

Aktualizacja link the PR

Upda Te 2 PR została połączona, a teraz, w przypadku UUID można użyć:

import org.json4s.ext.JavaTypesSerializers 

implicit val json4sFormats = Serialization.formats(NoTypeHints) ++ JavaTypesSerializers.all 
+0

Dzięki @iwein! Nadal przyzwyczajając się do magii implikacji ... trudno przełamać stare imperatywne nawyki. – DeaconDesperado

+0

cieszę się, że mogę pomóc @DeaconDesperado – iwein

10

Istnieje obecnie UUID serializer w opakowaniu Cechy specjalne json4s. Najprawdopodobniej będzie dostępna w wersji 3.2.11 (która nie została opublikowana od tego czasu).

Będziesz w stanie zrobić coś takiego:

import org.json4s.ext.JavaTypesSerializers 

implicit val json4sFormats = Serialization.formats(NoTypeHints) ++ JavaTypesSerializers.all 

ta została podjęta from the tests for this feature's PR.

+0

Uwielbiam to, gdy moje odpowiedzi stają się nieaktualne przez kogoś łączącego moje prośby o pociągnięcie :) +1 za dobre znalezisko, mam nadzieję, że nie masz nic przeciwko, że zaktualizowałem swoją odpowiedź, aby odzwierciedlić nową rzeczywistość. – iwein

+0

Przy okazji, link do testu jest zepsuty, możesz po prostu utworzyć link do żądania ściągnięcia, tak jak zrobiłem: https://github.com/json4s/json4s/pull/130/files – iwein