2009-04-07 10 views
3

Für Kontext speichern wir die meisten unserer Daten als JSON-Zeichenfolgen. Dies funktioniert sehr gut mit Hadoop im Backend und ist in Ruby am Frontend einfach zu handhaben. Meine Datentypen entsprechen dem natürlichen Muster für die Vererbung.Polymorphismus oder Vererbung in JSON mit Java und Ruby

Der Einfachheit halber sagen wir, ich habe eine Klasse Pet und ein Prozess FeedPet, die ein Haustier füttert. Ich habe auch einen Prozess WalkDog, der nur für Hund gilt, der eine Art Haustier ist. Meine Daten sind so organisiert, dass ich mir keine Sorgen machen muss, dass ich versuchen muss, ein Haustier zu gehen, das kein Hund ist.

Was ich tun möchte ist Pet und Hund erweitert Pet, mit Hund eine zusätzliche Methode "getLeash()", aber ich kann nicht herausfinden, wie dies zu JSON zuordnen.

Stattdessen habe ich eine Klasse Pet mit einem Dataset hashmap, also würde der WalkDog-Prozess pet.getSpeciesData ("Leine") anstelle von dog.getLeash() aufrufen.

Ich kann einen Hund erstellen erweitert Pet, und ich kann das zu JSON mit der Jackson-Bibliothek serialisieren. Das JSON-Objekt wird ein Leine-Feld haben. Aber gehe davon aus, dass ich alle Haustiere füttern möchte. Alle Haustiere haben eine getFood() Methode. Der FeedPet-Prozess deserialisiert also die Objekte an Pet. Aber das verliert das Leine-Feld.

Der WalkDog-Prozess kann dies tun, weil er weiß, dass alle seine Eingaben Hunde sein werden, so dass er es als Hund lesen und als Hund zurückschreiben kann.

Gibt es eine Möglichkeit, Java-Objekte zu JSON serialisieren, so dass ich ihren Typ beibehalten kann? Ich denke etwas wie Rails Single Table Vererbung, aber es müsste etwas sein, dass die JSON-Bibliotheken verstehen.

Antwort

2

Um es funktionieren zu lassen, müssen Sie einige Objekttypinformationen in Daten einbetten (wo es nur zur Deserialisierung nützlich ist) und normalerweise eine externe Schemadefinition verwenden, die sonst nicht benötigt würde (wie XML Schema für xml; generisches System). Dies hat die gleichen Probleme wie ORM: Hibernate muss hässliche Workarounds verwenden (n + 1-Wege-Joins, "Super Tables" oder Diskriminatorfelder).

Oder anders ausgedrückt: Datenmapping/Bindung ist nicht ganz dasselbe wie Objektserialisierung/Deserialisierung (letztere versucht, mehr von der Objektidentität zu erhalten).

Hier gehe ich davon aus, dass, was Sie wollen, ist im Grunde so etwas wie:

Pet pet = mapper.readValue(jsonString, Pet.class); 
// (and possibly get an exception if Pet is an abstract class...) 
Leash l = ((Dog) pet).getLeash(); 

Ist dies nicht der Fall ist, könnten Sie einfach binden einfach Hund

Dog dog = mapper.readValue(jsonString, Dog.class); 

Wie auch immer: Jackson Projekt hat feature request for doing just this, die Sie tun können, was (ich denke) Sie wollen.

Diese Lösung wird jedoch hauptsächlich für Java funktionieren, da es keine Standardmethode zum Übergeben von Informationen zum Objekttyp in JSON gibt. Mit XML kann dies mit XML-Schema durchgeführt werden definiert "xsi: type" -Attribut; welches den Schematyp identifiziert, der dann der Klasse zugeordnet wird (ja, ziemlich komplizierte Art, aber es funktioniert).

UPDATE: Jackson 1.5 hinzugefügt für diese Unterstützung (d.h. implementiert JACKSON-91 Feature-Request), so kann es zur Erzeugung von Typbezeichner verwendet werden, korrekte Handhabung von polymorphen Typen zu ermöglichen. Es sollte auch mit Nicht-Java-Systemen funktionieren, vorausgesetzt, Sie können Details darüber vollständig konfigurieren, wie Typinformationen enthalten sein sollen. und ist NICHT darauf beschränkt, Java-Klassennamen zu verwenden.

+0

Ich denke, Sie haben den Kern davon beantwortet, es gibt keine Standardmethode, dies in JSON darzustellen. JACKSON-91 würde mir genau das geben, was ich will, denn in meinem Fall lese ich nur die Daten in Ruby. –

+0

Ah ok. Eigentlich würde 91 nur benötigt, wenn Sie es in Java lesen müssten. Um Klasseninformationen zu schreiben, könnte es leichtere Wege geben (91 würde das natürlich auch abdecken). Eine Möglichkeit wäre, Object.getClass() serialisierbar zu machen (SerializationConfig.Feature.OUTPUT_CLASS_NAME?). – StaxMan

0

Ich hatte nicht so viel Erfahrung mit JSON als für Fixtures in Django, aber in diesem Fall habe ich nur einen "Modell" -Schlüssel mit dem zugehörigen Wert.

Es liegt dann an dem Programm, das die Objekte interpretiert, um ihren Typ und ihre Vererbungshierarchie zu bestimmen.

Was ich versuche zu sagen ist, dass es irrelevant ist, welche Methoden zur Verfügung stehen, da diese nicht serialisiert werden müssen. Nur der Name und die Attribute des Objekts.

- update

Nach Ihrer Frage wieder zu lesen, scheint es, wie Ihr Prozess in der übergeordneten Klasse ist deserialising, anstatt die eigentliche Klasse. Da Ihre Hundeklasse von Haustier erbt, möchten Sie nur sicherstellen, dass Ihr Deserialiser Objekte der am meisten spezialisierten Klasse erstellt.

Ich weiß nicht über die Jackson-Bibliothek, aber wenn Sie es einrichten können, um eine Art von Modellfeld zu haben, dann könnte das das Ziel sein.