123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425 |
- { **********************************************************************
- This file is part of the Free Component Library (FCL)
- Copyright (c) 2015 by the Free Pascal development team
-
- Base for REST classes
-
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- unit restbase;
- {$mode objfpc}{$H+}
- { $DEFINE DEBUGBASEOBJMEMLEAK}
- interface
- uses
- typinfo, fpjson, Classes, SysUtils, contnrs;
- Type
- ERESTAPI = Class(Exception);
- TStringArray = Array of string;
- TStringArrayArray = Array of TStringArray;
- TUnicodeStringArray = Array of UnicodeString;
- TIntegerArray = Array of Integer;
- TInt64Array = Array of Int64;
- TInt32Array = Array of Integer;
- TFloatArray = Array of TJSONFloat;
- TFloatArrayArray = Array of TFloatArray;
- TDoubleArray = Array of TJSONFloat;
- TDoubleArrayArray = Array of TDoubleArray;
- TDateTimeArray = Array of TDateTime;
- TBooleanArray = Array of boolean;
- TChildType = (ctArray,ctObject);
- TChildTypes = Set of TChildType;
- { TBaseObject }
- TObjectOption = (ooStartRecordingChanges,ooCreateObjectOnGet);
- TObjectOptions = set of TObjectOption;
- TDateTimeType = (dtNone,dtDateTime,dtDate,dtTime);
- Const
- DefaultObjectOptions = [ooStartRecordingChanges]; // Default for constructor.
- IndexShift = 3; // Number of bits reserved for flags.
- Type
- {$M+}
- TBaseObject = CLass(TObject)
- Private
- FObjectOptions : TObjectOptions;
- fadditionalProperties : TJSONObject;
- FBits : TBits;
- Function GetDynArrayProp(P: PPropInfo) : Pointer; virtual;
- procedure SetDynArrayProp(P: PPropInfo; AValue : Pointer); virtual;
- procedure SetObjectOptions(AValue: TObjectOptions);
- Function GetAdditionalProperties : TJSONObject;
- protected
- {$ifdef ver2_6}
- // Version 2.6.4 has a bug for i386 where the array cannot be set through RTTI.
- // This is a helper method that sets the length of the array to the desired length,
- // After which the new array pointer is read again.
- // AName is guaranteed to be lowercase
- Procedure SetArrayLength(const AName : String; ALength : Longint); virtual;
- {$endif}
- Procedure MarkPropertyChanged(AIndex : Integer);
- Function IsDateTimeProp(Info : PTypeInfo) : Boolean;
- Function DateTimePropType(Info : PTypeInfo) : TDateTimeType;
- // Load properties
- Procedure ClearProperty(P: PPropInfo); virtual;
- Procedure SetBooleanProperty(P: PPropInfo; AValue: Boolean); virtual;
- Procedure SetFloatProperty(P: PPropInfo; AValue: Extended); virtual;
- Procedure SetInt64Property(P: PPropInfo; AValue: Int64); virtual;
- {$ifndef ver2_6}
- Procedure SetQWordProperty(P: PPropInfo; AValue: QWord); virtual;
- {$endif}
- Procedure SetIntegerProperty(P: PPropInfo; AValue: Integer); virtual;
- Procedure SetStringProperty(P: PPropInfo; AValue: String); virtual;
- Procedure SetArrayProperty(P: PPropInfo; AValue : TJSONArray); virtual;
- Procedure SetObjectProperty(P: PPropInfo; AValue : TJSONObject); virtual;
- Procedure SetSetProperty(P: PPropInfo; AValue : TJSONArray); virtual;
- Procedure SetEnumProperty(P: PPropInfo; AValue : TJSONData); virtual;
- // Save properties
- Function GetBooleanProperty(P: PPropInfo) : TJSONData; virtual;
- Function GetIntegerProperty(P: PPropInfo) : TJSONData; virtual;
- Function GetInt64Property(P: PPropInfo) : TJSONData; virtual;
- Function GetQwordProperty(P: PPropInfo) : TJSONData; virtual;
- Function GetFloatProperty(P: PPropInfo) : TJSONData; virtual;
- Function GetStringProperty(P: PPropInfo) : TJSONData; virtual;
- Function GetSetProperty(P: PPropInfo) : TJSONData; virtual;
- Function GetEnumeratedProperty(P: PPropInfo) : TJSONData; virtual;
- Function GetArrayProperty(P: PPropInfo) : TJSONData; virtual;
- Function GetObjectProperty(P: PPropInfo) : TJSONData; virtual;
- // Clear properties on
- Procedure ClearChildren(ChildTypes : TChildTypes); virtual;
- Class Function ClearChildTypes : TChildTypes; virtual;
- Public
- Constructor Create(AOptions : TObjectOptions = DefaultObjectOptions); Virtual;
- Destructor Destroy; override;
- Procedure StartRecordPropertyChanges;
- Procedure ClearPropertyChanges;
- Procedure StopRecordPropertyChanges;
- Function IsPropertyModified(Info : PPropInfo) : Boolean;
- Function IsPropertyModified(const AName : String) : Boolean;
- Class Function AllowAdditionalProperties : Boolean; virtual;
- Class Function GetTotalPropCount : Integer; virtual;
- Class Function GetCurrentPropCount : Integer; virtual;
- Class Function GetParentPropCount : Integer; virtual;
- Class Function ExportPropertyName(Const AName : String) : string; virtual;
- Class Function CleanPropertyName(Const AName : String) : string;
- Class Function CreateObject(Const AKind : String; AClass: TClass = Nil) : TBaseObject;
- Class Procedure RegisterObject;
- Class Function ObjectRestKind : String; virtual;
- Procedure LoadPropertyFromJSON(Const AName : String; JSON : TJSONData); virtual;
- Function SavePropertyToJSON(Info : PPropInfo) : TJSONData; virtual;
- Procedure LoadFromJSON(JSON : TJSONObject); virtual;
- Procedure SaveToJSON(JSON : TJSONObject); virtual;
- Function SaveToJSON : TJSONObject;
- Property ObjectOptions : TObjectOptions Read FObjectOptions Write SetObjectOptions;
- Property additionalProperties : TJSONObject Read GetAdditionalProperties;
- end;
- TBaseObjectClass = Class of TBaseObject;
- TObjectArray = Array of TBaseObject;
- TObjectArrayArray = Array of TObjectArray;
- TBaseListEnumerator = class
- private
- FList: TFPObjectList;
- FPosition: Integer;
- public
- constructor Create(AList: TFPObjectList);
- function GetCurrent: TBaseObject; virtual;
- function MoveNext: Boolean;
- property Current: TBaseObject read GetCurrent;
- end;
- TBaseListEnumeratorClass = Class of TBaseListEnumerator;
- { TBaseObjectList }
- TBaseObjectList = Class(TBaseObject)
- private
- FList : TFPObjectList;
- Protected
- function GetO(Aindex : Integer): TBaseObject;
- procedure SetO(Aindex : Integer; AValue: TBaseObject);
- Class Function ObjectClass : TBaseObjectClass; virtual;
- Function DoCreateEnumerator(AEnumClass : TBaseListEnumeratorClass) : TBaseListEnumerator;
- Public
- Constructor Create(AOptions : TObjectOptions = DefaultObjectOptions); Override;
- Destructor Destroy; override;
- function GetEnumerator : TBaseListEnumerator;
- Function AddObject(Const AKind : String) : TBaseObject; virtual;
- Property Objects [Aindex : Integer] : TBaseObject Read GetO Write SetO; default;
- end;
- { TBaseObjectList }
- { TBaseNamedObjectList }
- TBaseNamedObjectList = Class(TBaseObject)
- private
- FList : TStringList;
- function GetN(Aindex : Integer): String;
- function GetO(Aindex : Integer): TBaseObject;
- function GetON(AName : String): TBaseObject;
- procedure SetN(Aindex : Integer; AValue: String);
- procedure SetO(Aindex : Integer; AValue: TBaseObject);
- procedure SetON(AName : String; AValue: TBaseObject);
- Protected
- Class Function ObjectClass : TBaseObjectClass; virtual;
- Public
- Constructor Create(AOptions : TObjectOptions = DefaultObjectOptions); Override;
- Destructor Destroy; override;
- Function AddObject(Const AName,AKind : String) : TBaseObject; virtual;
- Property Names [Aindex : Integer] : String Read GetN Write SetN;
- Property Objects [Aindex : Integer] : TBaseObject Read GetO Write SetO;
- Property ObjectByName [AName : String] : TBaseObject Read GetON Write SetON; default;
- end;
- // used to catch a general JSON schema.
- { TJSONSchema }
- TJSONSchema = Class(TBaseObject)
- private
- FSchema: String;
- Public
- Procedure SetArrayProperty(P: PPropInfo; AValue : TJSONArray); override;
- Procedure LoadFromJSON(JSON : TJSONObject); override;
- Property Schema : String Read FSchema Write FSchema;
- end;
- TJSONSchemaArray = Array of TJSONSchema;
- TTJSONSchemaArray = TJSONSchemaArray;
- { TObjectFactory }
- TObjectFactory = Class(TComponent)
- Private
- FList : TClassList;
- Public
- Constructor Create(AOwner : TComponent); override;
- Destructor Destroy; override;
- Procedure RegisterObject(A : TBaseObjectClass);
- Function GetObjectClass(Const AKind : String) : TBaseObjectClass;
- end;
- Function RESTFactory : TObjectFactory;
- Function DateTimeToRFC3339(ADate :TDateTime):string;
- Function DateToRFC3339(ADate :TDateTime):string;
- Function TimeToRFC3339(ADate :TDateTime):string;
- Function TryRFC3339ToDateTime(const Avalue: String; out ADateTime: TDateTime): Boolean;
- Function RFC3339ToDateTime(const Avalue: String): TDateTime;
- implementation
- Var
- Fact : TObjectFactory;
- function DateTimeToRFC3339(ADate :TDateTime):string;
- begin
- Result:=FormatDateTime('yyyy-mm-dd"T"hh":"nn":"ss"."zzz"Z"',ADate);
- end;
- function DateToRFC3339(ADate: TDateTime): string;
- begin
- Result:=FormatDateTime('yyyy-mm-dd',ADate);
- end;
- function TimeToRFC3339(ADate :TDateTime):string;
- begin
- Result:=FormatDateTime('hh":"nn":"ss"."zzz',ADate);
- end;
- Function TryRFC3339ToDateTime(const Avalue: String; out ADateTime: TDateTime): Boolean;
- // 1 2
- // 12345678901234567890123
- // yyyy-mm-ddThh:nn:ss.zzz
- Type
- TPartPos = (ppTime,ppYear,ppMonth,ppDay,ppHour,ppMinute,ppSec);
- TPos = Array [TPartPos] of byte;
- Const
- P : TPos = (11,1,6,9,12,15,18);
- var
- lY, lM, lD, lH, lMi, lS: Integer;
- begin
- if Trim(AValue) = '' then
- begin
- Result:=True;
- ADateTime:=0;
- end;
- lY:=StrToIntDef(Copy(AValue,P[ppYear],4),-1);
- lM:=StrToIntDef(Copy(AValue,P[ppMonth],2),-1);
- lD:=StrToIntDef(Copy(AValue,P[ppDay],2),-1);
- if (Length(AValue)>=P[ppTime]) then
- begin
- lH:=StrToIntDef(Copy(AValue,P[ppHour],2),-1);
- lMi:=StrToIntDef(Copy(AValue,P[ppMinute],2),-1);
- lS:=StrToIntDef(Copy(AValue,P[ppSec],2),-1);
- end
- else
- begin
- lH:=0;
- lMi:=0;
- lS:=0;
- end;
- Result:=(lY>=0) and (lM>=00) and (lD>=0) and (lH>=0) and (lMi>=0) and (ls>=0);
- if Not Result then
- ADateTime:=0
- else
- { Cannot EncodeDate if any part equals 0. EncodeTime is okay. }
- if (lY = 0) or (lM = 0) or (lD = 0) then
- ADateTime:=EncodeTime(lH, lMi, lS, 0)
- else
- ADateTime:=EncodeDate(lY, lM, lD) + EncodeTime(lH, lMi, lS, 0);
- end;
- Function CountProperties(TypeInfo : PTypeInfo; Recurse : Boolean): Integer;
- function aligntoptr(p : pointer) : pointer;inline;
- begin
- {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
- result:=align(p,sizeof(p));
- {$else FPC_REQUIRES_PROPER_ALIGNMENT}
- result:=p;
- {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
- end;
- var
- hp : PTypeData;
- pd : ^TPropData;
- begin
- Result:=0;
- while Assigned(TypeInfo) do
- begin
- // skip the name
- hp:=GetTypeData(Typeinfo);
- // the class info rtti the property rtti follows immediatly
- pd:=aligntoptr(pointer(pointer(@hp^.UnitName)+Length(hp^.UnitName)+1));
- Result:=Result+Pd^.PropCount;
- if Recurse then
- TypeInfo:=HP^.ParentInfo
- else
- TypeInfo:=Nil;
- end;
- end;
- Function RFC3339ToDateTime(const Avalue: String): TDateTime;
- begin
- if Not TryRFC3339ToDateTime(AValue,Result) then
- Result:=0;
- end;
- Function RESTFactory : TObjectFactory;
- begin
- if Fact=Nil then
- Fact:=TObjectfactory.Create(Nil);
- Result:=Fact;
- end;
- { TObjectFactory }
- Constructor TObjectFactory.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FList:=TClassList.Create;
- end;
- Destructor TObjectFactory.Destroy;
- begin
- FreeAndNil(FList);
- inherited Destroy;
- end;
- Procedure TObjectFactory.RegisterObject(A: TBaseObjectClass);
- begin
- Flist.Add(A);
- end;
- Function TObjectFactory.GetObjectClass(Const AKind: String): TBaseObjectClass;
- Var
- I : Integer;
- N : String;
- begin
- I:=FList.Count-1;
- Result:=Nil;
- While (Result=Nil) and (I>=0) do
- begin
- Result:=TBaseObjectClass(FList[i]);
- N:=Result.ObjectRestKind;
- if CompareText(N,AKind)<>0 then
- Result:=nil;
- Dec(I);
- end;
- end;
- { TBaseNamedObjectList }
- function TBaseNamedObjectList.GetN(Aindex : Integer): String;
- begin
- Result:=Flist[AIndex];
- end;
- function TBaseNamedObjectList.GetO(Aindex: Integer): TBaseObject;
- begin
- Result:=TBaseObject(Flist.Objects[AIndex]);
- end;
- function TBaseNamedObjectList.GetON(AName : String): TBaseObject;
- Var
- I : Integer;
- begin
- I:=FList.IndexOf(AName);
- if I<>-1 then
- Result:=GetO(I)
- else
- Result:=Nil;
- end;
- procedure TBaseNamedObjectList.SetN(Aindex : Integer; AValue: String);
- begin
- Flist[AIndex]:=Avalue
- end;
- procedure TBaseNamedObjectList.SetO(Aindex: Integer; AValue: TBaseObject);
- begin
- Flist.Objects[AIndex]:=Avalue
- end;
- procedure TBaseNamedObjectList.SetON(AName : String; AValue: TBaseObject);
- Var
- I : Integer;
- begin
- I:=FList.IndexOf(AName);
- if I<>-1 then
- SetO(I,AValue)
- else
- Flist.AddObject(AName,AValue);
- end;
- Class Function TBaseNamedObjectList.ObjectClass: TBaseObjectClass;
- begin
- Result:=TBaseObject;
- end;
- Constructor TBaseNamedObjectList.Create(AOptions : TObjectOptions = DefaultObjectOptions);
- begin
- inherited Create(AOptions);
- FList:=TStringList.Create;
- Flist.OwnsObjects:=True;
- end;
- Destructor TBaseNamedObjectList.Destroy;
- begin
- FreeAndNil(Flist);
- inherited Destroy;
- end;
- Function TBaseNamedObjectList.AddObject(Const AName, AKind: String
- ): TBaseObject;
- begin
- Result:=CreateObject(AKind);
- ObjectByName[AName]:=Result;
- end;
- { TJSONSchema }
- Procedure TJSONSchema.SetArrayProperty(P: PPropInfo; AValue: TJSONArray);
- begin
- Schema:=AValue.asJSON
- end;
- Procedure TJSONSchema.LoadFromJSON(JSON: TJSONObject);
- begin
- Schema:=JSON.AsJSON;
- end;
- { TBaseObjectList }
- function TBaseObjectList.GetO(Aindex : Integer): TBaseObject;
- begin
- Result:=TBaseObject(FList[AIndex]);
- end;
- procedure TBaseObjectList.SetO(Aindex : Integer; AValue: TBaseObject);
- begin
- FList[AIndex]:=AValue;
- end;
- class function TBaseObjectList.ObjectClass: TBaseObjectClass;
- begin
- Result:=TBaseObject;
- end;
- function TBaseObjectList.DoCreateEnumerator(AEnumClass: TBaseListEnumeratorClass
- ): TBaseListEnumerator;
- begin
- Result:=AEnumClass.Create(FList);
- end;
- constructor TBaseObjectList.Create(AOptions: TObjectOptions);
- begin
- inherited Create(AOptions);
- FList:=TFPObjectList.Create;
- end;
- destructor TBaseObjectList.Destroy;
- begin
- FreeAndNil(FList);
- inherited Destroy;
- end;
- function TBaseObjectList.GetEnumerator: TBaseListEnumerator;
- begin
- Result:=TBaseListEnumerator.Create(FList);
- end;
- function TBaseObjectList.AddObject(const AKind: String): TBaseObject;
- Var
- C : TBaseObjectClass;
- begin
- if (AKind<>'') then
- begin
- C:=RestFactory.GetObjectClass(AKind);
- if Not C.InheritsFrom(ObjectClass) then
- Raise ERestAPI.CreateFmt('Cannot add object of kind "%s" to list, associated class "%s" is not a descendent of list class "%s"',[AKind,C.ClassName,ObjectClass.ClassName]);
- end;
- Result:=ObjectClass.Create;
- FList.Add(Result);
- end;
- constructor TBAseListEnumerator.Create(AList: TFPObjectList);
- begin
- inherited Create;
- FList := AList;
- FPosition := -1;
- end;
- function TBaseListEnumerator.GetCurrent: TBaseObject;
- begin
- Result := TBaseObject(FList[FPosition]);
- end;
- function TBaseListEnumerator.MoveNext: Boolean;
- begin
- Inc(FPosition);
- Result := FPosition < FList.Count;
- end;
- { TBaseObject }
- function TBaseObject.GetDynArrayProp(P: PPropInfo): Pointer;
- begin
- Result:=Pointer(GetObjectProp(Self,P));
- end;
- { $DEFINE DUMPARRAY}
- {$IFDEF DUMPARRAY}
- Procedure DumpArray(ClassName,N : String; P : Pointer);
- Type
- pdynarray = ^tdynarray;
- tdynarray = packed record
- refcount : ptrint;
- high : tdynarrayindex;
- end;
- Var
- R : pdynarray;
- begin
- if P=Nil then
- Writeln(ClassName,' property ',N, ' is nil')
- else
- begin
- r:=pdynarray(p-sizeof(tdynarray));
- Writeln(ClassName,' property ',N, ' has ref count ',r^.refcount,' and high ',r^.high);
- end;
- end;
- {$ENDIF}
- procedure TBaseObject.SetDynArrayProp(P: PPropInfo; AValue: Pointer);
- begin
- {$IFDEF DUMPARRAY}
- DumpArray(ClassName+' (set)',P^.PropType^.Name,AValue);
- {$ENDIF}
- SetObjectProp(Self,P,TObject(AValue));
- {$IFDEF DUMPARRAY}
- DumpArray(ClassName+' (check)',P^.PropType^.Name,AValue);
- {$ENDIF}
- end;
- procedure TBaseObject.SetObjectOptions(AValue: TObjectOptions);
- begin
- if FObjectOptions=AValue then Exit;
- FObjectOptions:=AValue;
- if ooStartRecordingChanges in FObjectOptions then
- StartRecordPropertyChanges
- end;
- procedure TBaseObject.MarkPropertyChanged(AIndex: Integer);
- begin
- If Assigned(FBits) then
- FBits.SetOn(GetParentPropCount+(AIndex shr IndexShift));
- end;
- function TBaseObject.IsDateTimeProp(Info: PTypeInfo): Boolean;
- begin
- Result:=DateTimePropType(Info)<>dtNone;
- end;
- function TBaseObject.DateTimePropType(Info: PTypeInfo): TDateTimeType;
- begin
- Result:=dtNone;
- if (Info=TypeInfo(TDateTime)) then
- Result:=dtDateTime
- else if (Info=TypeInfo(TDate)) then
- Result:=dtDate
- else if (Info=TypeInfo(TTime)) then
- Result:=dtTime
- end;
- procedure TBaseObject.ClearProperty(P: PPropInfo);
- begin
- Case P^.PropType^.Kind of
- tkInteger,
- tkChar,
- tkEnumeration,
- tkBool,
- tkSet : SetOrdProp(Self,P,0);
- tkFloat : SetFloatProp(Self,P,0.0);
- tkSString,
- tkLString,
- tkUChar,
- tkAString: SetStrProp(Self,P,'');
- tkWChar,
- tkWString: SetWideStrProp(Self,P,'');
- tkUString: SetUnicodeStrProp(Self,P,'');
- tkInt64,
- tkQWord : SetInt64Prop(Self,P,0);
- tkClass :
- begin
- GetObjectProp(Self,P).Free;
- SetObjectProp(Self,P,Nil);
- end
- else
- // Do nothing
- end;
- end;
- procedure TBaseObject.SetBooleanProperty(P: PPropInfo; AValue: Boolean);
- begin
- SetOrdProp(Self,P,Ord(AValue));
- end;
- procedure TBaseObject.SetFloatProperty(P: PPropInfo; AValue: Extended);
- begin
- SetFloatProp(Self,P,AValue);
- end;
- procedure TBaseObject.SetIntegerProperty(P: PPropInfo; AValue: Integer);
- begin
- SetOrdProp(Self,P,AValue);
- end;
- procedure TBaseObject.SetInt64Property(P: PPropInfo; AValue: Int64);
- begin
- SetInt64Prop(Self,P,AValue);
- end;
- {$ifndef ver2_6}
- procedure TBaseObject.SetQWordProperty(P: PPropInfo; AValue: QWord);
- begin
- SetInt64Prop(Self,P,Int64(AValue));
- end;
- {$endif}
- procedure TBaseObject.SetStringProperty(P: PPropInfo; AValue: String);
- Var
- D : TDateTime;
- begin
- if not IsDateTimeProp(P^.PropType) then
- SetStrProp(Self,P,AValue)
- else if TryRFC3339ToDateTime(AValue,D) then
- SetFloatProp(Self,P,D)
- else
- SetFloatProp(Self,P,0)
- end;
- procedure TBaseObject.SetArrayProperty(P: PPropInfo; AValue: TJSONArray);
- procedure SetObjectArrayProp(PropAsPtr: Pointer;
- const TypeName: ShortString;
- const ClassType: TClass;
- const JSONArray: TJSONArray);
- var
- ObjectArray: TObjectArray;
- BaseObject: TBaseObject;
- Idx: Integer;
- begin
- ObjectArray := TObjectArray(PropAsPtr);
- // Free all objects
- for Idx := Low(ObjectArray) to High(ObjectArray) do
- FreeAndNil(ObjectArray[Idx]);
- SetLength(ObjectArray, JSONArray.Count);
- for Idx := Low(ObjectArray) to High(ObjectArray) do
- begin
- BaseObject := CreateObject(TypeName, ClassType);
- ObjectArray[Idx] := BaseObject;
- BaseObject.LoadFromJSON(JSONArray.Objects[Idx]);
- end;
- end;
- procedure SetFloatArrayProp(PropAsPtr: Pointer;
- const JSONArray: TJSONArray);
- var
- FloatArray: TFloatArray;
- Idx: Integer;
- begin
- FloatArray := TFloatArray(PropAsPtr);
- SetLength(FloatArray, JSONArray.Count);
- for Idx := Low(FloatArray) to High(FloatArray) do
- FloatArray[Idx] := JSONArray.Floats[Idx];
- end;
- procedure SetDateTimeArrayProp(PropAsPtr: Pointer;
- const JSONArray: TJSONArray);
- var
- DateTimeArray: TDateTimeArray;
- Idx: Integer;
- begin
- DateTimeArray := TDateTimeArray(PropAsPtr);
- SetLength(DateTimeArray, JSONArray.Count);
- for Idx := Low(DateTimeArray) to High(DateTimeArray) do
- DateTimeArray[Idx] := RFC3339ToDateTime(JSONArray.Strings[Idx]);
- end;
- procedure SetInt64ArrayProp(PropAsPtr: Pointer;
- const JSONArray: TJSONArray);
- var
- Int64Array: TInt64Array;
- Idx: Integer;
- begin
- Int64Array := TInt64Array(PropAsPtr);
- SetLength(Int64Array, JSONArray.Count);
- for Idx := Low(Int64Array) to High(Int64Array) do
- Int64Array[Idx] := JSONArray.Int64s[Idx];
- end;
- procedure SetBooleanArrayProp(PropAsPtr: Pointer;
- const JSONArray: TJSONArray);
- var
- BooleanArray: TBooleanArray;
- Idx: Integer;
- begin
- BooleanArray := TBooleanArray(PropAsPtr);
- SetLength(BooleanArray, JSONArray.Count);
- for Idx := Low(BooleanArray) to High(BooleanArray) do
- BooleanArray[Idx] := JSONArray.Booleans[Idx];
- end;
- procedure SetIntegerArrayProp(PropAsPtr: Pointer;
- const JSONArray: TJSONArray);
- var
- IntegerArray: TIntegerArray;
- Idx: Integer;
- begin
- IntegerArray := TIntegerArray(PropAsPtr);
- SetLength(IntegerArray, JSONArray.Count);
- for Idx := Low(IntegerArray) to High(IntegerArray) do
- IntegerArray[Idx] := JSONArray.Integers[Idx];
- end;
- procedure SetUnicodeStringArrayProp(PropAsPtr: Pointer;
- const JSONArray: TJSONArray);
- var
- UnicodeStringArray: TUnicodeStringArray;
- Idx: Integer;
- begin
- UnicodeStringArray := TUnicodeStringArray(PropAsPtr);
- SetLength(UnicodeStringArray, JSONArray.Count);
- for Idx := Low(UnicodeStringArray) to High(UnicodeStringArray) do
- UnicodeStringArray[Idx] := UTF8Decode(JSONArray.Strings[Idx]);
- end;
- procedure SetStringArrayProp(PropAsPtr: Pointer;
- const JSONArray: TJSONArray);
- var
- Idx: Integer;
- StringArray: TStringArray;
- begin
- StringArray := TStringArray(PropAsPtr);
- SetLength(StringArray, JSONArray.Count);
- for Idx := Low(StringArray) to High(StringArray) do
- StringArray[Idx] := JSONArray.Strings[Idx];
- end;
- Var
- T : PTypeData;
- L : TBaseObjectList;
- D : TJSONEnum;
- PTD : PTypeData;
- ET : PTypeInfo;
- AN : String;
- AP : Pointer;
- S : TJSONSchema;
- begin
- if P^.PropType^.Kind=tkClass then
- begin
- T:=GetTypeData(P^.PropType);
- if T^.ClassType.InheritsFrom(TBaseObjectList) then
- begin
- L:=TBaseObjectList(TBaseObjectClass(T^.ClassType).Create);
- SetObjectProp(Self,P,L); //what if there is an existing object, are we clobbering it?
- For D in AValue do
- L.AddObject('').LoadFromJSON(D.Value as TJSONObject);
- end
- else if T^.ClassType.InheritsFrom(TJSONSchema) then
- begin
- S:=TJSONSchema.Create;
- S.SetArrayProperty(P,AValue);
- SetObjectProp(Self,P,S); //what if there is an existing object, are we clobbering it?
- end
- else
- Raise ERESTAPI.CreateFmt('Unsupported class %s for property %s',[T^.ClassType.ClassName,P^.Name]);
- end
- else if P^.PropType^.Kind=tkDynArray then
- begin
- // Get array value
- AP:=GetObjectProp(Self,P); //NOTE: AP is dynanmic array as an untyped pointer
- //Getting it like this bypasses the reference count management
- //Be careful what do we with it to avoid leaking memory.
- PTD:=GetTypeData(P^.PropType);
- ET:=PTD^.ElType2;
- AN:=ET^.Name;
- case ET^.Kind of
- tkClass: SetObjectArrayProp(AP, ET^.Name, GetTypeData(ET)^.ClassType, AValue);
- tkFloat:
- if IsDateTimeProp(ET) then
- SetDateTimeArrayProp(AP, AValue)
- else
- SetFloatArrayProp(AP, AValue);
- tkInt64: SetInt64ArrayProp(AP, AValue);
- tkBool: SetBooleanArrayProp(AP, AValue);
- tkInteger: SetIntegerArrayProp(AP, AValue);
- tkUstring,
- tkWstring: SetUnicodeStringArrayProp(AP, AValue);
- tkString,
- tkAstring,
- tkLString: SetStringArrayProp(AP, AValue);
- else
- Raise ERESTAPI.CreateFmt('%s: unsupported array element type for property of type %s: %s',[ClassName,AN,GetEnumName(TypeInfo(TTypeKind),Ord(ET^.Kind))]);
- end;
- end;
- end;
- procedure TBaseObject.SetObjectProperty(P: PPropInfo; AValue: TJSONObject);
- Var
- O : TBaseObject;
- A: Pointer;
- T : PTypeData;
- D : TJSONEnum;
- AN : String;
- I : Integer;
- L : TBaseObjectList;
- NL : TBaseNamedObjectList;
- begin
- if P^.PropType^.Kind=tkDynArray then
- begin
- A:=GetDynArrayProp(P);
- For I:=0 to Length(TObjectArray(A))-1 do
- FreeAndNil(TObjectArray(A)[i]);
- SetLength(TObjectArray(A),AValue.Count);
- T:=GetTypeData(P^.PropType);
- AN:=T^.ElType2^.Name;
- I:=0;
- For D in AValue do
- begin
- O:=CreateObject(AN);
- TObjectArray(A)[I]:=O;
- // Writeln(ClassName,' Adding instance of type: ',AN,' for key ',D.Key);
- if IsPublishedProp(O,'name') then
- SetStrProp(O,'name',D.Key);
- O.LoadFromJSON(D.Value as TJSONObject);
- Inc(I);
- end;
- // Writeln(ClassName,' Done with array ',P^.Name,', final array length: ', Length(TObjectArray(A)));
- SetDynArrayProp(P,A);
- Exit;
- end;
- if Not (P^.PropType^.Kind=tkClass) then
- Raise ERESTAPI.CreateFmt('%s: Unsupported type for property %s',[ClassName,P^.Name]);
- T:=GetTypeData(P^.PropType);
- if T^.ClassType.InheritsFrom(TBaseObject) then
- begin
- O:=TBaseObject(GetObjectProp(Self,P,TBaseObject));
- if O=Nil then
- begin
- O:=TBaseObjectClass(T^.ClassType).Create;
- SetObjectProp(Self,P,O);
- end;
- O.LoadFromJSON(AValue);
- end
- else if T^.ClassType.InheritsFrom(TBaseObjectList) then
- begin
- L:=TBaseObjectList(TBaseObjectClass(T^.ClassType).Create);
- SetObjectProp(Self,P,L);
- For D in AValue do
- L.AddObject('').LoadFromJSON(D.Value as TJSONObject);
- end
- else if T^.ClassType.InheritsFrom(TBaseNamedObjectList) then
- begin
- NL:=TBaseNamedObjectList(TBaseObjectClass(T^.ClassType).Create);
- SetObjectProp(Self,P,L);
- For D in AValue do
- NL.AddObject(D.Key,'').LoadFromJSON(D.Value as TJSONObject);
- end
- else
- Raise ERESTAPI.CreateFmt('%s: unsupported class %s for property %s',[ClassName, T^.ClassType.ClassName,P^.Name]);
- end;
- procedure TBaseObject.SetSetProperty(P: PPropInfo; AValue: TJSONArray);
- type
- TSet = set of 0..31;
- var
- S,I,V : Integer;
- CurValue: string;
- EnumTyp: PTypeInfo;
- EnumTypData: PTypeData;
- begin
- S:=0;
- EnumTyp:=GetTypeData(P^.PropType)^.CompType;
- EnumTypData:=GetTypeData(EnumTyp);
- For I:=0 to AValue.Count-1 do
- begin
- CurValue:=AValue.Strings[i];
- if Not TryStrToInt(CurValue,V) then
- V:=GetEnumValue(EnumTyp,CurValue);
- if (V<EnumTypData^.MinValue) or (V>EnumTypData^.MaxValue) or (V>31) then
- Raise ERESTAPI.CreateFmt('%s: Invalid value %s for property %s',[ClassName, CurValue,P^.Name]);
- Include(TSet(S),V);
- end;
- SetOrdProp(Self,P,S);
- end;
- procedure TBaseObject.SetEnumProperty(P: PPropInfo; AValue: TJSONData);
- Var
- I : Integer;
- begin
- I:=GetEnumValue(P^.PropType,AValue.AsString);
- if (I=-1) then
- Raise ERESTAPI.CreateFmt('%s: Invalid value %s for property %s',[ClassName, AValue.AsString,P^.Name]);
- SetOrdProp(Self,P,I);
- end;
- function TBaseObject.GetBooleanProperty(P: PPropInfo): TJSONData;
- begin
- Result:=TJSONBoolean.Create(GetOrdProp(Self,P)<>0);
- end;
- function TBaseObject.GetIntegerProperty(P: PPropInfo): TJSONData;
- begin
- Result:=TJSONIntegerNumber.Create(GetOrdProp(Self,P));
- end;
- function TBaseObject.GetInt64Property(P: PPropInfo): TJSONData;
- begin
- Result:=TJSONInt64Number.Create(GetInt64Prop(Self,P));
- end;
- function TBaseObject.GetQwordProperty(P: PPropInfo): TJSONData;
- begin
- Result:=TJSONInt64Number.Create(Int64(GetInt64Prop(Self,P)));
- end;
- function TBaseObject.GetFloatProperty(P: PPropInfo): TJSONData;
- begin
- Case DateTimePropType(P^.PropType) of
- dtDateTime:
- Result:=TJSONString.Create(DateTimeToRFC3339(GetFloatProp(Self,P)));
- dtDate:
- Result:=TJSONString.Create(DateToRFC3339(GetFloatProp(Self,P)));
- dtTime:
- Result:=TJSONString.Create(TimeToRFC3339(GetFloatProp(Self,P))) ;
- else
- Result:=TJSONFloatNumber.Create(GetFloatProp(Self,P));
- end;
- end;
- function TBaseObject.GetStringProperty(P: PPropInfo): TJSONData;
- begin
- Result:=TJSONString.Create(GetStrProp(Self,P));
- end;
- function TBaseObject.GetSetProperty(P: PPropInfo): TJSONData;
- type
- TSet = set of 0..31;
- var
- Typ: PTypeInfo;
- S, i: integer;
- begin
- Result:=TJSONArray.Create;
- Typ:=GetTypeData(P^.PropType)^.CompType;
- S:=GetOrdProp(Self,P);
- for i:=Low(TSet) to High(TSet) do
- if (i in TSet(S)) then
- TJSONArray(Result).Add(TJSONString.Create(GetEnumName(Typ,i)));
- end;
- function TBaseObject.GetEnumeratedProperty(P: PPropInfo): TJSONData;
- begin
- Result:=TJSONString.Create(GetEnumProp(Self,P));
- end;
- function TBaseObject.GetArrayProperty(P: PPropInfo): TJSONData;
- Var
- AO : TObject;
- I : Integer;
- ET : PTypeInfo;
- PTD : PTypeData;
- AP : Pointer;
- A : TJSONArray;
- O : TJSONObject;
- begin
- A:=TJSONArray.Create;
- Result:=A;
- // Get array value type
- AP:=GetObjectProp(Self,P);
- PTD:=GetTypeData(P^.PropType);
- ET:=PTD^.ElType2;
- // Fill in all elements
- Case ET^.Kind of
- tkClass:
- For I:=0 to Length(TObjectArray(AP))-1 do
- begin
- // Writeln(ClassName,' Adding instance of type: ',AN);
- AO:=TObjectArray(AP)[I];
- if AO.InheritsFrom(TBaseObject) then
- begin
- O:=TJSONObject.Create;
- A.Add(O);
- TBaseObject(AO).SaveToJSON(O);
- end;
- end;
- tkFloat:
- if IsDateTimeProp(ET) then
- For I:=0 to Length(TDateTimeArray(AP))-1 do
- A.Add(TJSONString.Create(DateTimeToRFC3339(TDateTimeArray(AP)[I])))
- else
- For I:=0 to Length(TFloatArray(AP))-1 do
- A.Add(TJSONFloatNumber.Create(TFloatArray(AP)[I]));
- tkInt64:
- For I:=0 to Length(TInt64Array(AP))-1 do
- A.Add(TJSONInt64Number.Create(TInt64Array(AP)[I]));
- tkBool:
- For I:=0 to Length(TInt64Array(AP))-1 do
- A.Add(TJSONBoolean.Create(TBooleanArray(AP)[I]));
- tkInteger :
- For I:=0 to Length(TIntegerArray(AP))-1 do
- A.Add(TJSONIntegerNumber.Create(TIntegerArray(AP)[I]));
- tkUstring,
- tkWstring :
- For I:=0 to Length(TUnicodeStringArray(AP))-1 do
- A.Add(TJSONString.Create(TUnicodeStringArray(AP)[I]));
- tkString,
- tkAstring,
- tkLString :
- For I:=0 to Length(TStringArray(AP))-1 do
- A.Add(TJSONString.Create(TStringArray(AP)[I]));
- else
- Raise ERESTAPI.CreateFmt('%s: unsupported array element type : %s',[ClassName,GetEnumName(TypeInfo(TTypeKind),Ord(ET^.Kind))]);
- end;
- end;
- function TBaseObject.GetObjectProperty(P: PPropInfo): TJSONData;
- Var
- O : TObject;
- begin
- O:=GetObjectProp(Self,P);
- if (O is TBaseObject) then
- Result:=TBaseObject(O).SaveToJSON
- else
- Result:=Nil; // maybe we need to add an option to return null ?
- end;
- procedure TBaseObject.ClearChildren(ChildTypes: TChildTypes);
- Type
- TObjectArr = Array of TObject;
- var
- PL: PPropList;
- P : PPropInfo;
- i,j,count,len:integer;
- A : pointer;
- PTD : PTypeData;
- O : TObject;
- begin
- Count:=GetPropList(Self,PL);
- try
- for i:=0 to Count-1 do
- begin
- P:=PL^[I];
- case P^.PropType^.Kind of
- tkClass:
- if (ctObject in ChildTypes) then
- begin
- // Writeln(ClassName,' Examining object: ',P^.Name);
- O:=GetObjectProp(Self,P);
- O.Free;
- SetObjectProp(Self,P,Nil);
- end;
- tkDynArray:
- if (ctArray in ChildTypes) then
- begin
- len:=Length(P^.PropType^.Name);
- PTD:=GetTypeData(P^.PropType);
- if PTD^.ElType2^.Kind=tkClass then
- begin
- A:=GetDynArrayProp(P);
- {$IFDEF DUMPARRAY}
- DumpArray(ClassName+' (clear)',P^.PropType^.Name,A);
- {$ENDIF}
- // Writeln(ClassName,' Examining array: ',P^.Name,'Count:',Length(TObjectArr(A)));
- For J:=0 to Length(TObjectArr(A))-1 do
- begin
- FreeAndNil(TObjectArr(A)[J]);
- end;
- end;
- // Length is set to nil by destructor
- end;
- end;
- end;
- finally
- FreeMem(PL);
- end;
- end;
- class function TBaseObject.ClearChildTypes: TChildTypes;
- begin
- Result:=[ctArray,ctObject]
- end;
- {$IFDEF DEBUGBASEOBJMEMLEAK}
- Var
- ObjCounter : TStrings;
- {$ENDIF}
- constructor TBaseObject.Create(AOptions: TObjectOptions);
- begin
- {$IFDEF DEBUGBASEOBJMEMLEAK}
- if ObjCounter=Nil then
- ObjCounter:=TStringList.Create;
- ObjCounter.Values[ClassName]:=IntToStr(StrToIntDef(ObjCounter.Values[ClassName],0)+1);
- {$ENDIF}
- ObjectOptions:=AOptions;
- // Do nothing
- end;
- destructor TBaseObject.Destroy;
- begin
- StopRecordPropertyChanges;
- {$IFDEF DEBUGBASEOBJMEMLEAK}
- ObjCounter.Values[ClassName]:=IntToStr(StrToIntDef(ObjCounter.Values[ClassName],0)-1);
- {$ENDIF}
- FreeAndNil(fadditionalProperties);
- if ClearChildTypes<>[] then
- ClearChildren(ClearChildTypes);
- inherited;
- end;
- procedure TBaseObject.StartRecordPropertyChanges;
- begin
- if Assigned(FBits) then
- FBits.ClearAll
- else
- FBits:=TBits.Create(GetTotalPropCount);
- end;
- procedure TBaseObject.ClearPropertyChanges;
- begin
- FBits.ClearAll;
- end;
- procedure TBaseObject.StopRecordPropertyChanges;
- begin
- FreeAndNil(FBits);
- end;
- function TBaseObject.IsPropertyModified(Info: PPropInfo): Boolean;
- begin
- Result:=Not Assigned(FBits) or FBits.Bits[Info^.NameIndex]
- end;
- function TBaseObject.IsPropertyModified(const AName: String): Boolean;
- begin
- Result:=IsPropertyModified(GetPropInfo(Self,AName));
- end;
- function TBaseObject.GetAdditionalProperties: TJSONObject;
- begin
- if (fAdditionalProperties=Nil) and AllowAdditionalProperties then
- fAdditionalProperties:=TJSONObject.Create;
- Result:=fAdditionalProperties
- end;
- {$IFDEF VER2_6}
- procedure TBaseObject.SetArrayLength(Const AName: String; ALength: Longint);
- begin
- Raise ERestAPI.CreateFmt('Unknown Array %s',[AName]);
- end;
- {$ENDIF}
- class function TBaseObject.AllowAdditionalProperties: Boolean;
- begin
- Result:=False;
- end;
- class function TBaseObject.ExportPropertyName(const AName: String): string;
- begin
- Result:=AName;
- end;
- class function TBaseObject.CleanPropertyName(const AName: String): string;
- Const
- KW=';absolute;and;array;asm;begin;case;const;constructor;destructor;div;do;'+
- 'downto;else;end;file;for;function;goto;if;implementation;in;inherited;'+
- 'inline;interface;label;mod;nil;not;object;of;on;operator;or;packed;'+
- 'procedure;program;record;reintroduce;repeat;self;set;shl;shr;string;then;'+
- 'to;type;unit;until;uses;var;while;with;xor;dispose;exit;false;new;true;'+
- 'as;class;dispinterface;except;exports;finalization;finally;initialization;'+
- 'inline;is;library;on;out;packed;property;raise;resourcestring;threadvar;try;'+
- 'private;published;length;setlength;';
- Var
- I : Integer;
- begin
- Result:=Aname;
- For I:=Length(Result) downto 1 do
- If Not ((Upcase(Result[i]) in ['_','A'..'Z'])
- or ((I>1) and (Result[i] in (['0'..'9'])))) then
- Delete(Result,i,1);
- if Pos(';'+lowercase(Result)+';',KW)<>0 then
- Result:='_'+Result
- end;
- class function TBaseObject.CreateObject(const AKind: String; AClass: TClass = Nil): TBaseObject;
- Var
- C : TBaseObjectClass;
- begin
- C:=RESTFactory.GetObjectClass(AKind);
- if (C=Nil) and Assigned(AClass) and AClass.InheritsFrom(TBaseObject) then
- C:=TBaseObjectClass(AClass);
- if C<>Nil then
- Result:=C.Create
- else
- Raise ERESTAPI.CreateFmt('Unknown class : "%s"',[AKind]);
- // Do nothing
- end;
- class procedure TBaseObject.RegisterObject;
- begin
- RESTFactory.RegisterObject(Self);
- end;
- class function TBaseObject.ObjectRestKind: String;
- begin
- Result:=ClassName;
- end;
- class function TBaseObject.GetTotalPropCount: Integer;
- begin
- Result:=GetTypeData(ClassInfo)^.PropCount;
- end;
- class function TBaseObject.GetCurrentPropCount: Integer;
- begin
- Result:=CountProperties(ClassInfo,False);
- end;
- class function TBaseObject.GetParentPropCount: Integer;
- begin
- if (ClassParent=TBaseObject) or (ClassParent=Nil) then
- Result:=0
- else
- Result:=TBaseObjectClass(ClassParent).GetTotalPropCount;
- end;
- procedure TBaseObject.LoadPropertyFromJSON(const AName: String; JSON: TJSONData
- );
- Var
- P : PPropInfo;
- o : TJSONObject;
- begin
- // Writeln(ClassName,' loading : ',ANAme,' -> ',CleanPropertyName(aName));
- P:=GetPropInfo(Self,CleanPropertyName(aName));
- if (P=Nil) then
- begin
- o:=additionalProperties;
- if o=Nil then
- Raise ERESTAPI.CreateFmt('%s : Unknown property "%s"',[ClassName,AName]);
- o.Add(aName,JSON.Clone);
- end
- else
- case JSON.JSONType of
- jtstring :
- if (P^.PropType^.Kind=tkEnumeration) then
- SetEnumProperty(P,JSON)
- else
- SetStringproperty(P,JSON.AsString);
- jtNumber :
- case TJSONNumber(JSON).NumberType of
- ntFloat : SetFloatProperty(P,JSON.asFloat);
- ntInteger : SetIntegerProperty(P,JSON.asInteger);
- ntInt64 : SetInt64Property(P,JSON.asInt64);
- {$ifndef ver2_6}
- ntqword : SetQWordProperty(P,JSON.asQWord);
- {$endif}
- end;
- jtNull : ClearProperty(P);
- jtBoolean : SetBooleanProperty(P,json.AsBoolean);
- jtArray :
- if P^.PropType^.Kind=tkSet then
- SetSetProperty(P,TJSONArray(json))
- else
- SetArrayProperty(P,TJSONArray(json));
- jtObject : SetObjectProperty(P,TJSONObject(json));
- end;
- end;
- function TBaseObject.SavePropertyToJSON(Info: PPropInfo): TJSONData;
- begin
- Result:=Nil;
- if Not IsPropertyModified(Info) then
- Exit;
- Case Info^.PropType^.Kind of
- tkSet : Result:=GetSetProperty(Info);
- tkEnumeration : Result:=GetEnumeratedProperty(Info);
- tkAstring,
- tkUstring,
- tkWString,
- tkwchar,
- tkuchar,
- tkString : Result:=GetStringProperty(Info);
- tkFloat : Result:=GetFloatProperty(Info);
- tkBool : Result:=GetBooleanProperty(Info);
- tkClass : Result:=GetObjectProperty(Info);
- tkDynArray : Result:=GetArrayProperty(Info);
- tkQWord : Result:=GetQWordProperty(Info);
- tkInt64 : Result:=GetInt64Property(Info);
- tkInteger : Result:=GetIntegerProperty(Info);
- end;
- end;
- procedure TBaseObject.LoadFromJSON(JSON: TJSONObject);
- Var
- D : TJSONEnum;
- begin
- StopRecordPropertyChanges;
- For D in JSON Do
- LoadPropertyFromJSON(D.Key,D.Value);
- StartRecordPropertyChanges;
- end;
- procedure TBaseObject.SaveToJSON(JSON: TJSONObject);
- var
- PL: PPropList;
- P : PPropInfo;
- I,Count : integer;
- D : TJSONData;
- begin
- Count:=GetPropList(Self,PL);
- try
- for i:=0 to Count-1 do
- begin
- P:=PL^[I];
- D:=SavePropertyToJSON(P);
- if (D<>Nil) then
- JSON.add(ExportPropertyName(P^.Name),D);
- end;
- finally
- FreeMem(PL);
- end;
- end;
- function TBaseObject.SaveToJSON: TJSONObject;
- begin
- Result:=TJSONObject.Create;
- try
- SaveToJSON(Result);
- except
- FreeAndNil(Result);
- Raise;
- end;
- end;
- finalization
- {$IFDEF DEBUGBASEOBJMEMLEAK}
- if Assigned(ObjCounter) then
- begin
- Writeln(StdErr,'Object allocate-free count: ');
- Writeln(StdErr,ObjCounter.Text);
- FreeAndNil(ObjCounter);
- end;
- {$ENDIF}
- FreeAndNil(Fact);
- end.
|