![]() |
Delphi-Version: 5
Erste Schritte mit Rest.Json.pas: Wann braucht man einen eigenen TJsonInterceptor?
Da bin ich wieder. Es werden noch viele Fragen zu diesem Thema kommen da leider selbst in XE7 noch alles vollkommen undokumentiert ist.
Es tut mir leid um den vielen Code, ich habe extra das vorgestern erschienene " ![]() Nehmen wir an, ich habe folgende zwei Typen:
Delphi-Quellcode:
Wandele ich eine TOuterType-Instanz in JSON um, ist die Ausgabe
TInnerType = class(TInterfacedObject, IInterface)
public var [JSonName('someValue')] someValue: Single; public constructor Create(); // Setzt someValue auf 42.99 end; TOuterType = class protected var [JSonName('someSimpleField')] someSimpleField: Integer; [JSonName('someAdvancedField')] someAdvancedField: IInterface; public constructor Create(); // Setzt someSimpleField auf 42 und // someAdvancedField auf eine neue TInnerType-Instanz end;
Code:
. Das Feld "someAdvancedField" fehlt völlig.
{"someSimpleField":42}
Im Beispiel von Daniele Tetis Buch serialisiert er eine Klasse TPhoto nach JSON. Diese Klasse enthält einen TStream. Damit dieser TStream serialisiert wird hängt er ein Attribut
Delphi-Quellcode:
an das Feld. Den
[JSONReflect(ctString, rtString, TStreamInterceptor)]
Delphi-Quellcode:
hat er dann selber geschrieben.
TStreamInterceptor
Was ich dann tat: Ich fühlte mich schlau und fügte meinem Feld "someAdvancedField" ebenfalls folgendes Attribut hinzu:
Delphi-Quellcode:
Als Ergebnis gibt es:
TOuterType = class
protected var [JSonName('someSimpleField')] someSimpleField: Integer; [JSonName('someAdvancedField')] [JSonReflect(ctObjects, rtObject, TJSONInterceptor )] someAdvancedField: IInterface; public constructor Create(); end;
Code:
Ich hatte das Gefühl schon fast da zu sein. Aber ein Blick auf die Implementation von
{"someSimpleField":42,"someAdvancedField":[]}
Delphi-Quellcode:
bringt nur eine Klasse mit leeren Methoden zu Tage. Muss ich jetzt wirklich für jeden Firlefanz einen eigenen Interceptor schreiben? Oder gehe ich hier grade einen völlig falschen Weg?
Rest.JSonReflect.TJSONInterceptor
Ich versuche meine Nerverei so klein wie möglich zu halten, aber mir fehlt irgendwie das Grundverständnis wie die Embarcadero-Serialisierung vonstatten gehen soll: Die letzten Embarcadero-Videos zu JSON behandeln nur trivialste Dinge wie das Anzeigen des JSON-Strings in Memos. Dokumentation scheint überhaupt keine vorhanden. Ich weiß noch nicht einmal, was der Unterschied zwischen dem Kram aus Rest.Json.pas und Data.DBXJSONReflect.pas ist. Das Posten des Beispiels aus dem Buch habe ich bewusst vermieden, Copyright und so. |
AW: Erste Schritte mit Rest.Json.pas: Wann braucht man einen eigenen TJsonInterceptor
So auf Anhieb würde ich sagen, daß ein IInterface nicht gerade viele Felder zum Serialisieren bereit stellt.
|
AW: Erste Schritte mit Rest.Json.pas: Wann braucht man einen eigenen TJsonInterceptor
Das stimmt. Aber er muss es doch nur auf
Delphi-Quellcode:
casten und schon kann er es nach Feldern absuchen wie er es sonst auch macht.
TObject
Ich kann ja ebenso sagen
Delphi-Quellcode:
und bekomme
var
interfacedObj: IInterface; begin interfacedObj := TInnerType.Create(); marshalledObject := TJson.ObjectToJsonObject( interfacedObj as TObject ); WriteLn( marshalledObject.ToJSON() ); end.
Code:
{"someValue":42.99}
|
AW: Erste Schritte mit Rest.Json.pas: Wann braucht man einen eigenen TJsonInterceptor
Zitat:
|
AW: Erste Schritte mit Rest.Json.pas: Wann braucht man einen eigenen TJsonInterceptor
Sagen wir mal so: Wenn ich nur mit Gewalt das "as TObject" reindrücke scheint alles zu funktionieren. Zumindest glaube ich das. Denn das grundlegende Verständnis fehlt mir weiterhin. Warum war das jetzt überhaupt nötig?
Interface-Interceptor über Attribut angehangen:
Delphi-Quellcode:
Interceptor sieht so aus:
TOuterType = class
protected var [JSonName('someInt')] someInt: Integer; [JSonName('someIntf')] [JSONReflect(ctObject, rtObject, Unit2.TJSONInterfaceInterceptor)] someIntf: IInterface; public constructor Create(); end;
Delphi-Quellcode:
unit Unit2;
interface uses Rest.JSonReflect; type TJSONInterfaceInterceptor = class(Rest.JsonReflect.TJSONInterceptor) protected function getAsIInterface(const Data: TObject; const Field: string): IInterface; public function ObjectConverter(Data: TObject; Field: string): TObject; override; end experimental; implementation uses System.Rtti, Rest.Json; { TJSONInterfaceInterceptor } function TJSONInterfaceInterceptor.getAsIInterface(const Data: TObject; const Field: string): IInterface; var rttiType: TRttiType; rttiField: TRttiField; rttiContext: TRttiContext; begin rttiType := rttiContext.GetType(Data.ClassType); rttiField := rttiType.GetField(Field); Result := rttiField.GetValue(Data).AsInterface; end; function TJSONInterfaceInterceptor.ObjectConverter(Data: TObject; Field: string): TObject; begin Result := getAsIInterface(Data, Field) as TObject; end; initialization TJSONInterfaceInterceptor.ClassName(); end. Erhaltene Ausgabe:
Code:
{"someSimpleField":42,"someAdvancedField":{"someValue":42.25}}
|
AW: Erste Schritte mit Rest.Json.pas: Wann braucht man einen eigenen TJsonInterceptor
Zitat:
|
AW: Erste Schritte mit Rest.Json.pas: Wann braucht man einen eigenen TJsonInterceptor
Du hast, wie immer, Recht. Das würde ich auch gar nicht erwarten, das ist eigentlich Aufgabe des Entwicklers.
Ich bin nur verwirrt, dass diese paar Zeilen Extra-Arbeit für etwas allgemeingültiges nötig waren. Nicht, dass es hier doch einen Standard-Weg gibt, und ich kenne ihn nur nicht? Und ob ich mich nur einbilde, es funktioniere. |
AW: Erste Schritte mit Rest.Json.pas: Wann braucht man einen eigenen TJsonInterceptor
Etwas Licht sollte ein Blick in die Methode TTypeMarshaller<TSerial>.MarshalSimpleField in Data.DBXJSONReflect.pas bringen.
|
AW: Erste Schritte mit Rest.Json.pas: Wann braucht man einen eigenen TJsonInterceptor
Danke, da bin ich schon durchgeschwommen. Ich würde im Aufruf noch eins höher auf
Delphi-Quellcode:
gehen. Die ist nicht nur (trotz der Größe) gut lesbar, sondern hat auch Dokumentation (die es nicht ins Docwiki geschafft hat):
TTypeMarshaller<TSerial>.MarshalData(Data: TObject);
Zitat:
Auch: Kommentar aus DbxJsonReflect.pas: Zitat:
Produktiv habe ich heute bislang fast nichts geschafft, aber immerhin einiges gelernt :-) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:02 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz