Browse Source

Merge branch 'develop'

Unknown 6 years ago
parent
commit
03561de626

+ 123 - 8
Quick.AutoMapper.pas

@@ -5,9 +5,9 @@
   Unit        : Quick.AutoMapper
   Description : Auto Mapper object properties
   Author      : Kike Pérez
-  Version     : 1.0
+  Version     : 1.1
   Created     : 25/08/2018
-  Modified    : 30/08/2018
+  Modified    : 23/09/2018
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -36,9 +36,9 @@ interface
 uses
   SysUtils,
   Generics.Collections,
-  {$IFDEF FPC}
+  //{$IFDEF FPC}
   typinfo,
-  {$ENDIF}
+  //{$ENDIF}
   RTTI;
 
 type
@@ -58,6 +58,16 @@ type
     class procedure Map(aSrcObj : TObject; aTgtObj : TObject; aCustomMapping: TCustomMapping = nil);
   end;
 
+  TListMapper = class
+  public
+    class procedure Map(aSrcList, aTgtList: TObject; aCustomMapping: TCustomMapping);
+  end;
+
+  TObjListMapper = class
+  public
+    class procedure Map(aSrcObjList : TObject; aTgtObjList : TObject; aCustomMapping : TCustomMapping = nil);
+  end;
+
   TMapper<T : class, constructor> = class
   public
     class function Map(aSrcObj : TObject; aCustomMapping: TCustomMapping = nil): T; overload;
@@ -93,16 +103,19 @@ var
   tgtprop : TRttiProperty;
   mapname : string;
   obj : TObject;
+  clname : string;
 begin
-  if aTgtObj = nil then aTgtObj := aTgtObj.ClassType.Create;
+  if aTgtObj = nil then aTgtObj := GetTypeData(aTgtObj.ClassInfo).classType.Create;
 
+  rType := ctx.GetType(aSrcObj.ClassInfo);
   for tgtprop in ctx.GetType(aTgtObj.ClassInfo).GetProperties do
   begin
     if tgtprop.IsWritable then
     begin
+      if tgtprop.Name = 'Agent'
+        then Sleep(0);
       if not tgtprop.PropertyType.IsInstance then
       begin
-        rType := ctx.GetType(aSrcObj.ClassInfo);
         if Assigned(aCustomMapping) then
         begin
           if aCustomMapping.GetMap(tgtprop.Name,mapname) then
@@ -153,7 +166,10 @@ begin
         if obj <> nil then
         begin
           {$IFNDEF FPC}
-          TObjMapper.Map(rType.GetProperty(tgtprop.Name).GetValue(aSrcObj).AsObject,obj,aCustomMapping);
+          clname := rType.GetProperty(tgtprop.Name).GetValue(aSrcObj).AsObject.ClassName;
+          if clname.StartsWith('TObjectList') then TObjListMapper.Map(rType.GetProperty(tgtprop.Name).GetValue(aSrcObj).AsObject,obj,aCustomMapping)
+            else if clname.StartsWith('TList') then TListMapper.Map(rType.GetProperty(tgtprop.Name).GetValue(aSrcObj).AsObject,obj,aCustomMapping)
+              else TObjMapper.Map(rType.GetProperty(tgtprop.Name).GetValue(aSrcObj).AsObject,obj,aCustomMapping)
           {$ELSE}
           TObjMapper.Map(GetObjectProp(aSrcObj,tgtprop.Name),obj,aCustomMapping);
           SetObjectProp(aTgtObj,tgtprop.Name,obj);
@@ -192,7 +208,6 @@ begin
   inherited;
 end;
 
-{}
 function TAutoMapper<TClass1, TClass2>.Map(aSrcObj: TClass1): TClass2;
 begin
   Result := TMapper<TClass2>.Map(aSrcObj,fCustomMapping);
@@ -233,4 +248,104 @@ begin
   Result := fMapDictionary.TryGetValue(aName,vMapName);
 end;
 
+{ TListMapper }
+
+class procedure TListMapper.Map(aSrcList, aTgtList: TObject; aCustomMapping: TCustomMapping);
+{$IFNDEF FPC}
+var
+  rtype: TRttiType;
+  rtype2 : TRttiType;
+  typinfo : PTypeInfo;
+  methToArray: TRttiMethod;
+  value: TValue;
+  valuecop : TValue;
+  obj : TObject;
+  i : Integer;
+  rprop : TRttiProperty;
+  ctx : TRttiContext;
+begin
+  rtype := ctx.GetType(aSrcList.ClassInfo);
+  methToArray := rtype.GetMethod('ToArray');
+  if Assigned(methToArray) then
+  begin
+    value := methToArray.Invoke(aSrcList,[]);
+    Assert(value.IsArray);
+
+    rtype2 := ctx.GetType(aTgtList.ClassInfo);
+    rProp := rtype2.GetProperty('List');
+    typinfo := GetTypeData(rProp.PropertyType.Handle).DynArrElType^;
+
+    for i := 0 to value.GetArrayLength - 1 do
+    begin
+      if typinfo.Kind = tkClass then
+      begin
+        obj := typinfo.TypeData.ClassType.Create;
+        TObjMapper.Map(value.GetArrayElement(i).AsObject,obj,aCustomMapping);
+        TList<TObject>(aTgtList).Add(obj);
+      end
+      else if typinfo.Kind = tkRecord then
+      begin
+        valuecop := value.GetArrayElement(i);
+        //??
+      end
+      else
+      begin
+        valuecop := value.GetArrayElement(i);
+        case typinfo.Kind of
+          tkChar, tkString, tkWChar, tkWString : TList<string>(aTgtList).Add(valuecop.AsString);
+          tkInteger, tkInt64 : TList<Integer>(aTgtList).Add(valuecop.AsInt64);
+          tkFloat : TList<Extended>(aTgtList).Add(valuecop.AsExtended);
+        end;
+      end;
+    end;
+  end;
+end;
+{$ELSE}
+begin
+
+end;
+{$ENDIF}
+
+
+{ TObjListMapper }
+
+class procedure TObjListMapper.Map(aSrcObjList, aTgtObjList: TObject; aCustomMapping: TCustomMapping);
+{$IFNDEF FPC}
+var
+  rtype: TRttiType;
+  rtype2 : TRttiType;
+  typinfo : PTypeInfo;
+  methToArray: TRttiMethod;
+  value: TValue;
+  obj : TObject;
+  i : Integer;
+  rprop : TRttiProperty;
+  ctx : TRttiContext;
+begin
+  rtype := ctx.GetType(aSrcObjList.ClassInfo);
+  methToArray := rtype.GetMethod('ToArray');
+  if Assigned(methToArray) then
+  begin
+    value := methToArray.Invoke(aSrcObjList,[]);
+    Assert(value.IsArray);
+
+    rtype2 := ctx.GetType(aTgtObjList.ClassInfo);
+    rProp := rtype2.GetProperty('List');
+    typinfo := GetTypeData(rProp.PropertyType.Handle).DynArrElType^;
+
+    for i := 0 to value.GetArrayLength - 1 do
+    begin
+      obj := typinfo.TypeData.ClassType.Create;
+      TObjMapper.Map(value.GetArrayElement(i).AsObject,obj,aCustomMapping);
+      TObjectList<TObject>(aTgtObjList).Add(obj);
+    end;
+  end;
+end;
+{$ELSE}
+begin
+
+end;
+
+{$ENDIF}
+
 end.

+ 82 - 15
Quick.Commons.pas

@@ -7,7 +7,7 @@
   Author      : Kike Pérez
   Version     : 1.5
   Created     : 14/07/2017
-  Modified    : 13/08/2018
+  Modified    : 19/09/2018
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -101,7 +101,7 @@ type
 
   {$IFNDEF FPC}
   TFileHelper = record helper for TFile
-    {$IFDEF MSWINDOWS}
+    {$IF DEFINED(MSWINDOWS) OR DEFINED(DELPHILINUX)}
     class function IsInUse(const FileName : string) : Boolean; static;
     {$ENDIF}
     class function GetSize(const FileName: String): Int64; static;
@@ -198,6 +198,8 @@ type
   function FillStr(const C : Char; const Count : Byte) : string;
   //checks if string exists in array of string
   function StrInArray(const aValue : string; const aInArray : array of string) : Boolean;
+  //checks if integer exists in array of integer
+  function IntInArray(const aValue : Integer; const aInArray : array of Integer) : Boolean;
   //returns a number leading zero
   function Zeroes(const Number, Len : Int64) : string;
   //converts a number to thousand delimeter string
@@ -247,6 +249,8 @@ type
   function CountDigits(anInt: Cardinal): Cardinal; inline;
   //save stream to file
   procedure SaveStreamToFile(stream : TStream; const filename : string);
+  //returns a real comma separated text from stringlist
+  function CommaText(aList : TStringList) : string;
   {$IFDEF MSWINDOWS}
   //process messages on console applications
   procedure ProcessMessages;
@@ -256,6 +260,7 @@ type
   {$IF DEFINED(FPC) AND DEFINED(MSWINDOWS)}
   function GetLastInputInfo(var plii: TLastInputInfo): BOOL;stdcall; external 'user32' name 'GetLastInputInfo';
   {$ENDIF}
+  function RemoveLastChar(const aText : string) : string;
 
 {$IFDEF MSWINDOWS}
 var
@@ -293,6 +298,21 @@ begin
   end;
 end;
 {$ENDIF}
+{$IFDEF DELPHILINUX}
+class function TFileHelper.IsInUse(const FileName : string) : Boolean;
+var
+  fs : TFileStream;
+begin
+  try
+    fs := TFileStream.Create(FileName, fmOpenReadWrite, fmShareExclusive);
+    Result := True;
+    fs.Free;
+  except
+    Result := False;
+  end;
+
+end;
+{$ENDIF}
 
 {$IFDEF MSWINDOWS}
 class function TFileHelper.GetSize(const FileName: String): Int64;
@@ -546,6 +566,17 @@ begin
   Result := False;
 end;
 
+function IntInArray(const aValue : Integer; const aInArray : array of Integer) : Boolean;
+var
+  i : Integer;
+begin
+  for i in aInArray do
+  begin
+    if i = aValue then Exit(True);
+  end;
+  Result := False;
+end;
+
 function Zeroes(const Number, Len : Int64) : string;
 begin
   if Len > Length(IntToStr(Number)) then Result := FillStr('0',Len - Length(IntToStr(Number))) + IntToStr(Number)
@@ -683,7 +714,7 @@ function GetComputerName : string;
     Result := pchar(result);
   end;
 {$ELSE}
-  {$IF DEFINED(FPC) AND DEFINED(LINUX)}
+  {$IF DEFINED(FPC) OR DEFINED(LINUX)}
   begin
     Result := GetEnvironmentVariable('COMPUTERNAME');
   end;
@@ -814,12 +845,18 @@ end;
       else Result := '';
   end;
   {$ELSE}
-  var
-    PkgInfo : JPackageInfo;
-  begin
-    PkgInfo := SharedActivity.getPackageManager.getPackageInfo(SharedActivity.getPackageName,0);
-    Result := IntToStr(PkgInfo.VersionCode);
-  end;
+    {$IFDEF NEXTGEN}
+    var
+      PkgInfo : JPackageInfo;
+    begin
+      PkgInfo := SharedActivity.getPackageManager.getPackageInfo(SharedActivity.getPackageName,0);
+      Result := IntToStr(PkgInfo.VersionCode);
+    end;
+    {$ELSE}
+    begin
+      Result := 'N/A';
+    end;
+    {$ENDIF}
   {$ENDIF}
 {$ENDIF}
 
@@ -876,12 +913,18 @@ end;
       else Result := '';
   end;
   {$ELSE}
-  var
-    PkgInfo : JPackageInfo;
-  begin
-    PkgInfo := SharedActivity.getPackageManager.getPackageInfo(SharedActivity.getPackageName,0);
-    Result := JStringToString(PkgInfo.versionName);
-  end;
+    {$IFDEF NEXTGEN}
+    var
+      PkgInfo : JPackageInfo;
+    begin
+      PkgInfo := SharedActivity.getPackageManager.getPackageInfo(SharedActivity.getPackageName,0);
+      Result := JStringToString(PkgInfo.versionName);
+    end;
+    {$ELSE}
+    begin
+      Result := 'N/A';
+    end;
+    {$ENDIF}
   {$ENDIF}
 {$ENDIF}
 
@@ -991,6 +1034,25 @@ begin
   end;
 end;
 
+function CommaText(aList : TStringList) : string;
+var
+  value : string;
+  sb : TStringBuilder;
+begin
+  if aList.Text = '' then Exit;
+  sb := TStringBuilder.Create;
+  try
+    for value in aList do
+    begin
+      sb.Append(value);
+      sb.Append(',');
+    end;
+    if sb.Length > 1 then Result := sb.ToString(0, sb.Length - 1);
+  finally
+    sb.Free;
+  end;
+end;
+
 { TCounter }
 
 procedure TCounter.Init(aMaxValue : Integer);
@@ -1068,6 +1130,11 @@ begin
 end;
 {$ENDIF}
 
+function RemoveLastChar(const aText : string) : string;
+begin
+  Result := aText.Remove(aText.Length - 1);
+end;
+
 {$IFDEF MSWINDOWS}
 initialization
   try

+ 5 - 19
Quick.JSONUtils.pas → Quick.JSON.Helper.pas

@@ -2,7 +2,7 @@
 
   Copyright (c) 2015-2018 Kike Pérez
 
-  Unit        : Quick.JSONUtils
+  Unit        : Quick.JSON.Helper
   Description : Utils for working with JSON
   Author      : Kike Pérez
   Version     : 1.1
@@ -27,7 +27,7 @@
 
  *************************************************************************** }
 
-unit Quick.JSONUtils;
+unit Quick.JSON.Helper;
 
 {$i QuickLib.inc}
 
@@ -40,12 +40,13 @@ uses
     JSON.Types,
     REST.Json,
     System.JSON,
-    JSON.Serializers;
+    JSON.Serializers,
   {$ELSE}
     System.JSON,
     REST.JSON,
-    Rest.Json.Types;
+    Rest.Json.Types,
   {$ENDIF}
+  Quick.Json.Utils;
 
 type
   TObjectHelper = class helper for TObject
@@ -57,9 +58,6 @@ type
 
   //only public properties will be cloned or gotten
 
-  function IncludeJsonBraces(const json : string) : string;
-  function RemoveJsonBraces(const json : string) : string;
-
 var
   GlobalJsonIdenter : Boolean = True;
 
@@ -111,17 +109,5 @@ begin
   cObj.FromJson(Self.ToJson);
 end;
 
-function IncludeJsonBraces(const json : string) : string;
-begin
-  if (not json.StartsWith('{')) and (not json.EndsWith('}')) then Result := '{' + json + '}'
-    else Result := json;
-end;
-
-function RemoveJsonBraces(const json : string) : string;
-begin
-  if (json.StartsWith('{')) and (json.EndsWith('}')) then Result := Copy(json,2,Json.Length - 2)
-    else Result := json;
-end;
-
 
 end.

+ 125 - 0
Quick.JSON.Utils.pas

@@ -0,0 +1,125 @@
+{ ***************************************************************************
+
+  Copyright (c) 2015-2018 Kike Pérez
+
+  Unit        : Quick.JSON.Utils
+  Description : Json utils
+  Author      : Kike Pérez
+  Version     : 1.4
+  Created     : 21/09/2018
+  Modified    : 24/09/2018
+
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+
+ ***************************************************************************
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ *************************************************************************** }
+
+unit Quick.JSON.Utils;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  SysUtils;
+
+type
+
+  TJsonUtils = class
+  public
+    class function IncludeJsonBraces(const json : string) : string;
+    class function RemoveJsonBraces(const json : string) : string;
+    class function JsonFormat(const json : string): string;
+  end;
+
+implementation
+
+class function TJsonUtils.IncludeJsonBraces(const json : string) : string;
+begin
+  if (not json.StartsWith('{')) and (not json.EndsWith('}')) then Result := '{' + json + '}'
+    else Result := json;
+end;
+
+class function TJsonUtils.RemoveJsonBraces(const json : string) : string;
+begin
+  if (json.StartsWith('{')) and (json.EndsWith('}')) then Result := Copy(json,2,Json.Length - 2)
+    else Result := json;
+end;
+
+
+class function TJsonUtils.JsonFormat(const json : string) : string;
+const
+  EOL = #13#10;
+  INDENT = '    ';
+  SPACE = ' ';
+var
+  c : char;
+  LIndent : string;
+  isEOL : Boolean;
+  isIntoString : Boolean;
+  isEscape : Boolean;
+  i : Integer;
+begin
+  Result := '';
+  isEOL := True;
+  isIntoString := False;
+  isEscape := False;
+  for i := 1 to json.Length do
+  begin
+    c := json[i];
+    if isIntoString then
+    begin
+      isEOL := False;
+      Result := Result + c;
+    end
+    else
+    begin
+      case c of
+        ':' : Result := Result + c + SPACE;
+        '{','[' :
+          begin
+            LIndent := LIndent + INDENT;
+            if json[i+1] in ['}',']'] then Result := Result + c
+              else Result := Result + c + EOL + LIndent;
+            isEOL := True;
+          end;
+        ',' :
+          begin
+            isEOL := False;
+            Result := Result + c + EOL + LIndent;
+          end;
+        '}',']' :
+          begin
+            Delete(LIndent, 1, Length(INDENT));
+            if not isEOL then Result := Result + EOL;
+            if json[i+1] = ',' then Result := Result + LIndent + c
+              else if json[i-1] in ['{','['] then Result := Result + c + EOL
+                else Result := Result + LIndent + c + EOL;
+            isEOL := True;
+          end;
+        else
+          begin
+            isEOL := False;
+            Result := Result + c;
+          end;
+      end;
+    end;
+    isEscape := (c = '\') and not isEscape;
+    if not isEscape and (c = '"') then isIntoString := not isIntoString;
+  end;
+end;
+
+end.

+ 4 - 4
Quick.JSONRecord.pas

@@ -41,7 +41,7 @@ type
   IJsonable = interface
   ['{AF71F59C-89A5-4BFB-8227-0CC3068B7671}']
     procedure FromJson(const aJson : string);
-    function ToJson : string;
+    function ToJson(aIdent : Boolean = False) : string;
     procedure MapTo(aTgtObj : TObject);
     procedure MapFrom(aSrcObj : TObject);
   end;
@@ -50,7 +50,7 @@ type
   public
     constructor CreateFromJson(const aJson : string);
     procedure FromJson(const aJson : string);
-    function ToJson : string;
+    function ToJson(aIdent : Boolean = False) : string;
     function Map<T : class, constructor> : T;
     procedure MapTo(aTgtObj : TObject);
     procedure MapFrom(aSrcObj : TObject);
@@ -101,13 +101,13 @@ begin
   TObjMapper.Map(Self,aTgtObj);
 end;
 
-function TJsonRecord.ToJson: string;
+function TJsonRecord.ToJson(aIdent : Boolean = False) : string;
 var
   serializer : TJsonSerializer;
 begin
   serializer := TJsonSerializer.Create(TSerializeLevel.slPublishedProperty);
   try
-    Result := serializer.ObjectToJson(Self);
+    Result := serializer.ObjectToJson(Self,aIdent);
   finally
     serializer.Free;
   end;

+ 98 - 89
Quick.Json.Serializer.pas

@@ -5,9 +5,9 @@
   Unit        : Quick.JSON.Serializer
   Description : Json Serializer
   Author      : Kike Pérez
-  Version     : 1.2
+  Version     : 1.4
   Created     : 21/05/2018
-  Modified    : 28/08/2018
+  Modified    : 21/09/2018
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -52,7 +52,8 @@ uses
     {$ENDIF}
   {$ENDIF}
   DateUtils,
-  Quick.Commons;
+  Quick.Commons,
+  Quick.JSON.Utils;
 
 type
 
@@ -83,15 +84,15 @@ type
   ['{CA26F7AE-F1FE-41BE-9C23-723A687F60D1}']
     function JsonToObject(aType: TClass; const aJson: string): TObject; overload;
     function JsonToObject(aObject: TObject; const aJson: string): TObject; overload;
-    function ObjectToJson(aObject: TObject): string;
+    function ObjectToJson(aObject : TObject; aIndent : Boolean = False): string;
   end;
 
   TSerializeLevel = (slPublicProperty, slPublishedProperty);
 
   PValue = ^TValue;
 
-  TJsonSerializer = class(TInterfacedObject,IJsonSerializer)
-  strict private
+  TRTTIJson = class
+  private
     fSerializeLevel : TSerializeLevel;
     function GetValue(aAddr: Pointer; aType: TRTTIType): TValue; overload;
     function GetValue(aAddr: Pointer; aTypeInfo: PTypeInfo): TValue; overload;
@@ -105,6 +106,8 @@ type
     function GetPropType(aPropInfo: PPropInfo): PTypeInfo;
     procedure LoadSetProperty(aInstance : TObject; aPropInfo: PPropInfo; const aValue: string);
     {$ENDIF}
+  public
+    constructor Create(aSerializeLevel : TSerializeLevel);
     {$IFNDEF FPC}
     function DeserializeDynArray(aTypeInfo : PTypeInfo; aObject : TObject; const aJsonArray: TJSONArray) : TValue;
     function DeserializeRecord(aRecord : TValue; aObject : TObject; const aJson : TJSONObject) : TValue;
@@ -129,12 +132,19 @@ type
     function Serialize(const aName : string; aValue : TValue) : TJSONPair;
     {$ENDIF}
     function Serialize(aObject : TObject) : TJSONObject; overload;
+  end;
+
+  TJsonSerializer = class(TInterfacedObject,IJsonSerializer)
+  strict private
+    fSerializeLevel : TSerializeLevel;
+    fRTTIJson : TRTTIJson;
   public
     constructor Create(aSerializeLevel : TSerializeLevel);
+    destructor Destroy; override;
     property SerializeLevel : TSerializeLevel read fSerializeLevel;
     function JsonToObject(aType : TClass; const aJson: string) : TObject; overload;
     function JsonToObject(aObject : TObject; const aJson: string) : TObject; overload;
-    function ObjectToJson(aObject : TObject): string;
+    function ObjectToJson(aObject : TObject; aIndent : Boolean = False): string;
   end;
 
   PPByte = ^PByte;
@@ -145,10 +155,10 @@ resourcestring
 
 implementation
 
-{ TJsonSerializer }
+{ TRTTIJson }
 
 {$IFNDEF FPC}
-function TJsonSerializer.DeserializeDynArray(aTypeInfo: PTypeInfo; aObject: TObject; const aJsonArray: TJSONArray) : TValue;
+function TRTTIJson.DeserializeDynArray(aTypeInfo: PTypeInfo; aObject: TObject; const aJsonArray: TJSONArray) : TValue;
 var
   rType: PTypeInfo;
   len: NativeInt;
@@ -213,7 +223,7 @@ begin
   end;
 end;
 {$ELSE}
-procedure TJsonSerializer.DeserializeDynArray(aTypeInfo: PTypeInfo; const aPropertyName : string; aObject: TObject; const aJsonArray: TJSONArray);
+procedure TRTTIJson.DeserializeDynArray(aTypeInfo: PTypeInfo; const aPropertyName : string; aObject: TObject; const aJsonArray: TJSONArray);
 var
   rType: PTypeInfo;
   len: NativeInt;
@@ -277,7 +287,7 @@ end;
 {$ENDIF}
 
 {$IFNDEF FPC}
-function TJsonSerializer.DeserializeRecord(aRecord : TValue; aObject : TObject; const aJson : TJSONObject) : TValue;
+function TRTTIJson.DeserializeRecord(aRecord : TValue; aObject : TObject; const aJson : TJSONObject) : TValue;
 var
   ctx : TRttiContext;
   rRec : TRttiRecordType;
@@ -341,51 +351,12 @@ begin
 end;
 {$ENDIF}
 
-function TJsonSerializer.JsonToObject(aObject: TObject; const aJson: string): TObject;
-var
-  json: TJSONObject;
+constructor TRTTIJson.Create(aSerializeLevel: TSerializeLevel);
 begin
-  json := TJsonObject(TJSONObject.ParseJSONValue(aJson,True));
-  try
-    Result := DeserializeObject(aObject,json);
-  finally
-    json.Free;
-  end;
-end;
-
-function TJsonSerializer.JsonToObject(aType: TClass; const aJson: string): TObject;
-var
-  json: TJSONObject;
-begin
-  json := TJSONObject.ParseJSONValue(aJson,True) as TJSONObject;
-  try
-    Result := DeserializeClass(aType,json);
-  finally
-    json.Free;
-  end;
-end;
-
-function TJsonSerializer.ObjectToJson(aObject: TObject): string;
-var
-  json: TJSONObject;
-begin
-  json := Serialize(aObject);
-  try
-    Result := json.ToJSON;
-  finally
-    json.Free;
-  end;
-end;
-
-constructor TJsonSerializer.Create(aSerializeLevel: TSerializeLevel);
-begin
-  {$IFDEF FPC}
-  if aSerializeLevel = TSerializeLevel.slPublicProperty then raise EJsonSerializeError.Create('FreePascal RTTI only supports published properties');
-  {$ENDIF}
   fSerializeLevel := aSerializeLevel;
 end;
 
-function TJsonSerializer.DeserializeClass(aType: TClass; const aJson: TJSONObject): TObject;
+function TRTTIJson.DeserializeClass(aType: TClass; const aJson: TJSONObject): TObject;
 begin
   Result := nil;
   if (aJson = nil) or (aJson.Count = 0) then Exit;
@@ -402,7 +373,7 @@ begin
   end;
 end;
 
-function TJsonSerializer.DeserializeObject(aObject: TObject; const aJson: TJSONObject): TObject;
+function TRTTIJson.DeserializeObject(aObject: TObject; const aJson: TJSONObject): TObject;
 var
   ctx: TRttiContext;
   rType: TRttiType;
@@ -460,7 +431,7 @@ begin
 end;
 
 {$IFNDEF FPC}
-function TJsonSerializer.DeserializeList(aObject: TObject; const aName : string; const aJson: TJSONObject) : TObject;
+function TRTTIJson.DeserializeList(aObject: TObject; const aName : string; const aJson: TJSONObject) : TObject;
 var
   ctx : TRttiContext;
   rType : TRttiType;
@@ -511,7 +482,7 @@ begin
 end;
 {$ENDIF}
 
-function TJsonSerializer.DeserializeProperty(aObject : TObject; const aName : string; aProperty : TRttiProperty; const aJson : TJSONObject) : TObject;
+function TRTTIJson.DeserializeProperty(aObject : TObject; const aName : string; aProperty : TRttiProperty; const aJson : TJSONObject) : TObject;
 var
   rValue : TValue;
   {$IFNDEF FPC}
@@ -606,7 +577,7 @@ begin
 end;
 
 {$IFNDEF FPC}
-function TJsonSerializer.DeserializeType(aObject : TObject; aType : TTypeKind; aTypeInfo : PTypeInfo; const aValue: string) : TValue;
+function TRTTIJson.DeserializeType(aObject : TObject; aType : TTypeKind; aTypeInfo : PTypeInfo; const aValue: string) : TValue;
 var
   i : Integer;
   value : string;
@@ -680,7 +651,7 @@ begin
   end;
 end;
 {$ELSE}
-function TJsonSerializer.DeserializeType(aObject : TObject; aType : TTypeKind; const aPropertyName, aValue: string) : TValue;
+function TRTTIJson.DeserializeType(aObject : TObject; aType : TTypeKind; const aPropertyName, aValue: string) : TValue;
 var
   value : string;
   propinfo : PPropInfo;
@@ -761,22 +732,21 @@ begin
 end;
 {$ENDIF}
 
-function TJsonSerializer.IsAllowedProperty(aObject : TObject; const aPropertyName : string) : Boolean;
+function TRTTIJson.IsAllowedProperty(aObject : TObject; const aPropertyName : string) : Boolean;
 var
   propname : string;
   cname : string;
 begin
   Result := True;
   propname := aPropertyName.ToLower;
-  cname := aObject.ClassName;
-  if (cname.StartsWith('TObjectList')) or (cname.StartsWith('TList')) then
+  if IsGenericList(aObject) then
   begin
     if (propname = 'capacity') or (propname = 'count') or (propname = 'ownsobjects') then Result := False;
   end
   else if (propname = 'refcount') then Result := False;
 end;
 
-function TJsonSerializer.IsGenericList(aObject : TObject) : Boolean;
+function TRTTIJson.IsGenericList(aObject : TObject) : Boolean;
 var
   cname : string;
 begin
@@ -784,7 +754,7 @@ begin
   Result := (cname.StartsWith('TObjectList')) or (cname.StartsWith('TList'));
 end;
 
-function TJsonSerializer.GetPropertyValue(Instance : TObject; const PropertyName : string) : TValue;
+function TRTTIJson.GetPropertyValue(Instance : TObject; const PropertyName : string) : TValue;
 var
   pinfo : PPropInfo;
 begin
@@ -819,7 +789,7 @@ begin
   end;
 end;
 
-procedure TJsonSerializer.SetPropertyValue(Instance : TObject; const PropertyName : string; aValue : TValue);
+procedure TRTTIJson.SetPropertyValue(Instance : TObject; const PropertyName : string; aValue : TValue);
 var
   pinfo : PPropInfo;
 begin
@@ -827,7 +797,7 @@ begin
   SetPropertyValue(Instance,pinfo,aValue);
 end;
 
-procedure TJsonSerializer.SetPropertyValue(Instance : TObject; aPropInfo : PPropInfo; aValue : TValue);
+procedure TRTTIJson.SetPropertyValue(Instance : TObject; aPropInfo : PPropInfo; aValue : TValue);
 begin
   case aPropInfo.PropType^.Kind of
     tkInteger : SetOrdProp(Instance,aPropInfo,aValue.AsInteger);
@@ -856,7 +826,7 @@ begin
 end;
 
 {$IFDEF FPC}
-procedure TJsonSerializer.LoadSetProperty(aInstance : TObject; aPropInfo: PPropInfo; const aValue: string);
+procedure TRTTIJson.LoadSetProperty(aInstance : TObject; aPropInfo: PPropInfo; const aValue: string);
 type
   TCardinalSet = set of 0..SizeOf(Cardinal) * 8 - 1;
 const
@@ -884,7 +854,7 @@ begin
 end;
 {$ENDIF}
 
-function TJsonSerializer.Serialize(aObject: TObject): TJSONObject;
+function TRTTIJson.Serialize(aObject: TObject): TJSONObject;
 var
   ctx: TRttiContext;
   {$IFNDEF FPC}
@@ -979,25 +949,23 @@ begin
   end;
 end;
 
-function TJsonSerializer.GetValue(aAddr: Pointer; aType: TRTTIType): TValue;
+function TRTTIJson.GetValue(aAddr: Pointer; aType: TRTTIType): TValue;
 begin
   TValue.Make(aAddr,aType.Handle,Result);
 end;
 
-function TJsonSerializer.GetValue(aAddr: Pointer; aTypeInfo: PTypeInfo): TValue;
+function TRTTIJson.GetValue(aAddr: Pointer; aTypeInfo: PTypeInfo): TValue;
 begin
   TValue.Make(aAddr,aTypeInfo,Result);
 end;
 
 {$IFNDEF FPC}
-function TJsonSerializer.Serialize(const aName : string; aValue : TValue) : TJSONPair;
+function TRTTIJson.Serialize(const aName : string; aValue : TValue) : TJSONPair;
 var
   ctx: TRttiContext;
-  {$IFNDEF FPC}
   rRec : TRttiRecordType;
   rField : TRttiField;
   rDynArray : TRTTIDynamicArrayType;
-  {$ENDIF}
   json : TJSONObject;
   jArray : TJSONArray;
   jPair : TJSONPair;
@@ -1009,7 +977,6 @@ begin
   //Result.JsonString := TJSONString(aName);
   try
     case avalue.Kind of
-      {$IFNDEF FPC}
       tkDynArray :
         begin
           jArray := TJSONArray.Create;
@@ -1033,7 +1000,6 @@ begin
             ctx.Free;
           end;
         end;
-        {$ENDIF}
       tkClass :
         begin
            Result.JsonValue := TJSONValue(Serialize(aValue.AsObject));
@@ -1070,11 +1036,7 @@ begin
           end
           else
           begin
-            {$IFNDEF FPC}
             Result.JsonValue := TJSONNumber.Create(aValue.AsExtended);
-            {$ELSE}
-            Result.JsonValue := TJsonFloatNumber.Create(aValue.AsExtended);
-            {$ENDIF}
           end;
         end;
       tkEnumeration :
@@ -1093,7 +1055,6 @@ begin
         begin
           Result.JsonValue := TJSONString.Create(aValue.ToString);
         end;
-      {$IFNDEF FPC}
       tkRecord :
         begin
           rRec := ctx.GetType(aValue.TypeInfo).AsRecord;
@@ -1108,7 +1069,6 @@ begin
             ctx.Free;
           end;
         end;
-      {$ENDIF}
       tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
         begin
           //skip these properties
@@ -1116,30 +1076,24 @@ begin
         end
     else
       begin
-        {$IFNDEF FPC}
         raise EJsonSerializeError.CreateFmt(cNotSupportedDataType,[aName,GetTypeName(aValue.TypeInfo)]);
-        {$ELSE}
-        //raise EJsonDeserializeError.CreateFmt('Not supported type "%s":%d',[aName,Integer(aValue.Kind)]);
-        {$ENDIF}
       end;
     end;
   except
     on E : Exception do
     begin
       Result.Free;
-      {$IFNDEF FPC}
       raise EJsonSerializeError.CreateFmt('Serialize error class "%s.%s" : %s',[aName,aValue.ToString,e.Message]);
-      {$ENDIF}
     end;
   end;
 end;
 {$ELSE}
-function TJsonSerializer.GetPropType(aPropInfo: PPropInfo): PTypeInfo;
+function TRTTIJson.GetPropType(aPropInfo: PPropInfo): PTypeInfo;
 begin
   Result := aPropInfo^.PropType;
 end;
 
-function TJsonSerializer.FloatProperty(aObject : TObject; aPropInfo: PPropInfo): string;
+function TRTTIJson.FloatProperty(aObject : TObject; aPropInfo: PPropInfo): string;
 const
   Precisions: array[TFloatType] of Integer = (7, 15, 18, 18, 19);
 var
@@ -1151,7 +1105,7 @@ begin
     '.',fsettings.DecimalSeparator,[rfReplaceAll]);
 end;
 
-function TJsonSerializer.Serialize(const aName : string; aValue : TValue) : TJSONPair;
+function TRTTIJson.Serialize(const aName : string; aValue : TValue) : TJSONPair;
 begin
   Result := TJSONPair.Create(aName,nil);
   //Result.JsonString := TJSONString(aName);
@@ -1171,7 +1125,7 @@ begin
   end;
 end;
 
-function TJsonSerializer.Serialize(aObject : TObject; aType : TTypeKind; const aPropertyName : string) : TJSONPair;
+function TRTTIJson.Serialize(aObject : TObject; aType : TTypeKind; const aPropertyName : string) : TJSONPair;
 var
   propinfo : PPropInfo;
   jArray : TJsonArray;
@@ -1311,6 +1265,61 @@ begin
 end;
 {$ENDIF}
 
+
+{ TJsonSerializer}
+
+constructor TJsonSerializer.Create(aSerializeLevel: TSerializeLevel);
+begin
+  {$IFDEF FPC}
+  if aSerializeLevel = TSerializeLevel.slPublicProperty then raise EJsonSerializeError.Create('FreePascal RTTI only supports published properties');
+  {$ENDIF}
+  fSerializeLevel := aSerializeLevel;
+  fRTTIJson := TRTTIJson.Create(aSerializeLevel);
+end;
+
+function TJsonSerializer.JsonToObject(aType: TClass; const aJson: string): TObject;
+var
+  json: TJSONObject;
+begin
+  json := TJSONObject.ParseJSONValue(aJson,True) as TJSONObject;
+  try
+    Result := fRTTIJson.DeserializeClass(aType,json);
+  finally
+    json.Free;
+  end;
+end;
+
+destructor TJsonSerializer.Destroy;
+begin
+  fRTTIJson.Free;
+  inherited;
+end;
+
+function TJsonSerializer.JsonToObject(aObject: TObject; const aJson: string): TObject;
+var
+  json: TJSONObject;
+begin
+  json := TJsonObject(TJSONObject.ParseJSONValue(aJson,True));
+  try
+    Result := fRTTIJson.DeserializeObject(aObject,json);
+  finally
+    json.Free;
+  end;
+end;
+
+function TJsonSerializer.ObjectToJson(aObject : TObject; aIndent : Boolean = False): string;
+var
+  json: TJSONObject;
+begin
+  json := fRTTIJson.Serialize(aObject);
+  try
+    Result := json.ToJSON;
+    if aIndent then Result := TJsonUtils.JsonFormat(Result);
+  finally
+    json.Free;
+  end;
+end;
+
 {$IFNDEF FPC}
 { TCommentProperty }
 

+ 41 - 0
Quick.SyncObjs.Linux.Compatibility.pas

@@ -0,0 +1,41 @@
+unit Quick.SyncObjs.Linux.Compatibility;
+
+{i$ QuickLib.inc}
+
+interface
+
+uses
+  SyncObjs;
+
+type
+
+  TRTLCriticalSection = TCriticalSection;
+
+  procedure EnterCriticalSection(CS : TCriticalSection);
+  procedure LeaveCriticalSection(CS : TCriticalSection);
+  procedure InitializeCriticalSection(CS : TCriticalSection);
+  procedure DeleteCriticalSection(CS : TCriticalSection);
+
+implementation
+
+procedure EnterCriticalSection(CS : TCriticalSection);
+begin
+  CS.Enter;
+end;
+
+procedure LeaveCriticalSection(CS : TCriticalSection);
+begin
+  CS.Leave;
+end;
+
+procedure InitializeCriticalSection(CS : TCriticalSection);
+begin
+  CS := TCriticalSection.Create;
+end;
+
+procedure DeleteCriticalSection(CS : TCriticalSection);
+begin
+  CS.Free;
+end;
+
+end.

+ 10 - 3
QuickLib.inc

@@ -1,4 +1,4 @@
-{
+{
     This file is part of QuickLib: https://github.com/exilon/QuickLib
 
     QuickLibs. Copyright (C) 2018 Kike Pérez
@@ -27,6 +27,10 @@
   {$INLINE ON}
   {$define HASINLINE}
 
+  {$ifdef LINUX}
+    {$define FPCLINUX}
+  {$endif}
+
   {$ifdef ANDROID}
     {$define LINUX}
   {$endif}
@@ -111,11 +115,14 @@
     {$ifend}
     {$if CompilerVersion >= 31.0} //Delphi RX10.1 Berlin
       {$define DELPHIRX101_UP}
-	  {$define DELPHIBERLIN_UP}
+	    {$define DELPHIBERLIN_UP}
     {$ifend}
     {$if CompilerVersion >= 32.0} //Delphi RX10.2 Tokyo
       {$define DELPHIRX102_UP}
-	  {$define DELPHITOKYO_UP}
+	    {$define DELPHITOKYO_UP}
+      {$ifdef LINUX}
+        {$define DELPHILINUX}
+      {$ifend}
     {$ifend}
   {$else}
     //Delphi 5 or older

+ 2 - 0
quicklib.lpk

@@ -23,6 +23,7 @@
       </Item1>
       <Item2>
         <Filename Value="Quick.AppService.pas"/>
+        <AddToUsesPkgSection Value="False"/>
         <UnitName Value="Quick.AppService"/>
       </Item2>
       <Item3>
@@ -31,6 +32,7 @@
       </Item3>
       <Item4>
         <Filename Value="Quick.Chrono.pas"/>
+        <AddToUsesPkgSection Value="False"/>
         <UnitName Value="Quick.Chrono"/>
       </Item4>
       <Item5>

+ 5 - 5
quicklib.pas

@@ -8,11 +8,11 @@ unit QuickLib;
 interface
 
 uses
-  Quick.Console, Quick.AppService, Quick.Base64, Quick.Chrono, Quick.Commons, 
-  Quick.FileMonitor, Quick.Files, Quick.Format, Quick.Log, Quick.Network, 
-  Quick.Process, Quick.Service, Quick.SMTP, Quick.Threads, Quick.Config, 
-  Quick.Config.Provider.Json, Quick.Config.Provider.Registry, 
-  Quick.Json.fpc.Compatibility, Quick.JSONRecord;
+  Quick.Console, Quick.Base64, Quick.Commons, Quick.FileMonitor, Quick.Files, 
+  Quick.Format, Quick.Log, Quick.Network, Quick.Process, Quick.Service, 
+  Quick.SMTP, Quick.Threads, Quick.Config, Quick.Config.Provider.Json, 
+  Quick.Config.Provider.Registry, Quick.Json.fpc.Compatibility, 
+  Quick.JSONRecord;
 
 implementation
 

+ 64 - 8
samples/delphi/QuickAutoMapper/AutoMappingObjects.dpr

@@ -6,9 +6,11 @@ program AutoMappingObjects;
 
 uses
   System.SysUtils,
+  System.Generics.Collections,
   Quick.Commons,
   Quick.Console,
   Quick.JSONRecord,
+  Quick.Json.Serializer,
   Quick.AutoMapper;
 
 type
@@ -21,6 +23,8 @@ type
 
   TCarType = (ctOil, ctDiesel);
 
+  TAgentStatus = (stActive, stIdle, stFail);
+
   TCar = class
   private
     fModel : string;
@@ -30,25 +34,41 @@ type
     property CarType : TCarType read fCarType write fCarType;
   end;
 
+  TCarList = TObjectList<TCar>;
+
+  TAgent = record
+    Name : string;
+    Status : TAgentStatus;
+  end;
+
+  TAgentList = TList<TAgent>;
+
   TUserBase = class(TJsonRecord)
   private
     fName : string;
     fAge : Integer;
     fCreationDate : TDateTime;
     fNumbers : TArray<Integer>;
+    fAgent : TAgent;
   published
     property Name : string read fName write fName;
     property Age : Integer read fAge write fAge;
     property CreationDate : TDateTime read fCreationDate write fCreationDate;
     property Numbers : TArray<Integer> read fNumbers write fNumbers;
+    property Agent : TAgent read fAgent write fAgent;
   end;
 
+  TPointsList = TList<Integer>;
+
   TUser = class(TUserBase)
   private
     fId : Int64;
     fCash : Integer;
     fJob : TJob;
     fCar : TCar;
+    fCarList : TCarList;
+    fPoints : TPointsList;
+    fAgentList : TAgentList;
   public
     constructor Create;
     destructor Destroy; override;
@@ -57,34 +77,36 @@ type
     property Cash : Integer read fCash write fCash;
     property Job : TJob read fJob write fJob;
     property Car : TCar read fCar write fCar;
+    property CarList : TCarList read fCarList write fCarList;
+    property Points : TPointsList read fPoints write fPoints;
+    property AgentList : TAgentList read fAgentList write fAgentList;
   end;
 
   TUser2 = class(TUserBase)
   private
     fIdUser : Int64;
-    fName : string;
-    fAge : Integer;
-    fNumbers : TArray<Integer>;
     fJob : TJob;
     fMoney : Integer;
     fCar : TCar;
+    fCarList : TCarList;
+    fPoints : TPointsList;
+    fAgentList : TAgentList;
   public
     constructor Create;
     destructor Destroy; override;
   published
     property IdUser : Int64 read fIdUser write fIdUser;
-    property Name : string read fName write fName;
-    property Age : Integer read fAge write fAge;
-    property Numbers : TArray<Integer> read fNumbers write fNumbers;
     property Money : Integer read fMoney write fMoney;
     property Job : TJob read fJob write fJob;
     property Car : TCar read fCar write fCar;
+    property CarList : TCarList read fCarList write fCarList;
+    property Points : TPointsList read fPoints write fPoints;
+    property AgentList : TAgentList read fAgentList write fAgentList;
   end;
 
 var
   User : TUser;
   User2 : TUser2;
-  UserClone : TUser;
   job : TJob;
   AutoMapper : TAutoMapper<TUser,TUser2>;
 
@@ -93,11 +115,17 @@ var
 constructor TUser.Create;
 begin
   fCar := TCar.Create;
+  fCarList := TCarList.Create(True);
+  fPoints := TPointsList.Create;
+  fAgentList := TAgentList.Create;
 end;
 
 destructor TUser.Destroy;
 begin
   fCar.Free;
+  fCarList.Free;
+  fPoints.Free;
+  fAgentList.Free;
   inherited;
 end;
 
@@ -106,21 +134,31 @@ end;
 constructor TUser2.Create;
 begin
   fCar := TCar.Create;
+  fCarList := TCarList.Create(True);
+  fPoints := TPointsList.Create;
+  fAgentList := TAgentList.Create;
 end;
 
 destructor TUser2.Destroy;
 begin
   fCar.Free;
+  fCarList.Free;
+  fPoints.Free;
+  fAgentList.Free;
   inherited;
 end;
 
+var
+  car : TCar;
+  agent : TAgent;
+
 begin
   ReportMemoryLeaksOnShutdown := True;
   try
     User := TUser.Create;
     User.Id := 17;
     User.CreationDate := Now();
-    User.Name := 'Juan';
+    User.Name := 'John Miller';
     User.Age := 30;
     User.Numbers := [1,2,3,4,5];
     User.Cash := 3500;
@@ -130,6 +168,24 @@ begin
     User.Job := job;
     User.Car.Model := 'Ferrari';
     User.Car.CarType := ctOil;
+    car := TCar.Create;
+    car.Model := 'Ford';
+    car.CarType := ctDiesel;
+    User.CarList.Add(car);
+    car := TCar.Create;
+    car.Model := 'Nissan';
+    car.CarType := ctDiesel;
+    User.CarList.Add(car);
+    User.Points.Add(77);
+    User.Points.Add(100);
+    User.Points.Add(30);
+    agent.Name := 'FirstAgent';
+    agent.Status := TAgentStatus.stIdle;
+    User.Agent := agent;
+    User.AgentList.Add(agent);
+    agent.Name := 'SecondAgent';
+    agent.Status := TAgentStatus.stFail;
+    User.AgentList.Add(agent);
     //User2 := TMapper<TUser2>.Map(User);
     AutoMapper := TAutoMapper<TUser,TUser2>.Create;
     try

+ 231 - 1
samples/delphi/QuickConfig/ConfigToFileAndRegistry/Win64/Debug/Config.json

@@ -1 +1,231 @@
-{"Sizes":[23,11,554,12,34,29,77,30,48,59,773,221,98,3,22,983,122,231,433,12,31,987],"LastFilename":"library.txt","WindowPos":{"PosX":480,"PosY":0},"History":[{"Id":0,"Priority":"msLow","Redundant":true},{"Id":1,"Priority":"msLow","Redundant":true},{"Id":2,"Priority":"msLow","Redundant":true},{"Id":3,"Priority":"msLow","Redundant":true},{"Id":4,"Priority":"msLow","Redundant":true},{"Id":5,"Priority":"msLow","Redundant":true},{"Id":6,"Priority":"msLow","Redundant":true},{"Id":7,"Priority":"msLow","Redundant":true},{"Id":8,"Priority":"msLow","Redundant":true},{"Id":9,"Priority":"msLow","Redundant":true},{"Id":10,"Priority":"msLow","Redundant":true},{"Id":11,"Priority":"msLow","Redundant":true},{"Id":12,"Priority":"msLow","Redundant":true},{"Id":13,"Priority":"msLow","Redundant":true},{"Id":14,"Priority":"msLow","Redundant":true},{"Id":15,"Priority":"msLow","Redundant":true}],"Complex":{"Id":88586818,"Priority":"msHigh","Redundant":false},"ModifyDate":"2018-07-17T14:38:51.937Z","Title":"a fresh title","SessionName":"First Session"}
+{
+  "Sizes": [
+    23,
+    11,
+    554,
+    12,
+    34,
+    29,
+    77,
+    30,
+    48,
+    59,
+    773,
+    221,
+    98,
+    3,
+    22,
+    983,
+    122,
+    231,
+    433,
+    12,
+    31,
+    987
+  ],
+  "LastFilename": "library.txt",
+  "WindowPos": {
+    "PosX": 480,
+    "PosY": 0
+  },
+  "History": [
+    {
+      "Id": 0,
+      "Priority": 0,
+      "Redundant": true
+    },
+    {
+      "Id": 1,
+      "Priority": 0,
+      "Redundant": true
+    },
+    {
+      "Id": 2,
+      "Priority": 0,
+      "Redundant": true
+    },
+    {
+      "Id": 3,
+      "Priority": 0,
+      "Redundant": true
+    },
+    {
+      "Id": 4,
+      "Priority": 0,
+      "Redundant": true
+    },
+    {
+      "Id": 5,
+      "Priority": 0,
+      "Redundant": true
+    },
+    {
+      "Id": 6,
+      "Priority": 0,
+      "Redundant": true
+    },
+    {
+      "Id": 7,
+      "Priority": 0,
+      "Redundant": true
+    },
+    {
+      "Id": 8,
+      "Priority": 0,
+      "Redundant": true
+    },
+    {
+      "Id": 9,
+      "Priority": 0,
+      "Redundant": true
+    },
+    {
+      "Id": 10,
+      "Priority": 0,
+      "Redundant": true
+    },
+    {
+      "Id": 11,
+      "Priority": 0,
+      "Redundant": true
+    },
+    {
+      "Id": 12,
+      "Priority": 0,
+      "Redundant": true
+    },
+    {
+      "Id": 13,
+      "Priority": 0,
+      "Redundant": true
+    },
+    {
+      "Id": 14,
+      "Priority": 0,
+      "Redundant": true
+    },
+    {
+      "Id": 15,
+      "Priority": 0,
+      "Redundant": true
+    }
+  ],
+  "Complex": {
+    "Id": 35907504,
+    "Priority": 2,
+    "Redundant": false
+  },
+  "ModifyDate": "08/14/2018 00:45:53",
+  "Title": "a fresh title",
+  "SessionName": "First Session",
+  "WorkList": {
+    "FOwnsObjects": true,
+    "FListHelper": {
+      "FCount": 23
+    },
+    "FItems": [
+      {
+        "Name": "Process 0",
+        "Active": false
+      },
+      {
+        "Name": "Process 1",
+        "Active": false
+      },
+      {
+        "Name": "Process 2",
+        "Active": false
+      },
+      {
+        "Name": "Process 3",
+        "Active": false
+      },
+      {
+        "Name": "Process 4",
+        "Active": false
+      },
+      {
+        "Name": "Process 5",
+        "Active": false
+      },
+      {
+        "Name": "Process 6",
+        "Active": false
+      },
+      {
+        "Name": "Process 7",
+        "Active": false
+      },
+      {
+        "Name": "Process 8",
+        "Active": false
+      },
+      {
+        "Name": "Process 9",
+        "Active": false
+      },
+      {
+        "Name": "Process 10",
+        "Active": false
+      },
+      {
+        "Name": "Process 11",
+        "Active": false
+      },
+      {
+        "Name": "Process 12",
+        "Active": false
+      },
+      {
+        "Name": "Process 13",
+        "Active": false
+      },
+      {
+        "Name": "Process 14",
+        "Active": false
+      },
+      {
+        "Name": "Process 15",
+        "Active": false
+      },
+      {
+        "Name": "Process 16",
+        "Active": false
+      },
+      {
+        "Name": "Process 17",
+        "Active": false
+      },
+      {
+        "Name": "Process 18",
+        "Active": false
+      },
+      {
+        "Name": "Process 19",
+        "Active": false
+      },
+      {
+        "Name": "Process 20",
+        "Active": false
+      },
+      {
+        "Name": "Process 21",
+        "Active": false
+      },
+      {
+        "Name": "Process 22",
+        "Active": false
+      },
+      null,
+      null,
+      null,
+      null,
+      null,
+      null,
+      null,
+      null,
+      null
+    ],
+    "FComparer": {}
+  }
+}

+ 2 - 2
samples/delphi/QuickJsonSerializer/main.pas

@@ -185,7 +185,7 @@ begin
   User2.FromJson(Memo1.Text);
   //User2.CreateFromJson(Memo1.Text);
   Memo1.Lines.Add('User2 as json:');
-  Memo1.Lines.Add(User2.ToJson);
+  Memo1.Lines.Add(User2.ToJson(True));
   Memo1.Lines.Add(Format('Groups.OwnedObjects=%s',[BoolToStr(User2.Groups.OwnsObjects,True)]));
   Memo1.Lines.Add(Format('Groups.Count=%d',[User2.Groups.Count]));
   Memo1.Lines.Add(Format('Groups.Capacity=%d',[User2.Groups.Capacity]));
@@ -194,7 +194,7 @@ end;
 
 procedure TForm1.btnToJsonClick(Sender: TObject);
 begin
-  Memo1.Text := User.ToJson;
+  Memo1.Text := User.ToJson(True);
 end;
 
 procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

+ 7 - 7
samples/firemonkey/QuickAutoMapper/AutoMapperObjects.dproj

@@ -6,7 +6,7 @@
         <MainSource>AutoMapperObjects.dpr</MainSource>
         <Base>True</Base>
         <Config Condition="'$(Config)'==''">Debug</Config>
-        <Platform Condition="'$(Platform)'==''">Android</Platform>
+        <Platform Condition="'$(Platform)'==''">Win64</Platform>
         <TargetedPlatforms>1119</TargetedPlatforms>
         <AppType>Application</AppType>
     </PropertyGroup>
@@ -397,6 +397,12 @@
                         <Overwrite>true</Overwrite>
                     </Platform>
                 </DeployFile>
+                <DeployFile LocalName="$(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png" Configuration="Debug" Class="Android_SplashImage960">
+                    <Platform Name="Android">
+                        <RemoteName>splash_image.png</RemoteName>
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
                 <DeployFile LocalName="$(BDS)\Redist\osx32\libcgsqlite3.dylib" Class="DependencyModule">
                     <Platform Name="OSX32">
                         <Overwrite>true</Overwrite>
@@ -420,12 +426,6 @@
                         <Overwrite>true</Overwrite>
                     </Platform>
                 </DeployFile>
-                <DeployFile LocalName="$(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png" Configuration="Debug" Class="Android_SplashImage960">
-                    <Platform Name="Android">
-                        <RemoteName>splash_image.png</RemoteName>
-                        <Overwrite>true</Overwrite>
-                    </Platform>
-                </DeployFile>
                 <DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule">
                     <Platform Name="OSX32">
                         <Overwrite>true</Overwrite>

BIN
samples/firemonkey/QuickAutoMapper/AutoMapperObjects.res


+ 64 - 5
samples/firemonkey/QuickAutoMapper/Main.pas

@@ -6,7 +6,7 @@ uses
   System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
   FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
   Quick.AutoMapper, Quick.JSONRecord, FMX.Controls.Presentation,
-  FMX.ScrollBox, FMX.Memo;
+  FMX.ScrollBox, FMX.Memo, System.Generics.Collections;
 
 type
   TForm1 = class(TForm)
@@ -18,7 +18,7 @@ type
     { Public declarations }
   end;
 
-TJob = record
+  TJob = record
     Name : string;
     DateFrom : TDateTime;
     DateTo : TDateTime;
@@ -26,6 +26,8 @@ TJob = record
 
   TCarType = (ctOil, ctDiesel);
 
+  TAgentStatus = (stActive, stIdle, stFail);
+
   TCar = class
   private
     fModel : string;
@@ -35,25 +37,41 @@ TJob = record
     property CarType : TCarType read fCarType write fCarType;
   end;
 
+  TCarList = TObjectList<TCar>;
+
+  TAgent = record
+    Name : string;
+    Status : TAgentStatus;
+  end;
+
+  TAgentList = TList<TAgent>;
+
   TUserBase = class(TJsonRecord)
   private
     fName : string;
     fAge : Integer;
     fCreationDate : TDateTime;
     fNumbers : TArray<Integer>;
+    fAgent : TAgent;
   published
     property Name : string read fName write fName;
     property Age : Integer read fAge write fAge;
     property CreationDate : TDateTime read fCreationDate write fCreationDate;
     property Numbers : TArray<Integer> read fNumbers write fNumbers;
+    property Agent : TAgent read fAgent write fAgent;
   end;
 
+  TPointsList = TList<Integer>;
+
   TUser = class(TUserBase)
   private
     fId : Int64;
     fCash : Integer;
     fJob : TJob;
     fCar : TCar;
+    fCarList : TCarList;
+    fPoints : TPointsList;
+    fAgentList : TAgentList;
   public
     constructor Create;
     destructor Destroy; override;
@@ -62,6 +80,9 @@ TJob = record
     property Cash : Integer read fCash write fCash;
     property Job : TJob read fJob write fJob;
     property Car : TCar read fCar write fCar;
+    property CarList : TCarList read fCarList write fCarList;
+    property Points : TPointsList read fPoints write fPoints;
+    property AgentList : TAgentList read fAgentList write fAgentList;
   end;
 
   TUser2 = class(TUserBase)
@@ -70,6 +91,9 @@ TJob = record
     fJob : TJob;
     fMoney : Integer;
     fCar : TCar;
+    fCarList : TCarList;
+    fPoints : TPointsList;
+    fAgentList : TAgentList;
   public
     constructor Create;
     destructor Destroy; override;
@@ -78,6 +102,9 @@ TJob = record
     property Money : Integer read fMoney write fMoney;
     property Job : TJob read fJob write fJob;
     property Car : TCar read fCar write fCar;
+    property CarList : TCarList read fCarList write fCarList;
+    property Points : TPointsList read fPoints write fPoints;
+    property AgentList : TAgentList read fAgentList write fAgentList;
   end;
 
 var
@@ -86,6 +113,8 @@ var
   UserClone : TUser;
   job : TJob;
   AutoMapper : TAutoMapper<TUser,TUser2>;
+  car : TCar;
+  agent : TAgent;
 
 var
   Form1: TForm1;
@@ -99,11 +128,17 @@ implementation
 constructor TUser.Create;
 begin
   fCar := TCar.Create;
+  fCarList := TCarList.Create(True);
+  fPoints := TPointsList.Create;
+  fAgentList := TAgentList.Create;
 end;
 
 destructor TUser.Destroy;
 begin
   fCar.Free;
+  fCarList.Free;
+  fPoints.Free;
+  fAgentList.Free;
   inherited;
 end;
 
@@ -112,11 +147,17 @@ end;
 constructor TUser2.Create;
 begin
   fCar := TCar.Create;
+  fCarList := TCarList.Create(True);
+  fPoints := TPointsList.Create;
+  fAgentList := TAgentList.Create;
 end;
 
 destructor TUser2.Destroy;
 begin
   fCar.Free;
+  fCarList.Free;
+  fPoints.Free;
+  fAgentList.Free;
   inherited;
 end;
 
@@ -125,7 +166,7 @@ begin
 User := TUser.Create;
     User.Id := 17;
     User.CreationDate := Now();
-    User.Name := 'Jhon Miller';
+    User.Name := 'John Miller';
     User.Age := 30;
     User.Numbers := [1,2,3,4,5];
     User.Cash := 3500;
@@ -135,6 +176,24 @@ User := TUser.Create;
     User.Job := job;
     User.Car.Model := 'Ferrari';
     User.Car.CarType := ctOil;
+    car := TCar.Create;
+    car.Model := 'Ford';
+    car.CarType := ctDiesel;
+    User.CarList.Add(car);
+    car := TCar.Create;
+    car.Model := 'Nissan';
+    car.CarType := ctDiesel;
+    User.CarList.Add(car);
+    User.Points.Add(77);
+    User.Points.Add(100);
+    User.Points.Add(30);
+    agent.Name := 'FirstAgent';
+    agent.Status := TAgentStatus.stIdle;
+    User.Agent := agent;
+    User.AgentList.Add(agent);
+    agent.Name := 'SecondAgent';
+    agent.Status := TAgentStatus.stFail;
+    User.AgentList.Add(agent);
     //User2 := TMapper<TUser2>.Map(User);
     AutoMapper := TAutoMapper<TUser,TUser2>.Create;
     try
@@ -162,10 +221,10 @@ User := TUser.Create;
 
       Memo1.Lines.Add(' ');
       Memo1.Lines.Add('USER AS JSON RESULT');
-      Memo1.Lines.Add(Format('%s',[User.ToJson]));
+      Memo1.Lines.Add(Format('%s',[User.ToJson(True)]));
       Memo1.Lines.Add(' ');
       Memo1.Lines.Add('USER2 AS JSON RESULT');
-      Memo1.Lines.Add(Format('%s',[User2.ToJson]));
+      Memo1.Lines.Add(Format('%s',[User2.ToJson(True)]));
 
     finally
       AutoMapper.Free;

BIN
samples/fpc/QuickAutoMapper/AutoMapperObjects


+ 0 - 4
samples/fpc/QuickAutoMapper/AutoMapperObjects.lpi

@@ -43,10 +43,6 @@
       <OtherUnitFiles Value="..\..\.."/>
       <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
     </SearchPaths>
-    <CodeGeneration>
-      <TargetCPU Value="x86_64"/>
-      <TargetOS Value="linux"/>
-    </CodeGeneration>
   </CompilerOptions>
   <Debugging>
     <Exceptions Count="3">

+ 75 - 3
samples/fpc/QuickAutoMapper/AutoMapperObjects.lpr

@@ -2,6 +2,7 @@ program AutoMapperObjects;
 
 uses
   SysUtils,
+  Generics.Collections,
   Quick.Commons,
   Quick.Console,
   Quick.JSONRecord,
@@ -22,6 +23,8 @@ type
 
   TCarType = (ctOil, ctDiesel);
 
+  TAgentStatus = (stActive, stIdle, stFail);
+
   TCar = class
   private
     fModel : string;
@@ -31,27 +34,47 @@ type
     property CarType : TCarType read fCarType write fCarType;
   end;
 
-  TArrayOfInteger = array of Integer;
+  TCarList = specialize TObjectList<TCar>;
+
+  TAgent = class
+  private
+    fName : string;
+    fStatus : TAgentStatus;
+  published
+    property Name : string read fName write fName;
+    property Status : TAgentStatus read fStatus write fStatus;
+  end;
+
+  TAgentList = specialize TList<TAgent>;
+
+  TArrayNumbers = array of Integer;
 
   TUserBase = class(TJsonRecord)
   private
     fName : string;
     fAge : Integer;
     fCreationDate : TDateTime;
-    fNumbers : TArrayOfInteger;
+    fNumbers : TArrayNumbers;
+    fAgent : TAgent;
   published
     property Name : string read fName write fName;
     property Age : Integer read fAge write fAge;
     property CreationDate : TDateTime read fCreationDate write fCreationDate;
-    property Numbers : TArrayOfInteger read fNumbers write fNumbers;
+    property Numbers : TArrayNumbers read fNumbers write fNumbers;
+    property Agent : TAgent read fAgent write fAgent;
   end;
 
+  TPointsList = specialize TList<Integer>;
+
   TUser = class(TUserBase)
   private
     fId : Int64;
     fCash : Integer;
     fJob : TJob;
     fCar : TCar;
+    fCarList : TCarList;
+    fPoints : TPointsList;
+    fAgentList : TAgentList;
   public
     constructor Create;
     destructor Destroy; override;
@@ -60,6 +83,9 @@ type
     property Cash : Integer read fCash write fCash;
     property Job : TJob read fJob write fJob;
     property Car : TCar read fCar write fCar;
+    property CarList : TCarList read fCarList write fCarList;
+    property Points : TPointsList read fPoints write fPoints;
+    property AgentList : TAgentList read fAgentList write fAgentList;
   end;
 
   TUser2 = class(TUserBase)
@@ -68,6 +94,9 @@ type
     fJob : TJob;
     fMoney : Integer;
     fCar : TCar;
+    fCarList : TCarList;
+    fPoints : TPointsList;
+    fAgentList : TAgentList;
   public
     constructor Create;
     destructor Destroy; override;
@@ -76,12 +105,18 @@ type
     property Money : Integer read fMoney write fMoney;
     property Job : TJob read fJob write fJob;
     property Car : TCar read fCar write fCar;
+    property CarList : TCarList read fCarList write fCarList;
+    property Points : TPointsList read fPoints write fPoints;
+    property AgentList : TAgentList read fAgentList write fAgentList;
   end;
 
 var
   User : TUser;
   User2 : TUser2;
   AutoMapper : specialize TAutoMapper<TUser,TUser2>;
+  job : TJob;
+  car : TCar;
+  agent : TAgent;
 
 { TUser }
 
@@ -89,12 +124,20 @@ constructor TUser.Create;
 begin
   fCar := TCar.Create;
   fJob := TJob.Create;
+  fCarList := TCarList.Create(True);
+  fPoints := TPointsList.Create;
+  fAgent := TAgent.Create;
+  fAgentList := TAgentList.Create;
 end;
 
 destructor TUser.Destroy;
 begin
   fCar.Free;
   fJob.Free;
+  fCarList.Free;
+  fPoints.Free;
+  fAgent.Free;
+  fAgentList.Free;
   inherited;
 end;
 
@@ -104,12 +147,20 @@ constructor TUser2.Create;
 begin
   fCar := TCar.Create;
   fJob := TJob.Create;
+  fCarList := TCarList.Create(True);
+  fPoints := TPointsList.Create;
+  fAgent := TAgent.Create;
+  fAgentList := TAgentList.Create;
 end;
 
 destructor TUser2.Destroy;
 begin
   fCar.Free;
   fJob.Free;
+  fCarList.Free;
+  fPoints.Free;
+  fAgent.Free;
+  fAgentList.Free;
   inherited;
 end;
 
@@ -128,6 +179,27 @@ begin
     User.Job.DateTo := Now();
     User.Car.Model := 'Ferrari';
     User.Car.CarType := ctOil;
+    car := TCar.Create;
+    car.Model := 'Ford';
+    car.CarType := ctDiesel;
+    User.CarList.Add(car);
+    car := TCar.Create;
+    car.Model := 'Nissan';
+    car.CarType := ctDiesel;
+    User.CarList.Add(car);
+    User.Points.Add(77);
+    User.Points.Add(100);
+    User.Points.Add(30);
+    agent := TAgent.Create;
+    agent.Name := 'FirstAgent';
+    agent.Status := TAgentStatus.stIdle;
+    User.Agent.Name := 'John';
+    User.Agent.Status := TAgentStatus.stIdle;
+    User.AgentList.Add(agent);
+    agent := TAgent.Create;
+    agent.Name := 'SecondAgent';
+    agent.Status := TAgentStatus.stFail;
+    User.AgentList.Add(agent);
     //User2 := TMapper<TUser2>.Map(User);
     AutoMapper := specialize TAutoMapper<TUser,TUser2>.Create;
     try

BIN
samples/fpc/QuickChrono/simplechrono


+ 1 - 0
samples/fpc/QuickConfig/ConfigToFileAndRegistry/Config.json

@@ -0,0 +1 @@
+{ "Title" : "hola", "SessionName" : "", "Sizes" : [], "LastFilename" : "", "History" : [], "Complex" : { "Id" : 1, "Priority" : "msMed", "Redundant" : true }, "ModifyDate" : "2018-07-19T00:40:06.764Z " }

BIN
samples/fpc/QuickConsole/ConsoleOut/bin/x86_64-linux/ConsoleOut


BIN
samples/fpc/QuickJsonSerializer/JsonSerializer


BIN
samples/fpc/QuickJsonSerializer/lib/x86_64-linux/JsonSerializer.or


BIN
samples/fpc/QuickJsonSerializer/lib/x86_64-linux/JsonSerializer.res


+ 40 - 0
samples/fpc/QuickJsonSerializer/lib/x86_64-linux/main.lfm

@@ -0,0 +1,40 @@
+object Form1: TForm1
+  Left = 343
+  Height = 621
+  Top = 226
+  Width = 1025
+  Caption = 'Form1'
+  ClientHeight = 621
+  ClientWidth = 1025
+  OnClose = FormClose
+  OnCreate = FormCreate
+  LCLVersion = '1.9.0.0'
+  object Memo1: TMemo
+    Left = 8
+    Height = 540
+    Top = 8
+    Width = 1008
+    Lines.Strings = (
+      'Memo1'
+    )
+    TabOrder = 0
+  end
+  object btnFromJson: TButton
+    Left = 920
+    Height = 25
+    Top = 582
+    Width = 94
+    Caption = 'FromJson'
+    OnClick = btnFromJsonClick
+    TabOrder = 1
+  end
+  object btnToJson: TButton
+    Left = 808
+    Height = 25
+    Top = 582
+    Width = 99
+    Caption = 'ToJson'
+    OnClick = btnToJsonClick
+    TabOrder = 2
+  end
+end