浏览代码

[jsonSerializer] refactorize & performance

Exilon 5 年之前
父节点
当前提交
90ed2ec681
共有 1 个文件被更改,包括 278 次插入371 次删除
  1. 278 371
      Quick.Json.Serializer.pas

+ 278 - 371
Quick.Json.Serializer.pas

@@ -7,7 +7,7 @@
   Author      : Kike Pérez
   Version     : 1.11
   Created     : 21/05/2018
-  Modified    : 05/04/2020
+  Modified    : 07/04/2020
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -45,7 +45,7 @@ uses
    strUtils,
    //jsonreader,
    //fpjsonrtti,
-   Quick.Json.fpc.Compatibility,
+   Quick.Json.fpc.Compatibility,  
   {$ELSE}
     {$IFDEF DELPHIXE7_UP}
     System.Json,
@@ -90,7 +90,7 @@ type
     function JsonToObject(aType: TClass; const aJson: string): TObject; overload;
     function JsonToObject(aObject: TObject; const aJson: string): TObject; overload;
     function ObjectToJson(aObject : TObject; aIndent : Boolean = False): string;
-    function ValueToJson(aValue : TValue; aIndent : Boolean = False) : string;
+    function ValueToJson(const aValue : TValue; aIndent : Boolean = False) : string;
   end;
 
   TSerializeLevel = (slPublicProperty, slPublishedProperty);
@@ -108,7 +108,7 @@ type
     function GetPropertyValue(Instance : TObject; const PropertyName : string) : TValue;
     function GetPropertyValueFromObject(Instance : TObject; const PropertyName : string) : TValue;
     {$IFNDEF FPC}
-    function GetFieldValueFromRecord(aValue : TValue; const FieldName : string) : TValue;
+    function GetFieldValueFromRecord(const aValue : TValue; const FieldName : string) : TValue;
     {$ENDIF}
     procedure SetPropertyValue(Instance : TObject; aPropInfo : PPropInfo; aValue : TValue); overload;
     procedure SetPropertyValue(Instance : TObject; const PropertyName : string; aValue : TValue); overload;
@@ -121,33 +121,31 @@ type
     constructor Create(aSerializeLevel : TSerializeLevel; aUseEnumNames : Boolean = True);
     property UseEnumNames : Boolean read fUseEnumNames write fUseEnumNames;
     property UseJsonCaseSense : Boolean read fUseJsonCaseSense write fUseJsonCaseSense;
+    function GetJsonPairValueByName(aJson : TJSONObject; const aName : string) : TJsonValue;
+    function GetJsonPairByName(aJson : TJSONObject; const aName : string) : TJSONPair;
+    //serialize methods
+    function SerializeValue(const aValue : TValue) : TJSONValue;
+    function SerializeObject(aObject : TObject) : TJSONObject; overload;
     {$IFNDEF FPC}
-    function DeserializeDynArray(aTypeInfo : PTypeInfo; aObject : TObject; const aJsonArray: TJSONArray) : TValue;
-    function DeserializeRecord(aRecord : TValue; aObject : TObject; const aJson : TJSONObject) : TValue;
+    function SerializeDynArray(const aValue: TValue) : TJsonArray;
+    function SerializeRecord(const aValue : TValue) : TJSONValue;
     {$ELSE}
-    procedure DeserializeDynArray(aTypeInfo: PTypeInfo; const aPropertyName : string; aObject: TObject; const aJsonArray: TJSONArray);
+    function SerializeObject(aObject : TObject; aType : TTypeKind; const aPropertyName : string) : TJSONPair;
     {$ENDIF}
+    //deserialize methods
     function DeserializeClass(aType : TClass; const aJson : TJSONObject) : TObject;
     function DeserializeObject(aObject : TObject; const aJson : TJSONObject) : TObject; overload;
-    {$IFNDEF FPC}
-    function DeserializeList(aObject: TObject; const aName : string; const aJson: TJSONObject) : TObject;
-    procedure DeserializeXArray(Instance : TObject; aRecord : TValue; aProperty : TRttiProperty; const aPropertyName : string; aJson : TJsonObject);
-    {$ENDIF}
     function DeserializeProperty(aObject : TObject; const aName : string; aProperty : TRttiProperty; const aJson : TJSONObject) : TObject; overload;
     {$IFNDEF FPC}
     function DeserializeType(aObject : TObject; aType : TTypeKind; aTypeInfo : PTypeInfo; const aValue: string) : TValue;
+    function DeserializeDynArray(aTypeInfo : PTypeInfo; aObject : TObject; const aJsonArray: TJSONArray) : TValue;
+    function DeserializeRecord(const aRecord : TValue; aObject : TObject; const aJson : TJSONObject) : TValue;
+    function DeserializeList(aObject: TObject; const aName : string; const aJson: TJSONObject) : TObject;
+    procedure DeserializeXArray(Instance : TObject; aRecord : TValue; aProperty : TRttiProperty; const aPropertyName : string; aJson : TJsonObject);
     {$ELSE}
     function DeserializeType(aObject : TObject; aType : TTypeKind; const aPropertyName, aValue: string) : TValue;
+    procedure DeserializeDynArray(aTypeInfo: PTypeInfo; const aPropertyName : string; aObject: TObject; const aJsonArray: TJSONArray);
     {$ENDIF}
-    {$IFNDEF FPC}
-    function Serialize(const aName : string; aValue : TValue) : TJSONPair; overload;
-    {$ELSE}
-    function Serialize(aObject : TObject; aType : TTypeKind; const aPropertyName : string) : TJSONPair;
-    function Serialize(const aName : string; aValue : TValue) : TJSONPair;
-    {$ENDIF}
-    function Serialize(aObject : TObject) : TJSONObject; overload;
-    function GetJsonPairValueByName(aJson : TJSONObject; const aName : string) : TJsonValue;
-    function GetJsonPairByName(aJson : TJSONObject; const aName : string) : TJSONPair;
   end;
 
   TJsonSerializer = class(TInterfacedObject,IJsonSerializer)
@@ -169,20 +167,26 @@ type
     function JsonToObject(aObject : TObject; const aJson: string) : TObject; overload;
     function ObjectToJson(aObject : TObject; aIndent : Boolean = False): string;
     function ObjectToJsonString(aObject : TObject; aIndent : Boolean = False): string;
-    function ValueToJson(aValue : TValue; aIndent : Boolean = False) : string;
-    function ValueToJsonString(aValue : TValue; aIndent : Boolean = False) : string;
+    function ValueToJson(const aValue : TValue; aIndent : Boolean = False) : string;
+    function ValueToJsonString(const aValue : TValue; aIndent : Boolean = False) : string;
     function ArrayToJson<T>(aArray : TArray<T>; aIndent : Boolean = False) : string;
     function ArrayToJsonString<T>(aArray : TArray<T>; aIndent : Boolean = False) : string;
     {$IFNDEF FPC}
     function JsonToArray<T>(const aJson : string) : TArray<T>;
+    function JsonToValue(const aJson: string): TValue;
     {$ENDIF}
   end;
 
+  EJsonSerializerError = class(Exception);
+
   PPByte = ^PByte;
 
 resourcestring
-  cNotSupportedDataType = 'Not supported "%s" data type "%s"';
+  cNotSupportedDataType = 'Not supported data type "%s"';
+  cSerializeObjectError = 'Serialize object "%s" error: %s';
+  cSerializePropertyError = 'Property "%s" ("%s")';
   cNotSerializable = 'Object is not serializable';
+  cNotValidJson = 'Not a valid Json';
 
 implementation
 
@@ -323,7 +327,7 @@ end;
 {$ENDIF}
 
 {$IFNDEF FPC}
-function TRTTIJson.DeserializeRecord(aRecord : TValue; aObject : TObject; const aJson : TJSONObject) : TValue;
+function TRTTIJson.DeserializeRecord(const aRecord : TValue; aObject : TObject; const aJson : TJSONObject) : TValue;
 var
   ctx : TRttiContext;
   rRec : TRttiRecordType;
@@ -501,7 +505,7 @@ begin
   rProp := rType.GetProperty('List');
   if rProp = nil then Exit;
 
-
+  //check if exists List (denotes delphi json serialized) or not (normal json serialized)
   member := GetJsonPairValueByName(aJson,aName);
   if member = nil then jArray := TJSONObject.ParseJSONValue(aJson.ToJSON) as TJSONArray
     else jArray := TJSONObject.ParseJSONValue(member.ToJSON) as TJSONArray;
@@ -890,9 +894,8 @@ begin
     for i := 0 to aJson.Count - 1 do
     begin
       candidate := aJson.Pairs[I];
-      if candidate.JsonValue = nil then Exit(nil);
-      if CompareText(candidate.JsonString{$IFNDEF FPC}.Value{$ENDIF},aName) = 0 then
-        Exit(candidate.JsonValue);
+      if candidate.JsonValue = nil then continue;
+      if CompareText(candidate.JsonString{$IFNDEF FPC}.Value{$ENDIF},aName) = 0 then Exit(candidate.JsonValue);
     end;
   end;
   Result := nil;
@@ -914,7 +917,7 @@ begin
       for i := 0 to aJson.Count - 1 do
       begin
         Result := aJson.Pairs[I];
-        if Result.JsonValue = nil then Exit(nil);
+        if Result.JsonValue = nil then continue;
         if CompareText(Result.JsonString{$IFNDEF FPC}.Value{$ENDIF},aName) = 0 then Exit;
       end;
     end;
@@ -976,7 +979,7 @@ begin
 end;
 
 {$IFNDEF FPC}
-function TRTTIJson.GetFieldValueFromRecord(aValue : TValue; const FieldName : string) : TValue;
+function TRTTIJson.GetFieldValueFromRecord(const aValue : TValue; const FieldName : string) : TValue;
 var
   ctx : TRttiContext;
   rec : TRttiRecordType;
@@ -1054,7 +1057,7 @@ begin
 end;
 {$ENDIF}
 
-function TRTTIJson.Serialize(aObject: TObject): TJSONObject;
+function TRTTIJson.SerializeObject(aObject: TObject): TJSONObject;
 var
   ctx: TRttiContext;
   {$IFNDEF FPC}
@@ -1076,8 +1079,8 @@ begin
 
   Result := TJSONObject.Create;
   try
+    propertyname := '';
     rType := ctx.GetType(aObject.ClassInfo);
-    //s := rType.ToString;
     for rProp in TRTTI.GetProperties(rType,roFirstBase) do
     begin
       ExcludeSerialize := False;
@@ -1102,33 +1105,32 @@ begin
           {$ENDIF}
           begin
             propvalue := rProp.GetValue(aObject);
+            jpair := TJSONPair.Create(propertyName,nil);
             if (propvalue.IsObject) and (IsGenericList(propvalue.AsObject)) then
             begin
-              jpair := Serialize(propertyname,GetPropertyValueFromObject(propvalue.AsObject,'List'));
+              jpair.JsonValue := SerializeValue(GetPropertyValueFromObject(propvalue.AsObject,'List'));
             end
             {$IFNDEF FPC}
             else if (not propvalue.IsObject) and (IsGenericXArray(propvalue{$IFNDEF NEXTGEN}.TypeInfo.Name{$ELSE}.TypeInfo.NameFld.ToString{$ENDIF})) then
             begin
-              jpair := Serialize(propertyname,GetFieldValueFromRecord(propvalue,'fArray'));
+              jpair.JsonValue := SerializeValue(GetFieldValueFromRecord(propvalue,'fArray'));
             end
             {$ENDIF}
             else
             begin
               {$IFNDEF FPC}
-              jpair := Serialize(propertyname,propvalue);
+              jpair.JsonValue := SerializeValue(propvalue);
               {$ELSE}
-              jpair := Serialize(aObject,rProp.PropertyType.TypeKind,propertyname);
+              jpair.JsonValue := SerializeValue(propvalue);// SerializeObject(aObject,rProp.PropertyType.TypeKind,propertyname);
               {$ENDIF}
             end;
             //s := jpair.JsonValue.ToString;
-            if jpair <> nil then
+            if jpair.JsonValue <> nil then
             begin
               Result.AddPair(jpair);
             end
             else jpair.Free;
           end;
-          //Result.AddPair(Serialize(rProp.Name,rProp.GetValue(aObject)));
-          //s := Result.ToJSON;
         end;
       end;
     end;
@@ -1136,7 +1138,8 @@ begin
     on E : Exception do
     begin
       Result.Free;
-      raise EJsonSerializeError.CreateFmt('Serialize error object "%s" : %s',[aObject.ClassName,e.Message]);
+      if not propertyname.IsEmpty then raise EJsonSerializeError.CreateFmt('Serialize Error -> Object property: "%s" (%s)',[propertyname,e.Message])
+       else raise EJsonSerializeError.CreateFmt('Serialize Error -> Object (%s)',[e.Message]);
     end;
   end;
 end;
@@ -1151,154 +1154,183 @@ begin
   TValue.Make(aAddr,aTypeInfo,Result);
 end;
 
-{$IFNDEF FPC}
-function TRTTIJson.Serialize(const aName : string; aValue : TValue) : TJSONPair;
-var
-  ctx: TRttiContext;
-  rRec : TRttiRecordType;
-  rField : TRttiField;
-  rDynArray : TRTTIDynamicArrayType;
-  json : TJSONObject;
-  jArray : TJSONArray;
-  jPair : TJSONPair;
-  jValue : TJSONValue;
-  i : Integer;
+function TRTTIJson.SerializeValue(const aValue : TValue) : TJSONValue;
 begin
-  Result := TJSONPair.Create(aName,nil);
-  //Result.JsonString := TJSONString(aName);
-  try
-    case avalue.Kind of
-      tkDynArray :
-        begin
-          jArray := TJSONArray.Create;
-          rDynArray := ctx.GetType(aValue.TypeInfo) as TRTTIDynamicArrayType;
-          for i := 0 to aValue.GetArrayLength - 1 do
-          begin
-            if not GetValue(PPByte(aValue.GetReferenceToRawData)^ + rDynArray.ElementType.TypeSize * i, rDynArray.ElementType).IsEmpty then
-            begin
-              jValue := nil;
-              jPair := Serialize(aName,GetValue(PPByte(aValue.GetReferenceToRawData)^ + rDynArray.ElementType.TypeSize * i, rDynArray.ElementType));
-              try
-                //jValue := TJsonValue(jPair.JsonValue.Clone);
-                jValue := jPair.JsonValue;
-                if jValue <> nil then
-                begin
-                  jArray.AddElement(jValue);
-                  jPair.JsonValue.Owned := False;
-                end;
-              finally
-                jPair.Free;
-                if jValue <> nil then jValue.Owned := True;
-              end;
-            end;
-          end;
-          Result.JsonValue := jArray;
-        end;
-      tkClass :
-        begin         
-           Result.JsonValue := TJSONValue(Serialize(aValue.AsObject));
-        end;
-      tkString, tkLString, tkWString, tkUString :
-        begin
-          Result.JsonValue := TJSONString.Create(aValue.AsString);
-        end;
-      tkChar, tkWChar :
-        begin
-          Result.JsonValue := TJSONString.Create(aValue.AsString);
-        end;
-      tkInteger :
+  Result := nil;
+  case avalue.Kind of
+    tkDynArray :
+      begin
+        {$IFNDEF FPC}
+        Result := SerializeDynArray(aValue);
+        {$ENDIF}
+      end;
+    tkClass :
+      begin
+         Result := TJSONValue(SerializeObject(aValue.AsObject));
+      end;
+    tkString, tkLString, tkWString, tkUString :
+      begin
+        Result := TJSONString.Create(aValue.AsString);
+      end;
+    tkChar, tkWChar :
+      begin
+        Result := TJSONString.Create(aValue.AsString);
+      end;
+    tkInteger :
+      begin
+        Result := TJSONNumber.Create(aValue.AsInteger);
+      end;
+    tkInt64 :
+      begin
+        Result := TJSONNumber.Create(aValue.AsInt64);
+      end;
+    tkFloat :
+      begin
+        if aValue.TypeInfo = TypeInfo(TDateTime) then
         begin
-          Result.JsonValue := TJSONNumber.Create(aValue.AsInteger);
-        end;
-      tkInt64 :
+          if aValue.AsExtended <> 0.0 then Result := TJSONString.Create(DateTimeToJsonDate(aValue.AsExtended));
+        end
+        else if aValue.TypeInfo = TypeInfo(TDate) then
         begin
-          Result.JsonValue := TJSONNumber.Create(aValue.AsInt64);
-        end;
-      tkFloat :
+          if aValue.AsExtended <> 0.0 then Result := TJSONString.Create(DateToStr(aValue.AsExtended));
+        end
+        else if aValue.TypeInfo = TypeInfo(TTime) then
         begin
-          if aValue.TypeInfo = TypeInfo(TDateTime) then
-          begin
-            if aValue.AsExtended <> 0.0 then Result.JsonValue := TJSONString.Create(DateTimeToJsonDate(aValue.AsExtended));
-          end
-          else if aValue.TypeInfo = TypeInfo(TDate) then
-          begin
-            if aValue.AsExtended <> 0.0 then Result.JsonValue := TJSONString.Create(DateToStr(aValue.AsExtended));
-          end
-          else if aValue.TypeInfo = TypeInfo(TTime) then
-          begin
-            Result.JsonValue := TJSONString.Create(TimeToStr(aValue.AsExtended));
-          end
-          else
-          begin
-            Result.JsonValue := TJSONNumber.Create(aValue.AsExtended);
-          end;
-        end;
-      tkEnumeration :
+          Result := TJSONString.Create(TimeToStr(aValue.AsExtended));
+        end
+        else
         begin
-          if (aValue.TypeInfo = System.TypeInfo(Boolean)) then
-          begin
-            {$IFDEF DELPHIRX10_UP}
-            Result.JsonValue := TJSONBool.Create(aValue.AsBoolean);
-            {$ELSE}
-            if aValue.AsBoolean then Result.JsonValue := TJsonTrue.Create
-              else Result.JsonValue := TJsonFalse.Create;
-            {$ENDIF}
-          end
-          else
-          begin
-            //Result.JsonValue := TJSONString.Create(GetEnumName(aValue.TypeInfo,aValue.AsOrdinal));
-            if fUseEnumNames then Result.JsonValue := TJSONString.Create(aValue.ToString)
-              else Result.JsonValue := TJSONNumber.Create(GetEnumValue(aValue.TypeInfo,aValue.ToString));
-          end;
+          Result := TJSONNumber.Create(aValue.AsExtended);
         end;
-      tkSet :
+      end;
+    tkEnumeration :
+      begin
+        if (aValue.TypeInfo = System.TypeInfo(Boolean)) then
         begin
-          Result.JsonValue := TJSONString.Create(aValue.ToString);
-        end;
-      tkRecord :
+          {$IF Defined(DELPHIRX10_UP) OR Defined(FPC)}
+          Result := TJSONBool.Create(aValue.AsBoolean);
+          {$ELSE}
+          if aValue.AsBoolean then Result := TJsonTrue.Create
+            else Result := TJsonFalse.Create;
+          {$ENDIF}
+        end
+        else
         begin
-          rRec := ctx.GetType(aValue.TypeInfo).AsRecord;
-          if aValue.TypeInfo = System.TypeInfo(TGUID) then
-          begin
-            Result.JsonValue := TJSONString.Create(GUIDToString(aValue.AsType<TGUID>));
-          end
-          else
-          begin
-            json := TJSONObject.Create;
-            for rField in rRec.GetFields do
-            begin
-              json.AddPair(Serialize(rField.name,rField.GetValue(aValue.GetReferenceToRawData)));
-            end;
-            Result.JsonValue := json;
-          end;
+          //Result.JsonValue := TJSONString.Create(GetEnumName(aValue.TypeInfo,aValue.AsOrdinal));
+          if fUseEnumNames then Result := TJSONString.Create(aValue.ToString)
+            else Result := TJSONNumber.Create(GetEnumValue(aValue.TypeInfo,aValue.ToString));
         end;
-      tkVariant :
-        begin
-          case VarType(aValue.AsVariant) and VarTypeMask of
-            varInteger, varInt64 : Result.JsonValue := TJSONNumber.Create(aValue.AsInteger);
-            varString, varUString, varEmpty : Result.JsonValue := TJSONString.Create(aValue.AsString);
-            varDouble : Result.JsonValue := TJSONNumber.Create(aValue.AsExtended);
-          end;
+      end;
+    {$IFDEF FPC}
+    tkBool :
+      begin
+        Result := TJSONBool.Create(aValue.AsBoolean);
+      end;
+    {$ENDIF}
+    tkSet :
+      begin
+        Result := TJSONString.Create(aValue.ToString);
+      end;
+    tkRecord :
+      begin
+        {$IFNDEF FPC}
+        Result := SerializeRecord(aValue);
+        {$ENDIF}
+      end;
+    tkVariant :
+      begin
+        {$IFNDEF FPC}
+        case VarType(aValue.AsVariant) and VarTypeMask of
+          varInteger, varInt64 : Result := TJSONNumber.Create(aValue.AsInteger);
+          varString, varUString, varEmpty : Result := TJSONString.Create(aValue.AsString);
+          varDouble : Result := TJSONNumber.Create(aValue.AsExtended);
         end;
-      tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
-        begin
-          //skip these properties
-          //FreeAndNil(Result);
-        end
+        {$ENDIF}
+      end;
+    tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure, tkUnknown :
+      begin
+        //skip these properties
+      end
+  else
+    begin
+      {$IFNDEF FPC}
+      raise EJsonSerializeError.CreateFmt(cNotSupportedDataType,[GetTypeName(aValue.TypeInfo)]);
+      {$ELSE}
+      raise EJsonSerializeError.Create('Not supported Data Type');
+      {$ENDIF}
+    end;
+  end;
+  if Result = nil then Result := TJSONNull.Create;
+end;
+
+{$IFNDEF FPC}
+function TRTTIJson.SerializeDynArray(const aValue: TValue) : TJsonArray;
+var
+  ctx : TRttiContext;
+  rDynArray : TRTTIDynamicArrayType;
+  i : Integer;
+  jValue : TJSONValue;
+  element : Integer;
+  list : TList<TJSONValue>;
+begin
+  element := -1;
+  Result := TJSONArray.Create;
+  try
+    rDynArray := ctx.GetType(aValue.TypeInfo) as TRTTIDynamicArrayType;
+    list := TList<TJSONValue>.Create;
+    list.Capacity := aValue.GetArrayLength;
+    for i := 0 to aValue.GetArrayLength - 1 do
+    begin
+      if not GetValue(PPByte(aValue.GetReferenceToRawData)^ + rDynArray.ElementType.TypeSize * i, rDynArray.ElementType).IsEmpty then
+      begin
+        element := i;
+        jValue := SerializeValue(GetValue(PPByte(aValue.GetReferenceToRawData)^ + rDynArray.ElementType.TypeSize * i, rDynArray.ElementType));
+        if jValue = nil then jValue := TJSONNull.Create;
+        list.Add(jValue);
+      end;
+    end;
+    Result.SetElements(list);
+  except
+    on E : Exception do
+    begin
+      if element > -1 then raise EJsonSerializeError.CreateFmt('Serialize Error -> Array[%d] (%s)',[element,e.Message])
+       else raise EJsonSerializeError.CreateFmt('Serialize Error -> Array (%s)',[e.Message]);
+    end;
+  end;
+end;
+
+function TRTTIJson.SerializeRecord(const aValue : TValue) : TJSONValue;
+var
+  ctx : TRttiContext;
+  json : TJSONObject;
+  rRec : TRttiRecordType;
+  rField : TRttiField;
+begin
+  rField := nil;
+  try
+    rRec := ctx.GetType(aValue.TypeInfo).AsRecord;
+    if aValue.TypeInfo = System.TypeInfo(TGUID) then
+    begin
+      Result := TJSONString.Create(GUIDToString(aValue.AsType<TGUID>));
+    end
     else
+    begin
+      json := TJSONObject.Create;
+      for rField in rRec.GetFields do
       begin
-        raise EJsonSerializeError.CreateFmt(cNotSupportedDataType,[aName,GetTypeName(aValue.TypeInfo)]);
+        json.AddPair(rField.Name,SerializeValue(rField.GetValue(aValue.GetReferenceToRawData)));
       end;
+      Result := json;
     end;
-    if Result.JsonValue = nil then Result.JsonValue := TJSONNull.Create;
   except
     on E : Exception do
     begin
-      Result.Free;
-      raise EJsonSerializeError.CreateFmt('Serialize error class "%s.%s" : %s',[aName,aValue.ToString,e.Message]);
+      if rField <> nil then raise EJsonSerializeError.CreateFmt('Serialize Error -> Record property "%s" (%s)',[rField.Name,e.Message])
+       else raise EJsonSerializeError.CreateFmt('Serialize Error -> Record (%s)',[e.Message]);
     end;
   end;
 end;
+
 {$ELSE}
 function TRTTIJson.GetPropType(aPropInfo: PPropInfo): PTypeInfo;
 begin
@@ -1317,80 +1349,7 @@ begin
     '.',fsettings.DecimalSeparator,[rfReplaceAll]);
 end;
 
-function TRTTIJson.Serialize(const aName : string; aValue : TValue) : TJSONPair;
-begin
-  Result := TJSONPair.Create(aName,nil);
-  //Result.JsonString := TJSONString(aName);
-  try
-    case avalue.Kind of
-      tkClass :
-        begin
-           Result.JsonValue := TJSONValue(Serialize(aValue.AsObject));
-        end;
-      tkString, tkLString, tkWString, tkUString :
-        begin
-          Result.JsonValue := TJSONString.Create(aValue.AsString);
-        end;
-      tkChar, tkWChar :
-        begin
-          Result.JsonValue := TJSONString.Create(aValue.AsString);
-        end;
-      tkInteger :
-        begin
-          Result.JsonValue := TJSONNumber.Create(aValue.AsInteger);
-        end;
-      tkInt64 :
-        begin
-          Result.JsonValue := TJSONNumber.Create(aValue.AsInt64);
-        end;
-      tkFloat :
-        begin
-          if aValue.TypeInfo = TypeInfo(TDateTime) then
-          begin
-            if aValue.AsExtended <> 0.0 then Result.JsonValue := TJSONString.Create(DateTimeToJsonDate(aValue.AsExtended));
-          end
-          else if aValue.TypeInfo = TypeInfo(TDate) then
-          begin
-            if aValue.AsExtended <> 0.0 then Result.JsonValue := TJSONString.Create(DateToStr(aValue.AsExtended));
-          end
-          else if aValue.TypeInfo = TypeInfo(TTime) then
-          begin
-            Result.JsonValue := TJSONString.Create(TimeToStr(aValue.AsExtended));
-          end
-          else
-          begin
-            Result.JsonValue := TJSONNumber.Create(aValue.AsExtended);
-          end;
-        end;
-      tkEnumeration :
-        begin
-          if (aValue.TypeInfo = System.TypeInfo(Boolean)) then
-          begin
-            Result.JsonValue := TJSONBool.Create(aValue.AsBoolean);
-          end
-          else
-          begin
-            //Result.JsonValue := TJSONString.Create(GetEnumName(aValue.TypeInfo,aValue.AsOrdinal));
-            if fUseEnumNames then Result.JsonValue := TJSONString.Create(aValue.ToString)
-              else Result.JsonValue := TJSONNumber.Create(GetEnumValue(aValue.TypeInfo,aValue.ToString));
-          end;
-        end;
-      tkSet :
-        begin
-          Result.JsonValue := TJSONString.Create(aValue.ToString);
-        end;
-    else
-      begin
-        //raise EJsonDeserializeError.CreateFmt('Not supported type "%s":%d',[aName,Integer(aValue.Kind)]);
-      end;
-    end;
-    if Result.JsonValue = nil then Result.JsonValue := TJSONNull.Create;
-  except
-    Result.Free;
-  end;
-end;
-
-function TRTTIJson.Serialize(aObject : TObject; aType : TTypeKind; const aPropertyName : string) : TJSONPair;
+function TRTTIJson.SerializeObject(aObject : TObject; aType : TTypeKind; const aPropertyName : string) : TJSONPair;
 var
   propinfo : PPropInfo;
   jArray : TJsonArray;
@@ -1421,16 +1380,8 @@ begin
               for i := 0 to len - 1 do
               begin
                 rItemValue := rValue.GetArrayElement(i);
-                jPair := Serialize(aPropertyName,rItemValue);
-                try
-                  //jValue := TJsonValue(jPair.JsonValue.Clone);
-                  jValue := jPair.JsonValue;
-                  jArray.Add(jValue);
-                  //jPair.JsonValue.Owned := False;
-                finally
-                  jPair.Free;
-                  //jValue.Owned := True;
-                end;
+                jValue := SerializeValue(rItemValue);
+                jArray.Add(jValue);
               end;
             end;
             Result.JsonValue := jArray;
@@ -1441,7 +1392,7 @@ begin
         end;
       tkClass :
         begin
-          Result.JsonValue := TJSONValue(Serialize(GetObjectProp(aObject,aPropertyName)));
+          Result.JsonValue := TJSONValue(SerializeObject(GetObjectProp(aObject,aPropertyName)));
         end;
       tkString, tkLString, tkWString, tkUString, tkAString :
         begin
@@ -1463,11 +1414,11 @@ begin
         begin
           if propinfo.PropType = TypeInfo(TDateTime) then
           begin
-            if aValue.AsExtended <> 0.0 then Result.JsonValue := TJSONString.Create(DateTimeToJsonDate(GetFloatProp(aObject,aPropertyName)));
+            Result.JsonValue := TJSONString.Create(DateTimeToJsonDate(GetFloatProp(aObject,aPropertyName)));
           end
           else if propinfo.PropType = TypeInfo(TDate) then
           begin
-            if aValue.AsExtended <> 0.0 then Result.JsonValue := TJSONString.Create(DateToStr(GetFloatProp(aObject,aPropertyName)));
+            Result.JsonValue := TJSONString.Create(DateToStr(GetFloatProp(aObject,aPropertyName)));
           end
           else if propinfo.PropType = TypeInfo(TTime) then
           begin
@@ -1499,13 +1450,7 @@ begin
       {$IFNDEF FPC}
       tkRecord :
         begin
-          rRec := ctx.GetType(aValue.TypeInfo).AsRecord;
-          json := TJSONObject.Create;
-          for rField in rRec.GetFields do
-          begin
-            json.AddPair(Serialize(rField.name,rField.GetValue(aValue.GetReferenceToRawData)));
-          end;
-          Result.JsonValue := json;
+          Result.JsonValue := SerializeRecord(aValue);
         end;
       {$ENDIF}
       tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
@@ -1557,15 +1502,19 @@ function TJsonSerializer.JsonToObject(aType: TClass; const aJson: string): TObje
 var
   json: TJSONObject;
 begin
-  {$IFDEF DELPHIRX10_UP}
-  json := TJSONObject.ParseJSONValue(aJson,True) as TJSONObject;
-  {$ELSE}
-   {$IFDEF FPC}
-   json := TJSONObject(TJSONObject.ParseJSONValue(aJson,True));
-   {$ELSE}
-   json := TJsonObject.ParseJSONValue(TEncoding.UTF8.GetBytes(aJson),0,True) as TJSONObject;
-   {$ENDIF}
-  {$ENDIF}
+  try
+    {$IFDEF DELPHIRX10_UP}
+    json := TJSONObject.ParseJSONValue(aJson,True) as TJSONObject;
+    {$ELSE}
+     {$IFDEF FPC}
+     json := TJSONObject(TJSONObject.ParseJSONValue(aJson,True));
+     {$ELSE}
+     json := TJsonObject.ParseJSONValue(TEncoding.UTF8.GetBytes(aJson),0,True) as TJSONObject;
+     {$ENDIF}
+    {$ENDIF}
+  except
+    raise EJsonDeserializeError.Create(cNotValidJson);
+  end;
   try
     Result := fRTTIJson.DeserializeClass(aType,json);
   finally
@@ -1577,15 +1526,19 @@ function TJsonSerializer.JsonToObject(aObject: TObject; const aJson: string): TO
 var
   json: TJSONObject;
 begin;
-  {$IFDEF DELPHIRX10_UP}
-  json := TJSONObject.ParseJSONValue(aJson,True) as TJSONObject;
-  {$ELSE}
-   {$IFDEF FPC}
-   json := TJSONObject(TJSONObject.ParseJSONValue(aJson,True));
-   {$ELSE}
-   json := TJsonObject.ParseJSONValue(TEncoding.UTF8.GetBytes(aJson),0,True) as TJSONObject;
-   {$ENDIF}
-  {$ENDIF}
+  try
+    {$IFDEF DELPHIRX10_UP}
+    json := TJSONObject.ParseJSONValue(aJson,True) as TJSONObject;
+    {$ELSE}
+     {$IFDEF FPC}
+     json := TJSONObject(TJSONObject.ParseJSONValue(aJson,True));
+     {$ELSE}
+     json := TJsonObject.ParseJSONValue(TEncoding.UTF8.GetBytes(aJson),0,True) as TJSONObject;
+     {$ENDIF}
+    {$ENDIF}
+  except
+    raise EJsonDeserializeError.Create(cNotValidJson);
+  end;
   try
     Result := fRTTIJson.DeserializeObject(aObject,json);
   finally
@@ -1597,7 +1550,7 @@ function TJsonSerializer.ObjectToJson(aObject : TObject; aIndent : Boolean = Fal
 var
   json: TJSONObject;
 begin
-  json := fRTTIJson.Serialize(aObject);
+  json := fRTTIJson.SerializeObject(aObject);
   try
     if aIndent then Result := TJsonUtils.JsonFormat(json.ToJSON)
       else Result := json.ToJSON;
@@ -1610,7 +1563,7 @@ function TJsonSerializer.ObjectToJsonString(aObject : TObject; aIndent : Boolean
 var
   json: TJSONObject;
 begin
-  json := fRTTIJson.Serialize(aObject);
+  json := fRTTIJson.SerializeObject(aObject);
   try
     if aIndent then Result := TJsonUtils.JsonFormat(json.ToString)
       else  Result := json.ToString;
@@ -1619,38 +1572,29 @@ begin
   end;
 end;
 
-{$IFNDEF FPC}
-function TJsonSerializer.ValueToJson(aValue: TValue; aIndent: Boolean): string;
+function TJsonSerializer.ValueToJson(const aValue: TValue; aIndent: Boolean): string;
 var
-  json: TJSONObject;
+  json: TJSONValue;
 begin
-  json := TJSONObject.Create.AddPair(fRTTIJson.Serialize('value',aValue));
+  json:= fRTTIJson.SerializeValue(aValue);
+  if json = nil then raise EJsonSerializerError.Create('Error serializing TValue');
   try
-    {$IFDEF DELPHI103_UP}
-    if aIndent then Result := TJsonUtils.JsonFormat(json.P['value'].ToJSON)
-      else Result := json.P['value'].ToJSON;
-    {$ELSE}
-    if aIndent then Result := TJsonUtils.JsonFormat(json.GetValue('value').ToJSON)
-      else Result := json.GetValue('value').ToJSON;
-    {$ENDIF}
+    if aIndent then Result := TJsonUtils.JsonFormat(json{$IFNDEF FPC}.ToJSON{$ELSE}.AsJson{$ENDIF})
+      else Result := json{$IFNDEF FPC}.ToJSON{$ELSE}.AsJson{$ENDIF};
   finally
     json.Free;
   end;
 end;
 
-function TJsonSerializer.ValueToJsonString(aValue: TValue; aIndent: Boolean): string;
+function TJsonSerializer.ValueToJsonString(const aValue: TValue; aIndent: Boolean): string;
 var
-  json: TJSONObject;
+  json: TJSONValue;
 begin
-  json := TJSONObject.Create.AddPair(fRTTIJson.Serialize('value',aValue));
+  json:= fRTTIJson.SerializeValue(aValue);
+  if json = nil then raise EJsonSerializerError.Create('Error serializing TValue');
   try
-    {$IFDEF DELPHI103_UP}
-    if aIndent then Result := TJsonUtils.JsonFormat(json.P['value'].ToJSON)
-      else Result := json.P['value'].ToJSON;
-    {$ELSE}
-    if aIndent then Result := TJsonUtils.JsonFormat(json.GetValue('value').ToJSON)
-      else Result := json.GetValue('value').ToJSON;
-    {$ENDIF}
+    if aIndent then Result := TJsonUtils.JsonFormat(json.ToString)
+      else Result := json.ToString;
   finally
     json.Free;
   end;
@@ -1658,17 +1602,13 @@ end;
 
 function TJsonSerializer.ArrayToJson<T>(aArray: TArray<T>; aIndent: Boolean): string;
 var
-  json: TJSONObject;
+  json: TJSONValue;
 begin
-  json := TJSONObject.Create.AddPair(fRTTIJson.Serialize('array',TValue.From<TArray<T>>(aArray)));
+  json:= fRTTIJson.SerializeValue(TValue.From<TArray<T>>(aArray));
+  if json = nil then raise EJsonSerializerError.Create('Error serializing Array');
   try
-    {$IFDEF DELPHI103_UP}
-    if aIndent then Result := TJsonUtils.JsonFormat(json.P['array'].ToJSON)
-      else Result := json.P['array'].ToJSON;
-    {$ELSE}
-    if aIndent then Result := TJsonUtils.JsonFormat(json.GetValue('array').ToJSON)
-      else Result := json.GetValue('array').ToJSON;
-    {$ENDIF}
+    if aIndent then Result := TJsonUtils.JsonFormat(json{$IFNDEF FPC}.ToJSON{$ELSE}.AsJson{$ENDIF})
+      else Result := json{$IFNDEF FPC}.ToJSON{$ELSE}.AsJson{$ENDIF};
   finally
     json.Free;
   end;
@@ -1676,32 +1616,33 @@ end;
 
 function TJsonSerializer.ArrayToJsonString<T>(aArray: TArray<T>; aIndent: Boolean): string;
 var
-  json: TJSONObject;
+  json: TJSONValue;
 begin
-  json := TJSONObject.Create.AddPair(fRTTIJson.Serialize('array',TValue.From<TArray<T>>(aArray)));
+  json:= fRTTIJson.SerializeValue(TValue.From<TArray<T>>(aArray));
+  if json = nil then raise EJsonSerializerError.Create('Error serializing Array');
   try
-    {$IFDEF DELPHI103_UP}
-    if aIndent then Result := TJsonUtils.JsonFormat(json.P['array'].ToJSON)
-      else Result := json.P['array'].ToJSON;
-    {$ELSE}
-    if aIndent then Result := TJsonUtils.JsonFormat(json.GetValue('array').ToJSON)
-      else Result := json.GetValue('array').ToJSON;
-    {$ENDIF}
+    if aIndent then Result := TJsonUtils.JsonFormat(json.ToString)
+      else Result := json.ToString;
   finally
     json.Free;
   end;
 end;
 
+{$IFNDEF FPC}
 function TJsonSerializer.JsonToArray<T>(const aJson: string): TArray<T>;
 var
   jarray: TJSONArray;
   value : TValue;
 begin;
-  {$If Defined(FPC) OR Defined(DELPHIRX10_UP)}
-  jarray := TJSONObject.ParseJSONValue(aJson,True) as TJSONArray;
-  {$ELSE}
-  jarray := TJsonObject.ParseJSONValue(TEncoding.UTF8.GetBytes(aJson),0,True) as TJSONArray;
+  try
+    {$If Defined(FPC) OR Defined(DELPHIRX10_UP)}
+    jarray := TJSONObject.ParseJSONValue(aJson,True) as TJSONArray;
+    {$ELSE}
+    jarray := TJsonObject.ParseJSONValue(TEncoding.UTF8.GetBytes(aJson),0,True) as TJSONArray;
   {$ENDIF}
+  except
+    raise EJsonDeserializeError.Create(cNotValidJson);
+  end;
   try
     value := fRTTIJson.DeserializeDynArray(PTypeInfo(TypeInfo(TArray<T>)),nil,jarray);
     Result := value.AsType<TArray<T>>;
@@ -1709,58 +1650,24 @@ begin;
     jarray.Free;
   end;
 end;
-{$ELSE}
-function TJsonSerializer.ValueToJson(aValue: TValue; aIndent: Boolean): string;
-var
-  json: TJSONObject;
-begin
-  json := TJSONObject.Create;
-  json.AddPair(fRTTIJson.Serialize('value',aValue));
-  try
-    if aIndent then Result := TJsonUtils.JsonFormat(json.Get('value').ToJSON)
-      else Result := json.Get('value').ToJSON;
-  finally
-    json.Free;
-  end;
-end;
 
-function TJsonSerializer.ValueToJsonString(aValue: TValue; aIndent: Boolean): string;
+function TJsonSerializer.JsonToValue(const aJson: string): TValue;
 var
   json: TJSONObject;
-begin
-  json := TJSONObject.Create;
-  json.AddPair(fRTTIJson.Serialize('value',aValue));
-  try
-    if aIndent then Result := TJsonUtils.JsonFormat(json.Get('value').ToString)
-      else  Result := json.Get('value').ToString;
-  finally
-    json.Free;
-  end;
-end;
-
-function TJsonSerializer.ArrayToJson<T>(aArray: TArray<T>; aIndent: Boolean): string;
-var
-  json: TJSONObject;
-begin
-  json := TJSONObject.Create;
-  json.AddPair(fRTTIJson.Serialize('array',TValue.From<TArray<T>>(aArray)));
+  value : TValue;
+begin;
   try
-    if aIndent then Result := TJsonUtils.JsonFormat(json.Get('array').ToJSON)
-      else Result := json.Get('array').ToJSON;
-  finally
-    json.Free;
+    {$If Defined(FPC) OR Defined(DELPHIRX10_UP)}
+    json := TJSONObject.ParseJSONValue(aJson,True) as TJSONObject;
+    {$ELSE}
+    json := TJsonObject.ParseJSONValue(TEncoding.UTF8.GetBytes(aJson),0,True) as TJSONObject;
+    {$ENDIF}
+  except
+    raise EJsonDeserializeError.Create(cNotValidJson);
   end;
-end;
-
-function TJsonSerializer.ArrayToJsonString<T>(aArray: TArray<T>; aIndent: Boolean): string;
-var
-  json: TJSONObject;
-begin
-  json := TJSONObject.Create;
-  json.AddPair(fRTTIJson.Serialize('array',TValue.From<TArray<T>>(aArray)));
   try
-    if aIndent then Result := TJsonUtils.JsonFormat(json.Get('array').ToString)
-      else Result := json.Get('array').ToString;
+    value := fRTTIJson.DeserializeRecord(value,nil,json);
+    Result := value; // value.AsType<TArray<T>>;
   finally
     json.Free;
   end;