Ich habe das für mich jetzt so gelöst, dass ich mir eine Basisklasse TJSONSerializable erstellt habe. Diese geht per
RTTI ihre eigenen Properties durch und schaut, ob diese ein Attribut JSONFieldName aufweisen, in welchem der Keyname des JSON-Pairs angegeben ist. Zum Serialisieren wird ein TJSONObject erzeugt und die erwähnten JSON-Pairs gemäß der Readable-Properties hinzugefügt. Zum Deserialisieren geht das Ganze dann für die Writable-Properties andersherum. Eine spezialisierte generische TObjectList gibt es auch, die erstellt dann ein JSONArray mit Elementen der serialisierten TJSONSerializable-Instanzen. Leider habe ich diese Klasse für die Firma geschrieben und darf sie daher nicht einfach veröffentlichen, aber in dem Zusammenhang gibt es hier einen Thread von mir:
https://www.delphipraxis.net/209157-...-erkennen.html
Da das
IMHO unkritisch ist, kann ich aber zumindest Ausschnitte des Interface-Abschnitts zeigen:
Delphi-Quellcode:
uses System.SysUtils, System.JSON, System.Generics.Collections, System.Rtti;
type
(* Attribut, mit dem gesteuert wird, wie das Feld im JSON-Objekt
heißt/heißen soll *)
JSONFieldNameAttribute = class(TCustomAttribute)
private
FFieldname: string;
public
constructor Create(const AFieldName: string);
property Fieldname: string read FFieldname;
end;
(* Attribut, mit dem angegeben wird, dass der Standardwert des entsprechenden
Property-Datentyps als NULL ausgegeben werden soll. Betrifft nur die
Wandlung in JSON, andersherum nicht, da Delphi keine echten Nullables
kennt. *)
JSONNullIfDefaultAttribute = class(TCustomAttribute);
// Forward-Deklarationen für die Klassenfunktion FromJSON
TJSONSerializable = class;
TJSONSerializableClass = class of TJSONSerializable;
(* Die Parent-Klasse für JSON-Serialisierung. Betrachtet werden alle
Properties, die das JSONFieldName-Attribut (s.o.) haben. Geparst werden
einfache Datentypen, Arrays, Objekte (falls von TJSONSerializable
abgeleitet) und Listen, sofern diese generisch sind.
Heißt: TList<string> wird abgearbeitet, TStringList hingegen nicht.
Wir leiten von TInterfacedObject ab, damit wir in Ableitungen ggf. noch
Interfaces anflanschen können und damit automatische Referenzzählung
haben. *)
TJSONSerializable = class(TInterfacedObject)
public
constructor Create; virtual;
function ToJSON: TJSONObject; virtual;
// Parameter:
// Obj = das zu parsende JSON-Objekt
// AClass = die zu erzeugende konkrete Klasse (Ableitung von TJSONSerializable)
// Um das erzeugte Objekt dann auch vollständig nutzen zu können, muss
// es noch in den konkreten Typ gecastet werden:
// MyObj := TMyObj.FromJSON(JsonObjekt, TMyObj) as TMyObj;
class function FromJSON(const Obj: TJSONObject;
const AClass: TJSONSerializableClass): TJSONSerializable; static;
end;
TJSONSerializableObjectList<T: TJSONSerializable> = class(TObjectList<T>)
public
function ToJSON: TJSONArray; virtual;
class function FromJSON(const Obj: TJSONArray): TJSONSerializableObjectList<T>; static;
end;
Benutzen lässt sich dann beispielsweise so:
Delphi-Quellcode:
type
TUserDB = class(TJSONSerializable)
private
FName: String;
FWinAuth: Boolean;
FIsMySQL: Boolean;
FPort: Word;
FDatabase: String;
FPassword: String;
FUser: String;
FServer: String;
public
[JSONFieldName('Name')]
property Name: String read FName write FName;
[JSONFieldName('Server')]
property Server: String read FServer write FServer;
[JSONFieldName('IsMySql')]
property IsMySql: Boolean read FIsMySQL write FIsMySQL;
[JSONFieldName('User')]
property User: String read FUser write FUser;
[JSONFieldName('Database')]
property Database: String read FDatabase write FDatabase;
[JSONFieldName('Password')]
property Password: String read FPassword write FPassword;
[JSONFieldName('Port')]
[JSONNullIfDefault]
property Port: Word read FPort write FPort;
[JSONFieldName('WinAuth')]
property WinAuth: Boolean read FWinAuth write FWinAuth;
end;
...
UserDB := TUserDB.Create;
...
{TJSONObject}lObj := UserDB.ToJSON;