Browse Source

Merge pull request #92 from vldgeorgiev/master

Update the YAML serializer to handle nested object deserialization
Exilon 3 years ago
parent
commit
b0650a0155
1 changed files with 1629 additions and 1584 deletions
  1. 1629 1584
      Quick.YAML.Serializer.pas

+ 1629 - 1584
Quick.YAML.Serializer.pas

@@ -1,1584 +1,1629 @@
-{ ***************************************************************************
-
-  Copyright (c) 2015-2021 Kike Pérez
-
-  Unit        : Quick.YAML.Serializer
-  Description : YAML Serializer
-  Author      : Kike Pérez
-  Version     : 1.0
-  Created     : 12/04/2019
-  Modified    : 05/08/2021
-
-  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.YAML.Serializer;
-
-{$i QuickLib.inc}
-
-interface
-
-uses
-  Classes,
-  SysUtils,
-  Rtti,
-  TypInfo,
-  {$IFDEF FPC}
-   rttiutils,
-   strUtils,
-   Generics.Collections,
-  {$ELSE}
-    {$IFDEF DELPHIRX10_UP}
-    System.Generics.Collections,
-    {$ENDIF}
-  {$ENDIF}
-  DateUtils,
-  Quick.Commons,
-  Quick.RTTI.Utils,
-  Quick.YAML,
-  Quick.Value,
-  Quick.Arrays;
-
-type
-
-  EYamlSerializeError = class(Exception);
-  EYamlDeserializeError = class(Exception);
-
-  {$IFNDEF FPC}
-  TNotSerializableProperty = class(TCustomAttribute);
-
-  TCommentProperty = class(TCustomAttribute)
-  private
-    fComment : string;
-  public
-    constructor Create(const aComment: string);
-    property Comment : string read fComment;
-  end;
-
-  TCustomNameProperty = class(TCustomAttribute)
-  private
-    fName : string;
-  public
-    constructor Create(const aName: string);
-    property Name : string read fName;
-  end;
-  {$ENDIF}
-
-  IYamlSerializer = interface
-  ['{CA26F7AE-F1FE-41BE-9C23-723A687F60D1}']
-    function YamlToObject(aType: TClass; const aYaml: string): TObject; overload;
-    function YamlToObject(aObject: TObject; const aYaml: string): TObject; overload;
-    function ObjectToYaml(aObject : TObject): string;
-  end;
-
-  TSerializeLevel = (slPublicProperty, slPublishedProperty);
-
-  TRTTIYaml = class
-  private
-    fSerializeLevel : TSerializeLevel;
-    fUseEnumNames : Boolean;
-    fUseYamlCaseSense : Boolean;
-    function GetValue(aAddr: Pointer; aType: TRTTIType): TValue; overload;
-    function GetValue(aAddr: Pointer; aTypeInfo: PTypeInfo): TValue; overload;
-    function IsAllowedProperty(aObject : TObject; const aPropertyName : string) : Boolean;
-    function IsGenericList(aObject : TObject) : Boolean;
-    function IsGenericXArray(const aClassName : string) : Boolean;
-    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;
-    {$ENDIF}
-    procedure SetPropertyValue(Instance : TObject; aPropInfo : PPropInfo; aValue : TValue); overload;
-    procedure SetPropertyValue(Instance : TObject; const PropertyName : string; aValue : TValue); overload;
-    {$IFDEF FPC}
-    function FloatProperty(aObject : TObject; aPropInfo: PPropInfo): string;
-    function GetPropType(aPropInfo: PPropInfo): PTypeInfo;
-    procedure LoadSetProperty(aInstance : TObject; aPropInfo: PPropInfo; const aValue: string);
-    {$ENDIF}
-  public
-    constructor Create(aSerializeLevel : TSerializeLevel; aUseEnumNames : Boolean = True);
-    property UseEnumNames : Boolean read fUseEnumNames write fUseEnumNames;
-    property UseYamlCaseSense : Boolean read fUseYamlCaseSense write fUseYamlCaseSense;
-    {$IFNDEF FPC}
-    function DeserializeDynArray(aTypeInfo : PTypeInfo; aObject : TObject; const aYamlArray: TYamlArray) : TValue;
-    function DeserializeRecord(aRecord : TValue; aObject : TObject; const aYaml : TYamlObject) : TValue;
-    {$ELSE}
-    procedure DeserializeDynArray(aTypeInfo: PTypeInfo; const aPropertyName : string; aObject: TObject; const aYamlArray: TYamlArray);
-    {$ENDIF}
-    function DeserializeClass(aType : TClass; const aYaml : TYamlObject) : TObject;
-    function DeserializeObject(aObject : TObject; const aYaml : TYamlObject) : TObject; overload;
-    {$IFNDEF FPC}
-    function DeserializeList(aObject: TObject; const aName : string; const aYaml: TYamlObject) : TObject;
-    procedure DeserializeXArray(Instance : TObject; aRecord : TValue; aProperty : TRttiProperty; const aPropertyName : string; aYaml : TYamlObject);
-    {$ENDIF}
-    function DeserializeProperty(aObject : TObject; const aName : string; aProperty : TRttiProperty; const aYaml : TYamlObject) : TObject; overload;
-    {$IFNDEF FPC}
-    function DeserializeType(aObject : TObject; aType : TTypeKind; aTypeInfo : PTypeInfo; const aValue: string) : TValue;
-    {$ELSE}
-    function DeserializeType(aObject : TObject; aType : TTypeKind; const aPropertyName, aValue: string) : TValue;
-    {$ENDIF}
-    {$IFNDEF FPC}
-    function Serialize(const aName : string; aValue : TValue) : TYamlPair; overload;
-    {$ELSE}
-    function Serialize(aObject : TObject; aType : TTypeKind; const aPropertyName : string) : TYamlPair;
-    function Serialize(const aName : string; aValue : TValue) : TYamlPair;
-    {$ENDIF}
-    function Serialize(aObject : TObject) : TYamlObject; overload;
-    function GetYamlPairByName(aYaml : TYamlObject; const aName : string) : TYamlPair;
-  end;
-
-  TYamlSerializer = class(TInterfacedObject,IYamlSerializer)
-  strict private
-    fSerializeLevel : TSerializeLevel;
-    fUseEnumNames : Boolean;
-    fUseYamlCaseSense : Boolean;
-    fRTTIYaml : TRTTIYaml;
-  private
-    procedure SetUseEnumNames(const Value: Boolean);
-    procedure SetUseYamlCaseSense(const Value: Boolean);
-    procedure SetSerializeLevel(const Value: TSerializeLevel);
-  public
-    constructor Create(aSerializeLevel: TSerializeLevel; aUseEnumNames : Boolean = True);
-    destructor Destroy; override;
-    property SerializeLevel : TSerializeLevel read fSerializeLevel write SetSerializeLevel;
-    property UseEnumNames : Boolean read fUseEnumNames write SetUseEnumNames;
-    property UseYamlCaseSense : Boolean read fUseYamlCaseSense write SetUseYamlCaseSense;
-    function YamlToObject(aType : TClass; const aYaml: string) : TObject; overload;
-    function YamlToObject(aObject : TObject; const aYaml: string) : TObject; overload;
-    function ObjectToYaml(aObject : TObject): string;
-  end;
-
-  PPByte = ^PByte;
-
-resourcestring
-  cNotSupportedDataType = 'Not supported "%s" data type "%s"';
-  cNotSerializable = 'Object is not serializable';
-
-implementation
-
-{ TRTTIYaml }
-
-{$IFNDEF FPC}
-function TRTTIYaml.DeserializeDynArray(aTypeInfo: PTypeInfo; aObject: TObject; const aYamlArray: TYamlArray) : TValue;
-var
-  rType: PTypeInfo;
-  len: NativeInt;
-  pArr: Pointer;
-  rItemValue: TValue;
-  i: Integer;
-  objClass: TClass;
-  ctx : TRttiContext;
-  Yaml : TYamlObject;
-  rDynArray : TRttiDynamicArrayType;
-  propObj : TObject;
-begin
-  if GetTypeData(aTypeInfo).DynArrElType = nil then Exit;
-  if not assigned(aYamlArray) then Exit;
-
-  len := aYamlArray.Count;
-  rType := GetTypeData(aTypeInfo).DynArrElType^;
-  pArr := nil;
-  DynArraySetLength(pArr,aTypeInfo, 1, @len);
-  try
-    TValue.Make(@pArr,aTypeInfo, Result);
-    rDynArray := ctx.GetType(Result.TypeInfo) as TRTTIDynamicArrayType;
-
-    for i := 0 to aYamlArray.Count - 1 do
-    begin
-      rItemValue := nil;
-      case rType.Kind of
-        tkClass :
-          begin
-            if TYamlPair(aYamlArray.Items[i]).Value is TYamlObject then
-            begin
-              Yaml := TYamlObject(TYamlPair(aYamlArray.Items[i]).value);
-              propObj := GetValue(PPByte(Result.GetReferenceToRawData)^ +rDynArray.ElementType.TypeSize * i, rDynArray.ElementType).AsObject;
-              if propObj = nil then
-              begin
-                objClass := rType.TypeData.ClassType;
-                rItemValue := DeserializeClass(objClass,yaml);
-              end
-              else
-              begin
-                DeserializeObject(propObj,yaml);
-              end;
-            end;
-          end;
-        tkRecord :
-          begin
-            Yaml := TYamlObject(TYamlPair(aYamlArray.Items[i]).value);
-            rItemValue := DeserializeRecord(GetValue(PPByte(Result.GetReferenceToRawData)^ +rDynArray.ElementType.TypeSize * i,
-                                            rDynArray.ElementType),aObject,Yaml);
-          end;
-        tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
-          begin
-            //skip these properties
-          end
-      else
-        begin
-          rItemValue := DeserializeType(aObject,rType.Kind,aTypeInfo,aYamlArray.Items[i].Value);
-        end;
-      end;
-      if not rItemValue.IsEmpty then Result.SetArrayElement(i,rItemValue);
-    end;
-    //aProperty.SetValue(aObject,rValue);
-  finally
-    DynArrayClear(pArr,aTypeInfo);
-  end;
-end;
-{$ELSE}
-procedure TRTTIYaml.DeserializeDynArray(aTypeInfo: PTypeInfo; const aPropertyName : string; aObject: TObject; const aYamlArray: TYamlArray);
-var
-  rType: PTypeInfo;
-  len: NativeInt;
-  pArr: Pointer;
-  rItemValue: TValue;
-  i: Integer;
-  objClass: TClass;
-  propObj : TObject;
-  rValue : TValue;
-  yaml : TYamlObject;
-begin
-  if GetTypeData(aTypeInfo).ElType2 = nil then Exit;
-  len := aYamlArray.Count;
-  rType := GetTypeData(aTypeInfo).ElType2;
-  pArr := nil;
-  DynArraySetLength(pArr,aTypeInfo, 1, @len);
-  try
-    TValue.Make(@pArr,aTypeInfo, rValue);
-    for i := 0 to aYamlArray.Count - 1 do
-    begin
-      rItemValue := nil;
-      case rType.Kind of
-        tkClass :
-          begin
-            if TYamlPair(aYamlArray.Items[i]).Value is TYamlObject then
-            begin
-              Yaml := TYamlObject(TYamlPair(aYamlArray.Items[i]).value);
-              propObj := GetValue(PPByte(rValue.GetReferenceToRawData)^ +GetTypeData(aTypeInfo).elSize * i, GetTypeData(aTypeInfo).ElType2).AsObject;
-              if propObj = nil then
-              begin
-                //objClass := GetTypeData(aTypeInfo).ClassType;
-                objClass := GetTypeData(GetTypeData(aTypeInfo).ElType2).ClassType;
-                rItemValue := DeserializeClass(objClass,yaml);
-              end
-              else
-              begin
-                DeserializeObject(propObj,yaml);
-              end;
-            end;
-          end;
-        tkRecord :
-          begin
-            {Yaml := TYamlObject(aYamlArray.Items[i]);
-            rItemValue := DeserializeRecord(GetValue(PPByte(Result.GetReferenceToRawData)^ +rDynArray.ElementType.TypeSize * i,
-                                            rDynArray.ElementType),aObject,Yaml);  }
-          end;
-        tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
-          begin
-            //skip these properties
-          end
-      else
-        begin
-          rItemValue := DeserializeType(aObject,GetTypeData(aTypeInfo).ElType2.Kind,aPropertyName,aYamlArray.Items[i].Value);
-        end;
-      end;
-      if not rItemValue.IsEmpty then rValue.SetArrayElement(i,rItemValue);
-    end;
-    //aProperty.SetValue(aObject,rValue);
-    SetDynArrayProp(aObject,GetPropInfo(aObject,aPropertyName),pArr);
-  finally
-    DynArrayClear(pArr,aTypeInfo);
-  end;
-end;
-{$ENDIF}
-
-{$IFNDEF FPC}
-function TRTTIYaml.DeserializeRecord(aRecord : TValue; aObject : TObject; const aYaml : TYamlObject) : TValue;
-var
-  ctx : TRttiContext;
-  rRec : TRttiRecordType;
-  rField : TRttiField;
-  rValue : TValue;
-  member : TYamlPair;
-  yArray : TYamlArray;
-  Yaml : TYamlObject;
-  objClass : TClass;
-  propobj : TObject;
-begin
-  rRec := ctx.GetType(aRecord.TypeInfo).AsRecord;
-  try
-    for rField in rRec.GetFields do
-    begin
-      rValue := nil;
-      //member := TYamlPair(aYaml.GetValue(rField.Name));
-      member := GetYamlPairByName(aYaml,rField.Name);
-      if member <> nil then
-      case rField.FieldType.TypeKind of
-        tkDynArray :
-          begin
-            yArray := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlArray;
-            try
-              rValue := DeserializeDynArray(rField.FieldType.Handle,aObject,yArray);
-            finally
-              yArray.Free;
-            end;
-          end;
-        tkClass :
-          begin
-            //if (member.YamlValue is TYamlObject) then
-            begin
-              propobj := rField.GetValue(@aRecord).AsObject;
-              Yaml := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlObject;
-              try
-                if propobj = nil then
-                begin
-                  objClass := rField.FieldType.Handle^.TypeData.ClassType;// aProperty.PropertyType.Handle^.TypeData.ClassType;
-                  rValue := DeserializeClass(objClass,Yaml);
-                end
-                else
-                begin
-                  DeserializeObject(propobj,Yaml);
-                end;
-              finally
-                Yaml.Free;
-              end;
-            end
-          end;
-        tkRecord :
-          begin
-            Yaml := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlObject;
-            try
-              rValue := DeserializeRecord(rField.GetValue(aRecord.GetReferenceToRawData),aObject,Yaml);
-            finally
-              Yaml.Free;
-            end;
-          end
-      else
-        begin
-          //rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,member.ToYaml);
-          {$IFNDEF FPC}
-          //avoid return unicode escaped chars if string
-          if rField.FieldType.TypeKind in [tkString, tkLString, tkWString, tkUString] then
-            {$IFDEF DELPHIRX10_UP}
-            rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,member.Value.AsString)
-            {$ELSE}
-            rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,member.YamlString.ToString)
-            {$ENDIF}
-            else rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,member.Value.AsString);
-          {$ELSE}
-          rValue := DeserializeType(aObject,rField.FieldType.TypeKind,aName,member.Value.AsString);
-          {$ENDIF}
-        end;
-      end;
-      if not rValue.IsEmpty then rField.SetValue(aRecord.GetReferenceToRawData,rValue);
-    end;
-    Result := aRecord;
-  finally
-    ctx.Free;
-  end;
-end;
-{$ENDIF}
-
-constructor TRTTIYaml.Create(aSerializeLevel : TSerializeLevel; aUseEnumNames : Boolean = True);
-begin
-  fSerializeLevel := aSerializeLevel;
-  fUseEnumNames := aUseEnumNames;
-  fUseYamlCaseSense := False;
-end;
-
-function TRTTIYaml.DeserializeClass(aType: TClass; const aYaml: TYamlObject): TObject;
-begin
-  Result := nil;
-  if (aYaml = nil) or ((aYaml as TYamlValue) is TYamlNull) or (aYaml.Count = 0) then Exit;
-
-  try
-    Result := aType.Create;
-    Result := DeserializeObject(Result,aYaml);
-  except
-    on E : Exception do
-    begin
-      Result.Free;
-      raise EYamlDeserializeError.CreateFmt('Deserialize error class "%s" : %s',[aType.ClassName,e.Message]);
-    end;
-  end;
-end;
-
-function TRTTIYaml.DeserializeObject(aObject: TObject; const aYaml: TYamlObject): TObject;
-var
-  ctx: TRttiContext;
-  rType: TRttiType;
-  rProp: TRttiProperty;
-  {$IFNDEF FPC}
-  attr: TCustomAttribute;
-  {$ENDIF}
-  propertyname : string;
-begin
-  Result := aObject;
-
-  if (aYaml = nil) or ((aYaml as TYamlValue) is TYamlNull) or (aYaml.Count = 0) or (Result = nil) then Exit;
-
-  try
-    rType := ctx.GetType(aObject.ClassInfo);
-    try
-      for rProp in rType.GetProperties do
-      begin
-        {$IFNDEF FPC}
-        if ((fSerializeLevel = slPublicProperty) and (rProp.PropertyType.IsPublicType))
-            or ((fSerializeLevel = slPublishedProperty) and ((IsPublishedProp(aObject,rProp.Name)) or (rProp.Name = 'List'))) then
-        {$ENDIF}
-        begin
-          if ((rProp.IsWritable) or (rProp.Name = 'List')) and (IsAllowedProperty(aObject,rProp.Name)) then
-          begin
-            propertyname := rProp.Name;
-            {$IFNDEF FPC}
-            for attr in rProp.GetAttributes do if attr is TCustomNameProperty then propertyname := TCustomNameProperty(attr).Name;
-            if rProp.Name = 'List' then
-            begin
-              Result := DeserializeList(Result,propertyname,aYaml);
-            end
-            else if (rProp.GetValue(aObject).IsObject) and (IsGenericList(rProp.GetValue(aObject).AsObject)) then
-            begin
-              DeserializeList(rProp.GetValue(aObject).AsObject,'List',TYamlObject(aYaml.GetValue(propertyname)));
-            end
-            else if (not rProp.GetValue(aObject).IsObject) and (IsGenericXArray(rProp.GetValue(aObject){$IFNDEF NEXTGEN}.TypeInfo.Name{$ELSE}.TypeInfo.NameFld.ToString{$ENDIF})) then
-            begin
-              DeserializeXArray(Result,rProp.GetValue(aObject),rProp,propertyname,aYaml);
-            end
-            else
-            {$ENDIF}
-            Result := DeserializeProperty(Result,propertyname,rProp,aYaml);
-          end;
-        end;
-      end;
-    finally
-      ctx.Free;
-    end;
-  except
-    on E : Exception do
-    begin
-      Result.Free;
-      raise EYamlDeserializeError.CreateFmt('Deserialize error for object "%s" : %s',[aObject.ClassName,e.Message]);
-    end;
-  end;
-end;
-
-{$IFNDEF FPC}
-function TRTTIYaml.DeserializeList(aObject: TObject; const aName : string; const aYaml: TYamlObject) : TObject;
-var
-  ctx : TRttiContext;
-  rType : TRttiType;
-  yArray : TYamlArray;
-  member : TYamlPair;
-  rvalue : TValue;
-  i : Integer;
-  rProp : TRttiProperty;
-  {$IFNDEF DELPHIRX103_UP}
-  rfield : TRttiField;
-  {$ENDIF}
-begin
-  Result := aObject;
-
-  rType := ctx.GetType(aObject.ClassInfo);
-  try
-    rProp := rType.GetProperty('List');
-    if rProp = nil then Exit;
-  finally
-    ctx.Free;
-  end;
-  member := GetYamlPairByName(aYaml,aName);
-  //var a := aYaml.ToYaml;
-  if member = nil then yArray := TYamlArray(aYaml) //TYamlObject.ParseYamlValue(aYaml.ToYaml) as TYamlArray
-    else yArray := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlArray;
-
-  rvalue := DeserializeDynArray(rProp.PropertyType.Handle,Result,yArray);
-
-  if not rValue.IsEmpty then
-  begin
-    {$IFDEF DELPHIRX103_UP}
-    if (TObjectList<TObject>(aObject) <> nil) and (rvalue.IsArray) then
-    begin
-      TObjectList<TObject>(aObject).Clear;
-      TObjectList<TObject>(aObject).Capacity := rvalue.GetArrayLength;
-      for i := 0 to rvalue.GetArrayLength - 1 do
-      begin
-        TObjectList<TObject>(aObject).Add(rvalue.GetArrayElement(i).AsObject);
-      end;
-    end;
-    {$ELSE}
-    for rfield in rType.GetFields do
-    begin
-      if rfield.Name = 'FOwnsObjects' then rfield.SetValue(aObject,True);
-      //if rfield.Name = 'FCount' then rfield.SetValue(aObject,i);
-      if rfield.Name = 'FItems' then
-      begin
-        //if TList(aObject) <> nil then TList(aObject).Clear;
-        //rfield.GetValue(aObject).AsObject.Free;// aValue.GetReferenceToRawData)
-        rfield.SetValue(aObject,rValue);// .SetDynArrayProp(aObject,'fItems',Result);
-        Break;
-      end;
-    end;
-    rProp := rType.GetProperty('Count');
-    rProp.SetValue(aObject,i);
-    {$ENDIF}
-  end;
-end;
-{$ENDIF}
-
-{$IFNDEF FPC}
-procedure TRTTIYaml.DeserializeXArray(Instance : TObject; aRecord : TValue; aProperty : TRttiProperty; const aPropertyName : string; aYaml : TYamlObject);
-var
-  ctx : TRttiContext;
-  rRec : TRttiRecordType;
-  rfield : TRttiField;
-  rValue : TValue;
-  member : TYamlPair;
-  yArray : TYamlArray;
-begin
-  rRec := ctx.GetType(aRecord.TypeInfo).AsRecord;
-  try
-    rfield := rRec.GetField('fArray');
-    if rfield <> nil then
-    begin
-      rValue := nil;
-      //member := TYamlPair(aYaml.GetValue(rField.Name));
-      member := GetYamlPairByName(aYaml,aPropertyName);
-      if (member <> nil) and (rField.FieldType.TypeKind = tkDynArray) then
-      begin
-        yArray := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlArray;
-        try
-          rValue := DeserializeDynArray(rField.FieldType.Handle,nil,yArray);
-        finally
-          yArray.Free;
-        end;
-      end;
-    end;
-    if not rValue.IsEmpty then rField.SetValue(aRecord.GetReferenceToRawData,rValue);
-    aProperty.SetValue(Instance,aRecord);
-  finally
-    ctx.Free;
-  end;
-end;
-{$ENDIF}
-
-function TRTTIYaml.DeserializeProperty(aObject : TObject; const aName : string; aProperty : TRttiProperty; const aYaml : TYamlObject) : TObject;
-var
-  rValue : TValue;
-  member : TYamlPair;
-  objClass: TClass;
-  yArray : TYamlArray;
-  Yaml : TYamlObject;
-begin
-    Result := aObject;
-    rValue := nil;
-    //member := TYamlPair(aYaml.GetValue(aName));
-    member := GetYamlPairByName(aYaml,aName);
-    if member <> nil then
-    begin
-      case aProperty.PropertyType.TypeKind of
-        tkDynArray :
-          begin
-            yArray := member.Value as TYamlArray;
-            {$IFNDEF FPC}
-            aProperty.SetValue(aObject,DeserializeDynArray(aProperty.PropertyType.Handle,Result,yArray));
-            {$ELSE}
-            DeserializeDynArray(aProperty.PropertyType.Handle,aName,Result,yArray);
-            {$ENDIF}
-            Exit;
-          end;
-        tkClass :
-          begin
-            //if (member.YamlValue is TYamlObject) then
-            begin
-              Yaml := TYamlObject(TYamlObject.ParseYamlValue(member.ToYaml));
-              try
-                if aProperty.GetValue(aObject).AsObject = nil then
-                begin
-                  {$IFNDEF FPC}
-                  objClass := aProperty.PropertyType.Handle^.TypeData.ClassType;
-                  rValue := DeserializeClass(objClass,Yaml);
-                  {$ELSE}
-                  objClass := GetObjectPropClass(aObject,aName);
-                  //objClass := GetTypeData(aProperty.PropertyType.Handle)^.ClassType;
-                  rValue := DeserializeClass(objClass,Yaml);
-                  SetObjectProp(aObject,aName,rValue.AsObject);
-                  Exit;
-                  {$ENDIF}
-                end
-                else
-                begin
-                  rValue := DeserializeObject(aProperty.GetValue(aObject).AsObject,Yaml);
-                  Exit;
-                end;
-              finally
-                Yaml.Free;
-              end;
-            end
-          end;
-        {$IFNDEF FPC}
-        tkRecord :
-          begin
-            Yaml := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlObject;
-            try
-              rValue := DeserializeRecord(aProperty.GetValue(aObject),aObject,Yaml);
-            finally
-              Yaml.Free;
-            end;
-          end;
-        tkSet :
-          begin
-            rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,member.ToYaml)
-          end
-        {$ENDIF}
-      else
-        begin
-          {$IFNDEF FPC}
-          //avoid return unicode escaped chars if string
-          if aProperty.PropertyType.TypeKind in [tkString, tkLString, tkWString, tkUString] then
-            {$IFDEF DELPHIRX10_UP}
-            rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,member.Value.AsString)
-            {$ELSE}
-            rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,member.YamlString.ToString)
-            {$ENDIF}
-          else rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,member.Value.AsString);
-          {$ELSE}
-          rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aName,member.Value.AsString);
-          if not rValue.IsEmpty then SetPropertyValue(aObject,aName,rValue);
-          {$ENDIF}
-        end;
-      end;
-      {$IFNDEF FPC}
-      if not rValue.IsEmpty then aProperty.SetValue(Result,rValue);
-      {$ENDIF}
-    end;
-end;
-
-{$IFNDEF FPC}
-function TRTTIYaml.DeserializeType(aObject : TObject; aType : TTypeKind; aTypeInfo : PTypeInfo; const aValue: string) : TValue;
-var
-  i : Integer;
-  value : string;
-  fsettings : TFormatSettings;
-begin
-  try
-    value := AnsiDequotedStr(aValue,'"');
-    case aType of
-      tkString, tkLString, tkWString, tkUString :
-        begin
-          Result := value;
-        end;
-      tkChar, tkWChar :
-        begin
-          Result := value;
-        end;
-      tkInteger :
-        begin
-          Result := StrToInt(value);
-        end;
-      tkInt64 :
-        begin
-          Result := StrToInt64(value);
-        end;
-      tkFloat :
-        begin
-          if aTypeInfo = TypeInfo(TDateTime) then
-          begin
-            if CompareText(value,'null') <> 0 then Result := JsonDateToDateTime(value);
-          end
-          else if aTypeInfo = TypeInfo(TDate) then
-          begin
-            if CompareText(value,'null') <> 0 then Result := StrToDate(value);
-          end
-          else if aTypeInfo = TypeInfo(TTime) then
-          begin
-            Result := StrToTime(value);
-          end
-          else
-          begin
-            fsettings := TFormatSettings.Create;
-            Result := StrToFloat(StringReplace(value,'.',fsettings.DecimalSeparator,[]));
-          end;
-        end;
-      tkEnumeration :
-        begin
-          if aTypeInfo = System.TypeInfo(Boolean) then
-          begin
-            Result := StrToBool(value);
-          end
-          else
-          begin
-            //if fUseEnumNames then TValue.Make(GetEnumValue(aTypeInfo,value),aTypeInfo, Result)
-            //  else TValue.Make(StrToInt(value),aTypeInfo, Result);
-            if not TryStrToInt(value,i) then TValue.Make(GetEnumValue(aTypeInfo,value),aTypeInfo, Result)
-              else TValue.Make(StrToInt(value),aTypeInfo, Result);
-          end;
-        end;
-      tkSet :
-        begin
-          i := StringToSet(aTypeInfo,value);
-          TValue.Make(@i,aTypeInfo,Result);
-        end;
-    else
-        begin
-          //raise EclYamlSerializerError.Create('Not supported data type!');
-        end;
-    end;
-  except
-    on E : Exception do
-    begin
-      raise EYamlDeserializeError.CreateFmt('Deserialize error type "%s.%s" : %s',[aObject.ClassName,GetTypeName(aTypeInfo),e.Message]);
-    end;
-  end;
-end;
-{$ELSE}
-function TRTTIYaml.DeserializeType(aObject : TObject; aType : TTypeKind; const aPropertyName, aValue: string) : TValue;
-var
-  value : string;
-  propinfo : PPropInfo;
-  fsettings : TFormatSettings;
-begin
-  try
-    value := AnsiDequotedStr(aValue,'"');
-
-    if value = '' then
-    begin
-      Result := nil;
-      Exit;
-    end;
-    propinfo := GetPropInfo(aObject,aPropertyName);
-    //case propinfo.PropType.Kind of
-    case aType of
-      tkString, tkLString, tkWString, tkUString, tkAString :
-        begin
-          Result := value;
-          //SetStrProp(aObject,propinfo,value);
-        end;
-      tkChar, tkWChar :
-        begin
-          Result := value;
-        end;
-      tkInteger :
-        begin
-          Result := StrToInt(value);
-        end;
-      tkInt64 :
-        begin
-          Result := StrToInt64(value);
-        end;
-      tkFloat :
-        begin
-          if propinfo.PropType = TypeInfo(TDateTime) then
-          begin
-            if CompareText(value,'null') <> 0  then Result := JsonDateToDateTime(value);
-          end
-          else if propinfo.PropType = TypeInfo(TDate) then
-          begin
-            if CompareText(value,'null') <> 0 then Result := StrToDate(value);
-          end
-          else if propinfo.PropType = TypeInfo(TTime) then
-          begin
-            Result := StrToTime(value);
-          end
-          else
-          begin
-            fsettings := DefaultFormatSettings;
-            Result := StrToFloat(StringReplace(value,'.',fsettings.DecimalSeparator,[]));
-          end;
-        end;
-      tkEnumeration:
-        begin
-          Result := value;
-        end;
-      tkBool :
-          begin
-            Result := StrToBool(value);
-          end;
-      tkSet :
-        begin
-          Result := value;
-        end;
-    else
-        begin
-          //raise EclYamlSerializerError.Create('Not supported data type!');
-        end;
-    end;
-    //if not Result.IsEmpty then SetPropertyValue(aObject,propinfo,Result);
-  except
-    on E : Exception do
-    begin
-      raise EYamlDeserializeError.CreateFmt('Deserialize error type "%s" : %s',[aObject.ClassName,e.Message]);
-    end;
-  end;
-end;
-{$ENDIF}
-
-function TRTTIYaml.IsAllowedProperty(aObject : TObject; const aPropertyName : string) : Boolean;
-var
-  propname : string;
-begin
-  Result := True;
-  propname := aPropertyName.ToLower;
-  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 TRTTIYaml.IsGenericList(aObject : TObject) : Boolean;
-var
-  cname : string;
-begin
-  if aObject = nil then Exit(False);
-
-  cname := aObject.ClassName;
-  Result := (cname.StartsWith('TObjectList')) or (cname.StartsWith('TList'));
-end;
-
-function TRTTIYaml.IsGenericXArray(const aClassName : string) : Boolean;
-begin
-  Result := aClassName.StartsWith('TXArray');
-end;
-
-function TRTTIYaml.GetYamlPairByName(aYaml: TYamlObject; const aName: string): TYamlPair;
-var
-  candidate : TYamlPair;
-  yvalue : TYamlValue;
-  i : Integer;
-begin
-  if fUseYamlCaseSense then
-  begin
-    yvalue := aYaml.GetValue(aName);
-    if yvalue <> nil then Result := TYamlPair(yvalue);
-    Exit;
-  end
-  else
-  begin
-    if aYaml <> nil then
-    for i := 0 to aYaml.Count - 1 do
-    begin
-      candidate := aYaml.Pairs[I];
-      if (candidate = nil) or (candidate.Value = nil) then Exit(nil);
-      if CompareText(candidate.Name,aName) = 0 then
-        Exit(candidate);
-    end;
-  end;
-  Result := nil;
-end;
-
-function TRTTIYaml.GetPropertyValue(Instance : TObject; const PropertyName : string) : TValue;
-var
-  pinfo : PPropInfo;
-begin
-  Result := nil;
-  pinfo := GetPropInfo(Instance,PropertyName);
-  case pinfo.PropType^.Kind of
-    tkInteger : Result := GetOrdProp(Instance,pinfo);
-    tkInt64 : Result := GetInt64Prop(Instance,PropertyName);
-    tkFloat : Result := GetFloatProp(Instance,PropertyName);
-    tkChar : Result := Char(GetOrdProp(Instance,PropertyName));
-    {$IFDEF FPC}
-    tkWString : Result := GetWideStrProp(Instance,PropertyName);
-    tkSString,
-    tkAString,
-    {$ELSE}
-    tkWString,
-    {$ENDIF}
-    tkLString : Result := GetStrProp(Instance,pinfo);
-    {$IFDEF FPC}
-    tkEnumeration :
-      begin
-        if fUseEnumNames then Result := GetEnumName(pinfo.PropType,GetOrdProp(Instance,PropertyName))
-          else Result := GetOrdProp(Instance,PropertyName);
-      end;
-    {$ELSE}
-    tkEnumeration :
-      begin
-        if fUseEnumNames then Result := GetEnumName(@pinfo.PropType,GetOrdProp(Instance,PropertyName))
-          else Result := GetOrdProp(Instance,PropertyName);
-      end;
-    {$ENDIF}
-    tkSet : Result := GetSetProp(Instance,pinfo,True);
-    {$IFNDEF FPC}
-    tkClass :
-    {$ELSE}
-    tkBool : Result := Boolean(GetOrdProp(Instance,pinfo));
-    tkObject :
-    {$ENDIF} Result := GetObjectProp(Instance,pinfo);
-    tkDynArray : Result := GetDynArrayProp(Instance,pinfo);
-  end;
-end;
-
-function TRTTIYaml.GetPropertyValueFromObject(Instance : TObject; const PropertyName : string) : TValue;
-var
-  ctx : TRttiContext;
-  rprop : TRttiProperty;
-begin
-  rprop := ctx.GetType(Instance.ClassInfo).GetProperty(PropertyName);
-  Result := rprop.GetValue(Instance);
-end;
-
-{$IFNDEF FPC}
-function TRTTIYaml.GetFieldValueFromRecord(aValue : TValue; const FieldName : string) : TValue;
-var
-  ctx : TRttiContext;
-  rec : TRttiRecordType;
-  rfield : TRttiField;
-begin
-  rec := ctx.GetType(aValue.TypeInfo).AsRecord;
-  rfield := rec.GetField(FieldName);
-  if rfield <> nil then Result := rField.GetValue(aValue.GetReferenceToRawData)
-    else Result := nil;
-end;
-{$ENDIF}
-
-procedure TRTTIYaml.SetPropertyValue(Instance : TObject; const PropertyName : string; aValue : TValue);
-var
-  pinfo : PPropInfo;
-begin
-  pinfo := GetPropInfo(Instance,PropertyName);
-  SetPropertyValue(Instance,pinfo,aValue);
-end;
-
-procedure TRTTIYaml.SetPropertyValue(Instance : TObject; aPropInfo : PPropInfo; aValue : TValue);
-begin
-  case aPropInfo.PropType^.Kind of
-    tkInteger : SetOrdProp(Instance,aPropInfo,aValue.AsInteger);
-    tkInt64 : SetInt64Prop(Instance,aPropInfo,aValue.AsInt64);
-    tkFloat : SetFloatProp(Instance,aPropInfo,aValue.AsExtended);
-    tkChar : SetOrdProp(Instance,aPropInfo,aValue.AsOrdinal);
-    {$IFDEF FPC}
-    tkWString : SetWideStrProp(Instance,aPropInfo,aValue.AsString);
-    tkSString,
-    tkAString,
-    {$ELSE}
-    tkWString,
-    {$ENDIF}
-    tkLString : SetStrProp(Instance,aPropInfo,aValue.AsString);
-    {$IFDEF FPC}
-    tkBool : SetOrdProp(Instance,aPropInfo,aValue.AsOrdinal);
-    tkSet : LoadSetProperty(Instance,aPropInfo,aValue.AsString);
-    {$ENDIF}
-    tkEnumeration : SetEnumProp(Instance,aPropInfo,aValue.AsString);
-    {$IFNDEF FPC}
-    tkClass :
-    {$ELSE}
-    tkObject :
-    {$ENDIF} SetObjectProp(Instance,aPropInfo,aValue.AsObject);
-  end;
-end;
-
-{$IFDEF FPC}
-procedure TRTTIYaml.LoadSetProperty(aInstance : TObject; aPropInfo: PPropInfo; const aValue: string);
-type
-  TCardinalSet = set of 0..SizeOf(Cardinal) * 8 - 1;
-const
-  Delims = [' ', ',', '[', ']'];
-var
-  TypeInfo: PTypeInfo;
-  W: Cardinal;
-  I, N: Integer;
-  Count: Integer;
-  EnumName: string;
-begin
-  W := 0;
-  TypeInfo := GetTypeData(GetPropType(aPropInfo))^.CompType;
-  Count := WordCount(aValue, Delims);
-  for N := 1 to Count do
-  begin
-    EnumName := ExtractWord(N, aValue, Delims);
-    try
-      I := GetEnumValue(TypeInfo, EnumName);
-      if I >= 0 then Include(TCardinalSet(W),I);
-    except
-    end;
-  end;
-  SetOrdProp(aInstance,aPropInfo,W);
-end;
-{$ENDIF}
-
-function TRTTIYaml.Serialize(aObject: TObject): TYamlObject;
-var
-  ctx: TRttiContext;
-  {$IFNDEF FPC}
-  attr : TCustomAttribute;
-  comment : string;
-  {$ENDIF}
-  rType: TRttiType;
-  rProp: TRttiProperty;
-  ypair : TYamlPair;
-  ExcludeSerialize : Boolean;
-  propertyname : string;
-begin
-  if (aObject = nil) then
-  begin
-    Result := nil;
-    Exit;
-  end;
-
-  Result := TYamlObject.Create;
-  try
-    rType := ctx.GetType(aObject.ClassInfo);
-    try
-      //s := rType.ToString;
-      for rProp in TRTTI.GetProperties(rType,roFirstBase) do
-      begin
-        ExcludeSerialize := False;
-        propertyname := rProp.Name;
-        {$IFNDEF FPC}
-        comment := '';
-        for attr in rProp.GetAttributes do
-        begin
-          if attr is TNotSerializableProperty then ExcludeSerialize := True
-          else if attr is TCommentProperty then comment := TCommentProperty(attr).Comment
-          else if  attr is TCustomNameProperty then propertyname := TCustomNameProperty(attr).Name;
-        end;
-        if ((fSerializeLevel = slPublicProperty) and (rProp.PropertyType.IsPublicType))
-            or ((fSerializeLevel = slPublishedProperty) and ((IsPublishedProp(aObject,rProp.Name)) or (rProp.Name = 'List'))) then
-        {$ENDIF}
-        begin
-          if (IsAllowedProperty(aObject,propertyname)) and (not ExcludeSerialize) then
-          begin
-            //add comment as pair
-            {$IFNDEF FPC}
-            if comment <> '' then Result.AddPair(TYamlPair.Create('#',TYamlComment.Create(Comment)));
-            {$ENDIF}
-            begin
-              if (rProp.GetValue(aObject).IsObject) and (IsGenericList(rProp.GetValue(aObject).AsObject)) then
-              begin
-                ypair := Serialize(propertyname,GetPropertyValueFromObject(rProp.GetValue(aObject).AsObject,'List'));
-              end
-              {$IFNDEF FPC}
-              else if (not rProp.GetValue(aObject).IsObject) and (IsGenericXArray(rProp.GetValue(aObject){$IFNDEF NEXTGEN}.TypeInfo.Name{$ELSE}.TypeInfo.NameFld.ToString{$ENDIF})) then
-              begin
-                ypair := Serialize(propertyname,GetFieldValueFromRecord(rProp.GetValue(aObject),'fArray'));
-              end
-              {$ENDIF}
-              else
-              begin
-                {$IFNDEF FPC}
-                ypair := Serialize(propertyname,rProp.GetValue(aObject));
-                {$ELSE}
-                ypair := Serialize(aObject,rProp.PropertyType.TypeKind,propertyname);
-                {$ENDIF}
-              end;
-              //s := jpair.YamlValue.ToString;
-              if ypair <> nil then
-              begin
-                Result.AddPair(ypair);
-              end
-              else ypair.Free;
-            end;
-            //Result.AddPair(Serialize(rProp.Name,rProp.GetValue(aObject)));
-            //s := Result.ToYaml;
-          end;
-        end;
-      end;
-    finally
-      ctx.Free;
-    end;
-  except
-    on E : Exception do
-    begin
-      Result.Free;
-      raise EYamlSerializeError.CreateFmt('Serialize error object "%s" : %s',[aObject.ClassName,e.Message]);
-    end;
-  end;
-end;
-
-function TRTTIYaml.GetValue(aAddr: Pointer; aType: TRTTIType): TValue;
-begin
-  TValue.Make(aAddr,aType.Handle,Result);
-end;
-
-function TRTTIYaml.GetValue(aAddr: Pointer; aTypeInfo: PTypeInfo): TValue;
-begin
-  TValue.Make(aAddr,aTypeInfo,Result);
-end;
-
-{$IFNDEF FPC}
-function TRTTIYaml.Serialize(const aName : string; aValue : TValue) : TYamlPair;
-var
-  ctx: TRttiContext;
-  rRec : TRttiRecordType;
-  rField : TRttiField;
-  rDynArray : TRTTIDynamicArrayType;
-  Yaml : TYamlObject;
-  yArray : TYamlArray;
-  ypair : TYamlPair;
-  yvalue : TYamlValue;
-  i : Integer;
-begin
-  Result := TYamlPair.Create(aName,nil);
-  //Result.YamlString := TYamlString(aName);
-  try
-    case avalue.Kind of
-      tkDynArray :
-        begin
-          yArray := TYamlArray.Create;
-          rDynArray := ctx.GetType(aValue.TypeInfo) as TRTTIDynamicArrayType;
-          try
-            for i := 0 to aValue.GetArrayLength - 1 do
-            begin
-              if not GetValue(PPByte(aValue.GetReferenceToRawData)^ + rDynArray.ElementType.TypeSize * i, rDynArray.ElementType).IsEmpty then
-              begin
-                yvalue := nil;
-                ypair := Serialize(aName,GetValue(PPByte(aValue.GetReferenceToRawData)^ + rDynArray.ElementType.TypeSize * i, rDynArray.ElementType));
-                try
-                  //jValue := TYamlValue(jPair.YamlValue.Clone);
-                  yvalue := ypair.Value;
-                  if yvalue <> nil then
-                  begin
-                    yArray.AddElement(yvalue);
-                    ypair.Value.Owned := False;
-                  end;
-                finally
-                  ypair.Free;
-                  if yvalue <> nil then yvalue.Owned := True;
-                end;
-              end;
-            end;
-            Result.Value := yArray;
-          finally
-            ctx.Free;
-          end;
-        end;
-      tkClass :
-        begin
-           Result.Value := TYamlValue(Serialize(aValue.AsObject));
-        end;
-      tkString, tkLString, tkWString, tkUString :
-        begin
-          Result.Value := TYamlString.Create(aValue.AsString);
-        end;
-      tkChar, tkWChar :
-        begin
-          Result.Value := TYamlString.Create(aValue.AsString);
-        end;
-      tkInteger :
-        begin
-          Result.Value := TYamlInteger.Create(aValue.AsInteger);
-        end;
-      tkInt64 :
-        begin
-          Result.Value := TYamlInteger.Create(aValue.AsInt64);
-        end;
-      tkFloat :
-        begin
-          if aValue.TypeInfo = TypeInfo(TDateTime) then
-          begin
-            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateTimeToJsonDate(aValue.AsExtended));
-          end
-          else if aValue.TypeInfo = TypeInfo(TDate) then
-          begin
-            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateToStr(aValue.AsExtended));
-          end
-          else if aValue.TypeInfo = TypeInfo(TTime) then
-          begin
-            Result.Value := TYamlString.Create(TimeToStr(aValue.AsExtended));
-          end
-          else
-          begin
-            Result.Value := TYamlFloat.Create(aValue.AsExtended);
-          end;
-        end;
-      tkEnumeration :
-        begin
-          if (aValue.TypeInfo = System.TypeInfo(Boolean)) then
-          begin
-            Result.Value := TYamlBoolean.Create(aValue.AsBoolean);
-          end
-          else
-          begin
-            //Result.YamlValue := TYamlString.Create(GetEnumName(aValue.TypeInfo,aValue.AsOrdinal));
-            if fUseEnumNames then Result.Value := TYamlString.Create(aValue.ToString)
-              else Result.Value := TYamlInteger.Create(GetEnumValue(aValue.TypeInfo,aValue.ToString));
-          end;
-        end;
-      tkSet :
-        begin
-          Result.Value := TYamlString.Create(aValue.ToString);
-        end;
-      tkRecord :
-        begin
-          rRec := ctx.GetType(aValue.TypeInfo).AsRecord;
-          try
-            Yaml := TYamlObject.Create;
-            for rField in rRec.GetFields do
-            begin
-              Yaml.AddPair(Serialize(rField.name,rField.GetValue(aValue.GetReferenceToRawData)));
-            end;
-            Result.Value := Yaml;
-          finally
-            ctx.Free;
-          end;
-        end;
-      tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
-        begin
-          //skip these properties
-          //FreeAndNil(Result);
-        end
-    else
-      begin
-        raise EYamlSerializeError.CreateFmt(cNotSupportedDataType,[aName,GetTypeName(aValue.TypeInfo)]);
-      end;
-    end;
-    if Result.Value = nil then Result.Value := TYamlNull.Create;
-  except
-    on E : Exception do
-    begin
-      Result.Free;
-      raise EYamlSerializeError.CreateFmt('Serialize error class "%s.%s" : %s',[aName,aValue.ToString,e.Message]);
-    end;
-  end;
-end;
-{$ELSE}
-function TRTTIYaml.GetPropType(aPropInfo: PPropInfo): PTypeInfo;
-begin
-  Result := aPropInfo^.PropType;
-end;
-
-function TRTTIYaml.FloatProperty(aObject : TObject; aPropInfo: PPropInfo): string;
-const
-  Precisions: array[TFloatType] of Integer = (7, 15, 18, 18, 19);
-var
-  fsettings : TFormatSettings;
-begin
-  fsettings := FormatSettings;
-  Result := StringReplace(FloatToStrF(GetFloatProp(aObject, aPropInfo), ffGeneral,
-    Precisions[GetTypeData(GetPropType(aPropInfo))^.FloatType],0),
-    '.',fsettings.DecimalSeparator,[rfReplaceAll]);
-end;
-
-function TRTTIYaml.Serialize(const aName : string; aValue : TValue) : TYamlPair;
-begin
-  Result := TYamlPair.Create(aName,nil);
-  //Result.YamlString := TYamlString(aName);
-  try
-    case avalue.Kind of
-      tkClass :
-        begin
-           Result.Value := TYamlValue(Serialize(aValue.AsObject));
-        end;
-      tkString, tkLString, tkWString, tkUString :
-        begin
-          Result.Value := TYamlString.Create(aValue.AsString);
-        end;
-      tkChar, tkWChar :
-        begin
-          Result.Value := TYamlString.Create(aValue.AsString);
-        end;
-      tkInteger :
-        begin
-          Result.Value := TYamlInteger.Create(aValue.AsInteger);
-        end;
-      tkInt64 :
-        begin
-          Result.Value := TYamlInteger.Create(aValue.AsInt64);
-        end;
-      tkFloat :
-        begin
-          if aValue.TypeInfo = TypeInfo(TDateTime) then
-          begin
-            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateTimeToJsonDate(aValue.AsExtended));
-          end
-          else if aValue.TypeInfo = TypeInfo(TDate) then
-          begin
-            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateToStr(aValue.AsExtended));
-          end
-          else if aValue.TypeInfo = TypeInfo(TTime) then
-          begin
-            Result.Value := TYamlString.Create(TimeToStr(aValue.AsExtended));
-          end
-          else
-          begin
-            Result.Value := TYamlFloat.Create(aValue.AsExtended);
-          end;
-        end;
-      tkEnumeration :
-        begin
-          if (aValue.TypeInfo = System.TypeInfo(Boolean)) then
-          begin
-            Result.Value := TYamlBoolean.Create(aValue.AsBoolean);
-          end
-          else
-          begin
-            //Result.YamlValue := TYamlString.Create(GetEnumName(aValue.TypeInfo,aValue.AsOrdinal));
-            if fUseEnumNames then Result.Value := TYamlString.Create(aValue.ToString)
-              else Result.Value := TYamlInteger.Create(GetEnumValue(aValue.TypeInfo,aValue.ToString));
-          end;
-        end;
-      tkSet :
-        begin
-          Result.Value := TYamlString.Create(aValue.ToString);
-        end;
-    else
-      begin
-        //raise EYamlDeserializeError.CreateFmt('Not supported type "%s":%d',[aName,Integer(aValue.Kind)]);
-      end;
-    end;
-    if Result.Value = nil then Result.Value := TYamlNull.Create;
-  except
-    Result.Free;
-  end;
-end;
-
-function TRTTIYaml.Serialize(aObject : TObject; aType : TTypeKind; const aPropertyName : string) : TYamlPair;
-var
-  propinfo : PPropInfo;
-  yArray : TYamlArray;
-  ypair : TYamlPair;
-  yvalue : TYamlValue;
-  i : Integer;
-  pArr : Pointer;
-  rValue : TValue;
-  rItemValue : TValue;
-  len : Integer;
-begin
-  try
-    Result := TYamlPair.Create(aPropertyName,nil);
-
-    propinfo := GetPropInfo(aObject,aPropertyName);
-    //case propinfo.PropType.Kind of
-    case aType of
-      tkDynArray :
-        begin
-          len := 0;
-          yArray := TYamlArray.Create;
-          try
-            pArr := GetDynArrayProp(aObject,aPropertyName);
-            TValue.Make(@pArr,propinfo.PropType, rValue);
-            if rValue.IsArray then
-            begin
-              len := rValue.GetArrayLength;
-              for i := 0 to len - 1 do
-              begin
-                rItemValue := rValue.GetArrayElement(i);
-                ypair := Serialize(aPropertyName,rItemValue);
-                try
-                  //jValue := TYamlValue(jPair.YamlValue.Clone);
-                  yvalue := ypair.Value;
-                  yArray.AddElement(yvalue);
-                  //jPair.YamlValue.Owned := False;
-                finally
-                  ypair.Free;
-                  //jValue.Owned := True;
-                end;
-              end;
-            end;
-            Result.Value := yArray;
-          finally
-            //DynArrayClear(pArr,propinfo.PropType);
-            pArr := nil;
-          end;
-        end;
-      tkClass :
-        begin
-          Result.Value := TYamlValue(Serialize(GetObjectProp(aObject,aPropertyName)));
-        end;
-      tkString, tkLString, tkWString, tkUString, tkAString :
-        begin
-          Result.Value := TYamlString.Create(GetStrProp(aObject,aPropertyName));
-        end;
-      tkChar, tkWChar :
-        begin
-          Result.Value := TYamlString.Create(Char(GetOrdProp(aObject,aPropertyName)));
-        end;
-      tkInteger :
-        begin
-          Result.Value := TYamlInteger.Create(GetOrdProp(aObject,aPropertyName));
-        end;
-      tkInt64 :
-        begin
-          Result.Value := TYamlInteger.Create(GetOrdProp(aObject,aPropertyName));
-        end;
-      tkFloat :
-        begin
-          if propinfo.PropType = TypeInfo(TDateTime) then
-          begin
-            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateTimeToJsonDate(GetFloatProp(aObject,aPropertyName)));
-          end
-          else if propinfo.PropType = TypeInfo(TDate) then
-          begin
-            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateToStr(GetFloatProp(aObject,aPropertyName)));
-          end
-          else if propinfo.PropType = TypeInfo(TTime) then
-          begin
-            Result.Value := TYamlString.Create(TimeToStr(GetFloatProp(aObject,aPropertyName)));
-          end
-          else
-          begin
-            //Result.YamlValue := TYamlFloatNumber.Create(GetFloatProp(aObject,aPropertyName));
-            Result.Value := TYamlFloat.Create(StrToFloat(FloatProperty(aObject,propinfo)));
-          end;
-        end;
-      tkEnumeration,tkBool :
-        begin
-          if (propinfo.PropType = System.TypeInfo(Boolean)) then
-          begin
-            Result.Value := TYamlBoolean.Create(Boolean(GetOrdProp(aObject,aPropertyName)));
-          end
-          else
-          begin
-            if fUseEnumNames then Result.Value := TYamlString.Create(GetEnumName(propinfo.PropType,GetOrdProp(aObject,aPropertyName)))
-              else Result.Value := TYamlInteger.Create(GetOrdProp(aObject,aPropertyName));
-            //Result.YamlValue := TYamlString.Create(aValue.ToString);
-          end;
-        end;
-      tkSet :
-        begin
-          Result.Value := TYamlString.Create(GetSetProp(aObject,aPropertyName));
-        end;
-      {$IFNDEF FPC}
-      tkRecord :
-        begin
-          rRec := ctx.GetType(aValue.TypeInfo).AsRecord;
-          try
-            Yaml := TYamlObject.Create;
-            for rField in rRec.GetFields do
-            begin
-              Yaml.AddPair(Serialize(rField.name,rField.GetValue(aValue.GetReferenceToRawData)));
-            end;
-            Result.YamlValue := Yaml;
-          finally
-            ctx.Free;
-          end;
-        end;
-      {$ENDIF}
-      tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
-        begin
-          //skip these properties
-          //FreeAndNil(Result);
-        end
-    else
-      begin
-
-        //raise EYamlDeserializeError.CreateFmt('Not supported type "%s":%d',[aName,Integer(aValue.Kind)]);
-      end;
-    end;
-    if Result.Value = nil then Result.Value := TYamlNull.Create;
-  except
-    on E : Exception do
-    begin
-      Result.Free;
-      {$IFNDEF FPC}
-      raise EYamlSerializeError.CreateFmt('Serialize error class "%s.%s" : %s',[aName,aValue.ToString,e.Message]);
-      {$ENDIF}
-    end;
-  end;
-end;
-{$ENDIF}
-
-
-{ TYamlSerializer}
-
-constructor TYamlSerializer.Create(aSerializeLevel: TSerializeLevel; aUseEnumNames : Boolean = True);
-begin
-  {$IFDEF FPC}
-  if aSerializeLevel = TSerializeLevel.slPublicProperty then raise EYamlSerializeError.Create('FreePascal RTTI only supports published properties');
-  {$ENDIF}
-  fSerializeLevel := aSerializeLevel;
-  fUseEnumNames := aUseEnumNames;
-  fUseYamlCaseSense := False;
-  fRTTIYaml := TRTTIYaml.Create(aSerializeLevel,aUseEnumNames);
-  fRTTIYaml.UseYamlCaseSense := fUseYamlCaseSense;
-end;
-
-function TYamlSerializer.YamlToObject(aType: TClass; const aYaml: string): TObject;
-var
-  Yaml: TYamlObject;
-begin
-  Yaml := TYamlObject.ParseYamlValue(aYaml) as TYamlObject;
-  try
-    Result := fRTTIYaml.DeserializeClass(aType,Yaml);
-  finally
-    Yaml.Free;
-  end;
-end;
-
-destructor TYamlSerializer.Destroy;
-begin
-  fRTTIYaml.Free;
-  inherited;
-end;
-
-function TYamlSerializer.YamlToObject(aObject: TObject; const aYaml: string): TObject;
-var
-  Yaml: TYamlObject;
-begin
-  Result := aObject;
-  Yaml := TYamlObject(TYamlObject.ParseYamlValue(aYaml));
-  try
-    fRTTIYaml.DeserializeObject(aObject,Yaml);
-  finally
-    Yaml.Free;
-  end;
-end;
-
-function TYamlSerializer.ObjectToYaml(aObject : TObject): string;
-var
-  Yaml: TYamlObject;
-begin
-  Yaml := fRTTIYaml.Serialize(aObject);
-  try
-    Result := Yaml.ToYaml;
-  finally
-    Yaml.Free;
-  end;
-end;
-
-procedure TYamlSerializer.SetSerializeLevel(const Value: TSerializeLevel);
-begin
-  fSerializeLevel := Value;
-  if Assigned(fRTTIYaml) then fRTTIYaml.fSerializeLevel := Value;
-end;
-
-procedure TYamlSerializer.SetUseEnumNames(const Value: Boolean);
-begin
-  fUseEnumNames := Value;
-  if Assigned(fRTTIYaml) then fRTTIYaml.UseEnumNames := Value;
-end;
-
-procedure TYamlSerializer.SetUseYamlCaseSense(const Value: Boolean);
-begin
-  fUseYamlCaseSense := Value;
-  if Assigned(fRTTIYaml) then fRTTIYaml.UseYamlCaseSense := Value;
-end;
-
-{$IFNDEF FPC}
-{ TCommentProperty }
-
-constructor TCommentProperty.Create(const aComment: string);
-begin
-  fComment := aComment;
-end;
-
-{ TCustomNameProperty }
-
-constructor TCustomNameProperty.Create(const aName: string);
-begin
-  fName := aName;
-end;
-{$ENDIF}
-
-
-end.
-
-
-
-
+{ ***************************************************************************
+
+  Copyright (c) 2015-2021 Kike P�rez
+
+  Unit        : Quick.YAML.Serializer
+  Description : YAML Serializer
+  Author      : Kike P�rez
+  Version     : 1.0
+  Created     : 12/04/2019
+  Modified    : 05/08/2021
+
+  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.YAML.Serializer;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  Classes,
+  SysUtils,
+  Rtti,
+  TypInfo,
+  {$IFDEF FPC}
+   rttiutils,
+   strUtils,
+   Generics.Collections,
+  {$ELSE}
+    {$IFDEF DELPHIRX10_UP}
+    System.Generics.Collections,
+    {$ENDIF}
+  {$ENDIF}
+  DateUtils,
+  Quick.Commons,
+  Quick.RTTI.Utils,
+  Quick.YAML,
+  Quick.Value,
+  Quick.Arrays;
+
+type
+
+  EYamlSerializeError = class(Exception);
+  EYamlDeserializeError = class(Exception);
+
+  {$IFNDEF FPC}
+  TNotSerializableProperty = class(TCustomAttribute);
+
+  TCommentProperty = class(TCustomAttribute)
+  private
+    fComment : string;
+  public
+    constructor Create(const aComment: string);
+    property Comment : string read fComment;
+  end;
+
+  TCustomNameProperty = class(TCustomAttribute)
+  private
+    fName : string;
+  public
+    constructor Create(const aName: string);
+    property Name : string read fName;
+  end;
+  {$ENDIF}
+
+  IYamlSerializer = interface
+  ['{CA26F7AE-F1FE-41BE-9C23-723A687F60D1}']
+    function YamlToObject(aType: TClass; const aYaml: string): TObject; overload;
+    function YamlToObject(aObject: TObject; const aYaml: string): TObject; overload;
+    function ObjectToYaml(aObject : TObject): string;
+  end;
+
+  TSerializeLevel = (slPublicProperty, slPublishedProperty);
+
+  TRTTIYaml = class
+  private
+    fSerializeLevel : TSerializeLevel;
+    fUseEnumNames : Boolean;
+    fUseYamlCaseSense : Boolean;
+    function GetValue(aAddr: Pointer; aType: TRTTIType): TValue; overload;
+    function GetValue(aAddr: Pointer; aTypeInfo: PTypeInfo): TValue; overload;
+    function IsAllowedProperty(aObject : TObject; const aPropertyName : string) : Boolean;
+    function IsGenericList(aObject : TObject) : Boolean;
+    function IsGenericXArray(const aClassName : string) : Boolean;
+    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 CreateInstance(aClass: TClass): TValue; overload;
+    function CreateInstance(aType: TRttiType): TValue; overload;
+    {$ENDIF}
+    procedure SetPropertyValue(Instance : TObject; aPropInfo : PPropInfo; aValue : TValue); overload;
+    procedure SetPropertyValue(Instance : TObject; const PropertyName : string; aValue : TValue); overload;
+    {$IFDEF FPC}
+    function FloatProperty(aObject : TObject; aPropInfo: PPropInfo): string;
+    function GetPropType(aPropInfo: PPropInfo): PTypeInfo;
+    procedure LoadSetProperty(aInstance : TObject; aPropInfo: PPropInfo; const aValue: string);
+    {$ENDIF}
+  public
+    constructor Create(aSerializeLevel : TSerializeLevel; aUseEnumNames : Boolean = True);
+    property UseEnumNames : Boolean read fUseEnumNames write fUseEnumNames;
+    property UseYamlCaseSense : Boolean read fUseYamlCaseSense write fUseYamlCaseSense;
+    {$IFNDEF FPC}
+    function DeserializeDynArray(aTypeInfo : PTypeInfo; aObject : TObject; const aYamlArray: TYamlArray) : TValue;
+    function DeserializeRecord(aRecord : TValue; aObject : TObject; const aYaml : TYamlObject) : TValue;
+    {$ELSE}
+    procedure DeserializeDynArray(aTypeInfo: PTypeInfo; const aPropertyName : string; aObject: TObject; const aYamlArray: TYamlArray);
+    {$ENDIF}
+    function DeserializeClass(aType : TClass; const aYaml : TYamlObject) : TObject;
+    function DeserializeObject(aObject : TObject; const aYaml : TYamlObject) : TObject; overload;
+    {$IFNDEF FPC}
+    function DeserializeList(aObject: TObject; const aName : string; const aYaml: TYamlObject) : TObject;
+    procedure DeserializeXArray(Instance : TObject; aRecord : TValue; aProperty : TRttiProperty; const aPropertyName : string; aYaml : TYamlObject);
+    {$ENDIF}
+    function DeserializeProperty(aObject : TObject; const aName : string; aProperty : TRttiProperty; const aYaml : TYamlObject) : TObject; overload;
+    {$IFNDEF FPC}
+    function DeserializeType(aObject : TObject; aType : TTypeKind; aTypeInfo : PTypeInfo; const aValue: string) : TValue;
+    {$ELSE}
+    function DeserializeType(aObject : TObject; aType : TTypeKind; const aPropertyName, aValue: string) : TValue;
+    {$ENDIF}
+    {$IFNDEF FPC}
+    function Serialize(const aName : string; aValue : TValue) : TYamlPair; overload;
+    {$ELSE}
+    function Serialize(aObject : TObject; aType : TTypeKind; const aPropertyName : string) : TYamlPair;
+    function Serialize(const aName : string; aValue : TValue) : TYamlPair;
+    {$ENDIF}
+    function Serialize(aObject : TObject) : TYamlObject; overload;
+    function GetYamlPairByName(aYaml : TYamlObject; const aName : string) : TYamlPair;
+  end;
+
+  TYamlSerializer = class(TInterfacedObject,IYamlSerializer)
+  strict private
+    fSerializeLevel : TSerializeLevel;
+    fUseEnumNames : Boolean;
+    fUseYamlCaseSense : Boolean;
+    fRTTIYaml : TRTTIYaml;
+  private
+    procedure SetUseEnumNames(const Value: Boolean);
+    procedure SetUseYamlCaseSense(const Value: Boolean);
+    procedure SetSerializeLevel(const Value: TSerializeLevel);
+  public
+    constructor Create(aSerializeLevel: TSerializeLevel; aUseEnumNames : Boolean = True);
+    destructor Destroy; override;
+    property SerializeLevel : TSerializeLevel read fSerializeLevel write SetSerializeLevel;
+    property UseEnumNames : Boolean read fUseEnumNames write SetUseEnumNames;
+    property UseYamlCaseSense : Boolean read fUseYamlCaseSense write SetUseYamlCaseSense;
+    function YamlToObject(aType : TClass; const aYaml: string) : TObject; overload;
+    function YamlToObject(aObject : TObject; const aYaml: string) : TObject; overload;
+    function ObjectToYaml(aObject : TObject): string;
+  end;
+
+  PPByte = ^PByte;
+
+resourcestring
+  cNotSupportedDataType = 'Not supported "%s" data type "%s"';
+  cNotSerializable = 'Object is not serializable';
+
+implementation
+
+{ TRTTIYaml }
+
+{$IFNDEF FPC}
+function TRTTIYaml.DeserializeDynArray(aTypeInfo: PTypeInfo; aObject: TObject; const aYamlArray: TYamlArray) : TValue;
+var
+  rType: PTypeInfo;
+  len: NativeInt;
+  pArr: Pointer;
+  rItemValue: TValue;
+  i: Integer;
+  objClass: TClass;
+  ctx : TRttiContext;
+  Yaml : TYamlObject;
+  rDynArray : TRttiDynamicArrayType;
+  propObj : TObject;
+begin
+  if GetTypeData(aTypeInfo).DynArrElType = nil then Exit;
+  if not assigned(aYamlArray) then Exit;
+
+  len := aYamlArray.Count;
+  rType := GetTypeData(aTypeInfo).DynArrElType^;
+  pArr := nil;
+  DynArraySetLength(pArr,aTypeInfo, 1, @len);
+  try
+    TValue.Make(@pArr,aTypeInfo, Result);
+    rDynArray := ctx.GetType(Result.TypeInfo) as TRTTIDynamicArrayType;
+
+    for i := 0 to aYamlArray.Count - 1 do
+    begin
+      rItemValue := nil;
+      case rType.Kind of
+        tkClass :
+          begin
+            if TYamlPair(aYamlArray.Items[i]).Value is TYamlObject then
+            begin
+              Yaml := TYamlObject(TYamlPair(aYamlArray.Items[i]).value);
+              propObj := GetValue(PPByte(Result.GetReferenceToRawData)^ +rDynArray.ElementType.TypeSize * i, rDynArray.ElementType).AsObject;
+              if propObj = nil then
+              begin
+                objClass := rType.TypeData.ClassType;
+                rItemValue := DeserializeClass(objClass,yaml);
+              end
+              else
+              begin
+                DeserializeObject(propObj,yaml);
+              end;
+            end;
+          end;
+        tkRecord :
+          begin
+            Yaml := TYamlObject(TYamlPair(aYamlArray.Items[i]).value);
+            rItemValue := DeserializeRecord(GetValue(PPByte(Result.GetReferenceToRawData)^ +rDynArray.ElementType.TypeSize * i,
+                                            rDynArray.ElementType),aObject,Yaml);
+          end;
+        tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
+          begin
+            //skip these properties
+          end
+      else
+        begin
+          rItemValue := DeserializeType(aObject,rType.Kind,aTypeInfo,aYamlArray.Items[i].Value);
+        end;
+      end;
+      if not rItemValue.IsEmpty then Result.SetArrayElement(i,rItemValue);
+    end;
+    //aProperty.SetValue(aObject,rValue);
+  finally
+    DynArrayClear(pArr,aTypeInfo);
+  end;
+end;
+{$ELSE}
+procedure TRTTIYaml.DeserializeDynArray(aTypeInfo: PTypeInfo; const aPropertyName : string; aObject: TObject; const aYamlArray: TYamlArray);
+var
+  rType: PTypeInfo;
+  len: NativeInt;
+  pArr: Pointer;
+  rItemValue: TValue;
+  i: Integer;
+  objClass: TClass;
+  propObj : TObject;
+  rValue : TValue;
+  yaml : TYamlObject;
+begin
+  if GetTypeData(aTypeInfo).ElType2 = nil then Exit;
+  len := aYamlArray.Count;
+  rType := GetTypeData(aTypeInfo).ElType2;
+  pArr := nil;
+  DynArraySetLength(pArr,aTypeInfo, 1, @len);
+  try
+    TValue.Make(@pArr,aTypeInfo, rValue);
+    for i := 0 to aYamlArray.Count - 1 do
+    begin
+      rItemValue := nil;
+      case rType.Kind of
+        tkClass :
+          begin
+            if TYamlPair(aYamlArray.Items[i]).Value is TYamlObject then
+            begin
+              Yaml := TYamlObject(TYamlPair(aYamlArray.Items[i]).value);
+              propObj := GetValue(PPByte(rValue.GetReferenceToRawData)^ +GetTypeData(aTypeInfo).elSize * i, GetTypeData(aTypeInfo).ElType2).AsObject;
+              if propObj = nil then
+              begin
+                //objClass := GetTypeData(aTypeInfo).ClassType;
+                objClass := GetTypeData(GetTypeData(aTypeInfo).ElType2).ClassType;
+                rItemValue := DeserializeClass(objClass,yaml);
+              end
+              else
+              begin
+                DeserializeObject(propObj,yaml);
+              end;
+            end;
+          end;
+        tkRecord :
+          begin
+            {Yaml := TYamlObject(aYamlArray.Items[i]);
+            rItemValue := DeserializeRecord(GetValue(PPByte(Result.GetReferenceToRawData)^ +rDynArray.ElementType.TypeSize * i,
+                                            rDynArray.ElementType),aObject,Yaml);  }
+          end;
+        tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
+          begin
+            //skip these properties
+          end
+      else
+        begin
+          rItemValue := DeserializeType(aObject,GetTypeData(aTypeInfo).ElType2.Kind,aPropertyName,aYamlArray.Items[i].Value);
+        end;
+      end;
+      if not rItemValue.IsEmpty then rValue.SetArrayElement(i,rItemValue);
+    end;
+    //aProperty.SetValue(aObject,rValue);
+    SetDynArrayProp(aObject,GetPropInfo(aObject,aPropertyName),pArr);
+  finally
+    DynArrayClear(pArr,aTypeInfo);
+  end;
+end;
+{$ENDIF}
+
+{$IFNDEF FPC}
+function TRTTIYaml.DeserializeRecord(aRecord : TValue; aObject : TObject; const aYaml : TYamlObject) : TValue;
+var
+  ctx : TRttiContext;
+  rRec : TRttiRecordType;
+  rField : TRttiField;
+  rValue : TValue;
+  member : TYamlPair;
+  yArray : TYamlArray;
+  Yaml : TYamlObject;
+  objClass : TClass;
+  propobj : TObject;
+begin
+  rRec := ctx.GetType(aRecord.TypeInfo).AsRecord;
+  try
+    for rField in rRec.GetFields do
+    begin
+      rValue := nil;
+      //member := TYamlPair(aYaml.GetValue(rField.Name));
+      member := GetYamlPairByName(aYaml,rField.Name);
+      if member <> nil then
+      case rField.FieldType.TypeKind of
+        tkDynArray :
+          begin
+            yArray := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlArray;
+            try
+              rValue := DeserializeDynArray(rField.FieldType.Handle,aObject,yArray);
+            finally
+              yArray.Free;
+            end;
+          end;
+        tkClass :
+          begin
+            //if (member.YamlValue is TYamlObject) then
+            begin
+              propobj := rField.GetValue(@aRecord).AsObject;
+              Yaml := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlObject;
+              try
+                if propobj = nil then
+                begin
+                  objClass := rField.FieldType.Handle^.TypeData.ClassType;// aProperty.PropertyType.Handle^.TypeData.ClassType;
+                  rValue := DeserializeClass(objClass,Yaml);
+                end
+                else
+                begin
+                  DeserializeObject(propobj,Yaml);
+                end;
+              finally
+                Yaml.Free;
+              end;
+            end
+          end;
+        tkRecord :
+          begin
+            Yaml := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlObject;
+            try
+              rValue := DeserializeRecord(rField.GetValue(aRecord.GetReferenceToRawData),aObject,Yaml);
+            finally
+              Yaml.Free;
+            end;
+          end
+      else
+        begin
+          //rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,member.ToYaml);
+          {$IFNDEF FPC}
+          //avoid return unicode escaped chars if string
+          if rField.FieldType.TypeKind in [tkString, tkLString, tkWString, tkUString] then
+            {$IFDEF DELPHIRX10_UP}
+            rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,member.Value.AsString)
+            {$ELSE}
+            rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,member.YamlString.ToString)
+            {$ENDIF}
+            else rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,member.Value.AsString);
+          {$ELSE}
+          rValue := DeserializeType(aObject,rField.FieldType.TypeKind,aName,member.Value.AsString);
+          {$ENDIF}
+        end;
+      end;
+      if not rValue.IsEmpty then rField.SetValue(aRecord.GetReferenceToRawData,rValue);
+    end;
+    Result := aRecord;
+  finally
+    ctx.Free;
+  end;
+end;
+{$ENDIF}
+
+constructor TRTTIYaml.Create(aSerializeLevel : TSerializeLevel; aUseEnumNames : Boolean = True);
+begin
+  fSerializeLevel := aSerializeLevel;
+  fUseEnumNames := aUseEnumNames;
+  fUseYamlCaseSense := False;
+end;
+
+function TRTTIYaml.DeserializeClass(aType: TClass; const aYaml: TYamlObject): TObject;
+var
+  Ctx: TRttiContext;
+  rType: TRttiType;
+  mType: TRTTIMethod;
+  metaClass: TClass;
+begin
+  Result := nil;
+  if (aYaml = nil) or ((aYaml as TYamlValue) is TYamlNull) or (aYaml.Count = 0) then Exit;
+
+  {$IFNDEF FPC}
+  Result := CreateInstance(aType).AsObject;
+  {$ELSE}
+  Result := aType.Create;
+  {$ENDIF}
+  try
+    Result := DeserializeObject(Result, aYaml);
+  except
+    on E : Exception do
+    begin
+      Result.Free;
+      raise EYamlDeserializeError.CreateFmt('Deserialize error class "%s" : %s',[aType.ClassName,e.Message]);
+    end;
+  end;
+end;
+
+function TRTTIYaml.DeserializeObject(aObject: TObject; const aYaml: TYamlObject): TObject;
+var
+  ctx: TRttiContext;
+  rType: TRttiType;
+  rProp: TRttiProperty;
+  {$IFNDEF FPC}
+  attr: TCustomAttribute;
+  {$ENDIF}
+  propertyname : string;
+begin
+  Result := aObject;
+
+  if (aYaml = nil) or ((aYaml as TYamlValue) is TYamlNull) or (aYaml.Count = 0) or (Result = nil) then Exit;
+
+  try
+    rType := ctx.GetType(aObject.ClassInfo);
+    try
+      for rProp in rType.GetProperties do
+      begin
+        {$IFNDEF FPC}
+        if ((fSerializeLevel = slPublicProperty) and (rProp.PropertyType.IsPublicType))
+            or ((fSerializeLevel = slPublishedProperty) and ((IsPublishedProp(aObject,rProp.Name)) or (rProp.Name = 'List'))) then
+        {$ENDIF}
+        begin
+          if ((rProp.IsWritable) or (rProp.Name = 'List')) and (IsAllowedProperty(aObject,rProp.Name)) then
+          begin
+            propertyname := rProp.Name;
+            {$IFNDEF FPC}
+            for attr in rProp.GetAttributes do if attr is TCustomNameProperty then propertyname := TCustomNameProperty(attr).Name;
+            if rProp.Name = 'List' then
+            begin
+              Result := DeserializeList(Result,propertyname,aYaml);
+            end
+            else if (rProp.GetValue(aObject).IsObject) and (IsGenericList(rProp.GetValue(aObject).AsObject)) then
+            begin
+              DeserializeList(rProp.GetValue(aObject).AsObject,'List',TYamlObject(aYaml.GetValue(propertyname)));
+            end
+            else if (not rProp.GetValue(aObject).IsObject) and (IsGenericXArray(rProp.GetValue(aObject){$IFNDEF NEXTGEN}.TypeInfo.Name{$ELSE}.TypeInfo.NameFld.ToString{$ENDIF})) then
+            begin
+              DeserializeXArray(Result,rProp.GetValue(aObject),rProp,propertyname,aYaml);
+            end
+            else
+            {$ENDIF}
+            Result := DeserializeProperty(Result,propertyname,rProp,aYaml);
+          end;
+        end;
+      end;
+    finally
+      ctx.Free;
+    end;
+  except
+    on E : Exception do
+    begin
+      Result.Free;
+      raise EYamlDeserializeError.CreateFmt('Deserialize error for object "%s" : %s',[aObject.ClassName,e.Message]);
+    end;
+  end;
+end;
+
+{$IFNDEF FPC}
+function TRTTIYaml.DeserializeList(aObject: TObject; const aName : string; const aYaml: TYamlObject) : TObject;
+var
+  ctx : TRttiContext;
+  rType : TRttiType;
+  yArray : TYamlArray;
+  member : TYamlPair;
+  rvalue : TValue;
+  i : Integer;
+  rProp : TRttiProperty;
+  {$IFNDEF DELPHIRX103_UP}
+  rfield : TRttiField;
+  {$ENDIF}
+begin
+  Result := aObject;
+
+  rType := ctx.GetType(aObject.ClassInfo);
+  try
+    rProp := rType.GetProperty('List');
+    if rProp = nil then Exit;
+  finally
+    ctx.Free;
+  end;
+  member := GetYamlPairByName(aYaml,aName);
+  //var a := aYaml.ToYaml;
+  if member = nil then yArray := TYamlArray(aYaml) //TYamlObject.ParseYamlValue(aYaml.ToYaml) as TYamlArray
+    else yArray := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlArray;
+
+  rvalue := DeserializeDynArray(rProp.PropertyType.Handle,Result,yArray);
+
+  if not rValue.IsEmpty then
+  begin
+    {$IFDEF DELPHIRX103_UP}
+    if (TObjectList<TObject>(aObject) <> nil) and (rvalue.IsArray) then
+    begin
+      TObjectList<TObject>(aObject).Clear;
+      TObjectList<TObject>(aObject).Capacity := rvalue.GetArrayLength;
+      for i := 0 to rvalue.GetArrayLength - 1 do
+      begin
+        TObjectList<TObject>(aObject).Add(rvalue.GetArrayElement(i).AsObject);
+      end;
+    end;
+    {$ELSE}
+    for rfield in rType.GetFields do
+    begin
+      if rfield.Name = 'FOwnsObjects' then rfield.SetValue(aObject,True);
+      //if rfield.Name = 'FCount' then rfield.SetValue(aObject,i);
+      if rfield.Name = 'FItems' then
+      begin
+        //if TList(aObject) <> nil then TList(aObject).Clear;
+        //rfield.GetValue(aObject).AsObject.Free;// aValue.GetReferenceToRawData)
+        rfield.SetValue(aObject,rValue);// .SetDynArrayProp(aObject,'fItems',Result);
+        Break;
+      end;
+    end;
+    rProp := rType.GetProperty('Count');
+    rProp.SetValue(aObject,i);
+    {$ENDIF}
+  end;
+end;
+{$ENDIF}
+
+{$IFNDEF FPC}
+procedure TRTTIYaml.DeserializeXArray(Instance : TObject; aRecord : TValue; aProperty : TRttiProperty; const aPropertyName : string; aYaml : TYamlObject);
+var
+  ctx : TRttiContext;
+  rRec : TRttiRecordType;
+  rfield : TRttiField;
+  rValue : TValue;
+  member : TYamlPair;
+  yArray : TYamlArray;
+begin
+  rRec := ctx.GetType(aRecord.TypeInfo).AsRecord;
+  try
+    rfield := rRec.GetField('fArray');
+    if rfield <> nil then
+    begin
+      rValue := nil;
+      //member := TYamlPair(aYaml.GetValue(rField.Name));
+      member := GetYamlPairByName(aYaml,aPropertyName);
+      if (member <> nil) and (rField.FieldType.TypeKind = tkDynArray) then
+      begin
+        yArray := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlArray;
+        try
+          rValue := DeserializeDynArray(rField.FieldType.Handle,nil,yArray);
+        finally
+          yArray.Free;
+        end;
+      end;
+    end;
+    if not rValue.IsEmpty then rField.SetValue(aRecord.GetReferenceToRawData,rValue);
+    aProperty.SetValue(Instance,aRecord);
+  finally
+    ctx.Free;
+  end;
+end;
+{$ENDIF}
+
+function TRTTIYaml.DeserializeProperty(aObject : TObject; const aName : string; aProperty : TRttiProperty; const aYaml : TYamlObject) : TObject;
+var
+  rValue : TValue;
+  member : TYamlPair;
+  objClass: TClass;
+  yArray : TYamlArray;
+  Yaml : TYamlObject;
+begin
+    Result := aObject;
+    rValue := nil;
+    //member := TYamlPair(aYaml.GetValue(aName));
+    member := GetYamlPairByName(aYaml,aName);
+    if member <> nil then
+    begin
+      case aProperty.PropertyType.TypeKind of
+        tkDynArray :
+          begin
+            yArray := member.Value as TYamlArray;
+            {$IFNDEF FPC}
+            aProperty.SetValue(aObject,DeserializeDynArray(aProperty.PropertyType.Handle,Result,yArray));
+            {$ELSE}
+            DeserializeDynArray(aProperty.PropertyType.Handle,aName,Result,yArray);
+            {$ENDIF}
+            Exit;
+          end;
+        tkClass :
+          begin
+            //if (member.YamlValue is TYamlObject) then
+            begin
+              Yaml := TYamlObject(TYamlObject.ParseYamlValue(member.ToYaml));
+              try
+                if aProperty.GetValue(aObject).AsObject = nil then
+                begin
+                  {$IFNDEF FPC}
+                  objClass := aProperty.PropertyType.Handle^.TypeData.ClassType;
+                  rValue := DeserializeClass(objClass,Yaml);
+                  {$ELSE}
+                  objClass := GetObjectPropClass(aObject,aName);
+                  //objClass := GetTypeData(aProperty.PropertyType.Handle)^.ClassType;
+                  rValue := DeserializeClass(objClass,Yaml);
+                  SetObjectProp(aObject,aName,rValue.AsObject);
+                  Exit;
+                  {$ENDIF}
+                end
+                else
+                begin
+                  rValue := DeserializeObject(aProperty.GetValue(aObject).AsObject,Yaml);
+                  Exit;
+                end;
+              finally
+                Yaml.Free;
+              end;
+            end
+          end;
+        {$IFNDEF FPC}
+        tkRecord :
+          begin
+            Yaml := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlObject;
+            try
+              rValue := DeserializeRecord(aProperty.GetValue(aObject),aObject,Yaml);
+            finally
+              Yaml.Free;
+            end;
+          end;
+        tkSet :
+          begin
+            rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,member.ToYaml)
+          end
+        {$ENDIF}
+      else
+        begin
+          {$IFNDEF FPC}
+          //avoid return unicode escaped chars if string
+          if aProperty.PropertyType.TypeKind in [tkString, tkLString, tkWString, tkUString] then
+            {$IFDEF DELPHIRX10_UP}
+            rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,member.Value.AsString)
+            {$ELSE}
+            rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,member.YamlString.ToString)
+            {$ENDIF}
+          else rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,member.Value.AsString);
+          {$ELSE}
+          rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aName,member.Value.AsString);
+          if not rValue.IsEmpty then SetPropertyValue(aObject,aName,rValue);
+          {$ENDIF}
+        end;
+      end;
+      {$IFNDEF FPC}
+      if not rValue.IsEmpty then aProperty.SetValue(Result,rValue);
+      {$ENDIF}
+    end;
+end;
+
+{$IFNDEF FPC}
+function TRTTIYaml.DeserializeType(aObject : TObject; aType : TTypeKind; aTypeInfo : PTypeInfo; const aValue: string) : TValue;
+var
+  i : Integer;
+  value : string;
+  fsettings : TFormatSettings;
+begin
+  try
+    value := AnsiDequotedStr(aValue,'"');
+    case aType of
+      tkString, tkLString, tkWString, tkUString :
+        begin
+          Result := value;
+        end;
+      tkChar, tkWChar :
+        begin
+          Result := value;
+        end;
+      tkInteger :
+        begin
+          Result := StrToInt(value);
+        end;
+      tkInt64 :
+        begin
+          Result := StrToInt64(value);
+        end;
+      tkFloat :
+        begin
+          if aTypeInfo = TypeInfo(TDateTime) then
+          begin
+            if CompareText(value,'null') <> 0 then Result := JsonDateToDateTime(value);
+          end
+          else if aTypeInfo = TypeInfo(TDate) then
+          begin
+            if CompareText(value,'null') <> 0 then Result := StrToDate(value);
+          end
+          else if aTypeInfo = TypeInfo(TTime) then
+          begin
+            Result := StrToTime(value);
+          end
+          else
+          begin
+            fsettings := TFormatSettings.Create;
+            Result := StrToFloat(StringReplace(value,'.',fsettings.DecimalSeparator,[]));
+          end;
+        end;
+      tkEnumeration :
+        begin
+          if aTypeInfo = System.TypeInfo(Boolean) then
+          begin
+            Result := StrToBool(value);
+          end
+          else
+          begin
+            //if fUseEnumNames then TValue.Make(GetEnumValue(aTypeInfo,value),aTypeInfo, Result)
+            //  else TValue.Make(StrToInt(value),aTypeInfo, Result);
+            if not TryStrToInt(value,i) then TValue.Make(GetEnumValue(aTypeInfo,value),aTypeInfo, Result)
+              else TValue.Make(StrToInt(value),aTypeInfo, Result);
+          end;
+        end;
+      tkSet :
+        begin
+          i := StringToSet(aTypeInfo,value);
+          TValue.Make(@i,aTypeInfo,Result);
+        end;
+    else
+        begin
+          //raise EclYamlSerializerError.Create('Not supported data type!');
+        end;
+    end;
+  except
+    on E : Exception do
+    begin
+      raise EYamlDeserializeError.CreateFmt('Deserialize error type "%s.%s" : %s',[aObject.ClassName,GetTypeName(aTypeInfo),e.Message]);
+    end;
+  end;
+end;
+{$ELSE}
+function TRTTIYaml.DeserializeType(aObject : TObject; aType : TTypeKind; const aPropertyName, aValue: string) : TValue;
+var
+  value : string;
+  propinfo : PPropInfo;
+  fsettings : TFormatSettings;
+begin
+  try
+    value := AnsiDequotedStr(aValue,'"');
+
+    if value = '' then
+    begin
+      Result := nil;
+      Exit;
+    end;
+    propinfo := GetPropInfo(aObject,aPropertyName);
+    //case propinfo.PropType.Kind of
+    case aType of
+      tkString, tkLString, tkWString, tkUString, tkAString :
+        begin
+          Result := value;
+          //SetStrProp(aObject,propinfo,value);
+        end;
+      tkChar, tkWChar :
+        begin
+          Result := value;
+        end;
+      tkInteger :
+        begin
+          Result := StrToInt(value);
+        end;
+      tkInt64 :
+        begin
+          Result := StrToInt64(value);
+        end;
+      tkFloat :
+        begin
+          if propinfo.PropType = TypeInfo(TDateTime) then
+          begin
+            if CompareText(value,'null') <> 0  then Result := JsonDateToDateTime(value);
+          end
+          else if propinfo.PropType = TypeInfo(TDate) then
+          begin
+            if CompareText(value,'null') <> 0 then Result := StrToDate(value);
+          end
+          else if propinfo.PropType = TypeInfo(TTime) then
+          begin
+            Result := StrToTime(value);
+          end
+          else
+          begin
+            fsettings := DefaultFormatSettings;
+            Result := StrToFloat(StringReplace(value,'.',fsettings.DecimalSeparator,[]));
+          end;
+        end;
+      tkEnumeration:
+        begin
+          Result := value;
+        end;
+      tkBool :
+          begin
+            Result := StrToBool(value);
+          end;
+      tkSet :
+        begin
+          Result := value;
+        end;
+    else
+        begin
+          //raise EclYamlSerializerError.Create('Not supported data type!');
+        end;
+    end;
+    //if not Result.IsEmpty then SetPropertyValue(aObject,propinfo,Result);
+  except
+    on E : Exception do
+    begin
+      raise EYamlDeserializeError.CreateFmt('Deserialize error type "%s" : %s',[aObject.ClassName,e.Message]);
+    end;
+  end;
+end;
+{$ENDIF}
+
+function TRTTIYaml.IsAllowedProperty(aObject : TObject; const aPropertyName : string) : Boolean;
+var
+  propname : string;
+begin
+  Result := True;
+  propname := aPropertyName.ToLower;
+  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 TRTTIYaml.IsGenericList(aObject : TObject) : Boolean;
+var
+  cname : string;
+begin
+  if aObject = nil then Exit(False);
+
+  cname := aObject.ClassName;
+  Result := (cname.StartsWith('TObjectList')) or (cname.StartsWith('TList'));
+end;
+
+function TRTTIYaml.IsGenericXArray(const aClassName : string) : Boolean;
+begin
+  Result := aClassName.StartsWith('TXArray');
+end;
+
+function TRTTIYaml.GetYamlPairByName(aYaml: TYamlObject; const aName: string): TYamlPair;
+var
+  candidate : TYamlPair;
+  yvalue : TYamlValue;
+  i : Integer;
+begin
+  if fUseYamlCaseSense then
+  begin
+    yvalue := aYaml.GetValue(aName);
+    if yvalue <> nil then Result := TYamlPair(yvalue);
+    Exit;
+  end
+  else
+  begin
+    if aYaml <> nil then
+    for i := 0 to aYaml.Count - 1 do
+    begin
+      candidate := aYaml.Pairs[I];
+      if (candidate = nil) or (candidate.Value = nil) then Exit(nil);
+      if CompareText(candidate.Name,aName) = 0 then
+        Exit(candidate);
+    end;
+  end;
+  Result := nil;
+end;
+
+function TRTTIYaml.GetPropertyValue(Instance : TObject; const PropertyName : string) : TValue;
+var
+  pinfo : PPropInfo;
+begin
+  Result := nil;
+  pinfo := GetPropInfo(Instance,PropertyName);
+  case pinfo.PropType^.Kind of
+    tkInteger : Result := GetOrdProp(Instance,pinfo);
+    tkInt64 : Result := GetInt64Prop(Instance,PropertyName);
+    tkFloat : Result := GetFloatProp(Instance,PropertyName);
+    tkChar : Result := Char(GetOrdProp(Instance,PropertyName));
+    {$IFDEF FPC}
+    tkWString : Result := GetWideStrProp(Instance,PropertyName);
+    tkSString,
+    tkAString,
+    {$ELSE}
+    tkWString,
+    {$ENDIF}
+    tkLString : Result := GetStrProp(Instance,pinfo);
+    {$IFDEF FPC}
+    tkEnumeration :
+      begin
+        if fUseEnumNames then Result := GetEnumName(pinfo.PropType,GetOrdProp(Instance,PropertyName))
+          else Result := GetOrdProp(Instance,PropertyName);
+      end;
+    {$ELSE}
+    tkEnumeration :
+      begin
+        if fUseEnumNames then Result := GetEnumName(@pinfo.PropType,GetOrdProp(Instance,PropertyName))
+          else Result := GetOrdProp(Instance,PropertyName);
+      end;
+    {$ENDIF}
+    tkSet : Result := GetSetProp(Instance,pinfo,True);
+    {$IFNDEF FPC}
+    tkClass :
+    {$ELSE}
+    tkBool : Result := Boolean(GetOrdProp(Instance,pinfo));
+    tkObject :
+    {$ENDIF} Result := GetObjectProp(Instance,pinfo);
+    tkDynArray : Result := GetDynArrayProp(Instance,pinfo);
+  end;
+end;
+
+function TRTTIYaml.GetPropertyValueFromObject(Instance : TObject; const PropertyName : string) : TValue;
+var
+  ctx : TRttiContext;
+  rprop : TRttiProperty;
+begin
+  rprop := ctx.GetType(Instance.ClassInfo).GetProperty(PropertyName);
+  Result := rprop.GetValue(Instance);
+end;
+
+{$IFNDEF FPC}
+function TRTTIYaml.GetFieldValueFromRecord(aValue : TValue; const FieldName : string) : TValue;
+var
+  ctx : TRttiContext;
+  rec : TRttiRecordType;
+  rfield : TRttiField;
+begin
+  rec := ctx.GetType(aValue.TypeInfo).AsRecord;
+  rfield := rec.GetField(FieldName);
+  if rfield <> nil then Result := rField.GetValue(aValue.GetReferenceToRawData)
+    else Result := nil;
+end;
+{$ENDIF}
+
+{$IFNDEF FPC}
+function TRTTIYaml.CreateInstance(aClass: TClass): TValue;
+var
+  ctx : TRttiContext;
+  rtype : TRttiType;
+begin
+  Result := nil;
+  rtype := ctx.GetType(aClass);
+  Result := CreateInstance(rtype);
+end;
+{$ENDIF}
+
+{$IFNDEF FPC}
+function TRTTIYaml.CreateInstance(aType: TRttiType): TValue;
+var
+  rmethod : TRttiMethod;
+begin
+  Result := nil;
+  if atype = nil then Exit;
+  for rmethod in TRttiInstanceType(atype).GetMethods do
+  begin
+    if rmethod.IsConstructor then
+    begin
+      //create if don't have parameters
+      if Length(rmethod.GetParameters) = 0 then
+      begin
+        Result := rmethod.Invoke(TRttiInstanceType(atype).MetaclassType,[]);
+        Break;
+      end;
+    end;
+  end;
+end;
+{$ENDIF}
+
+procedure TRTTIYaml.SetPropertyValue(Instance : TObject; const PropertyName : string; aValue : TValue);
+var
+  pinfo : PPropInfo;
+begin
+  pinfo := GetPropInfo(Instance,PropertyName);
+  SetPropertyValue(Instance,pinfo,aValue);
+end;
+
+procedure TRTTIYaml.SetPropertyValue(Instance : TObject; aPropInfo : PPropInfo; aValue : TValue);
+begin
+  case aPropInfo.PropType^.Kind of
+    tkInteger : SetOrdProp(Instance,aPropInfo,aValue.AsInteger);
+    tkInt64 : SetInt64Prop(Instance,aPropInfo,aValue.AsInt64);
+    tkFloat : SetFloatProp(Instance,aPropInfo,aValue.AsExtended);
+    tkChar : SetOrdProp(Instance,aPropInfo,aValue.AsOrdinal);
+    {$IFDEF FPC}
+    tkWString : SetWideStrProp(Instance,aPropInfo,aValue.AsString);
+    tkSString,
+    tkAString,
+    {$ELSE}
+    tkWString,
+    {$ENDIF}
+    tkLString : SetStrProp(Instance,aPropInfo,aValue.AsString);
+    {$IFDEF FPC}
+    tkBool : SetOrdProp(Instance,aPropInfo,aValue.AsOrdinal);
+    tkSet : LoadSetProperty(Instance,aPropInfo,aValue.AsString);
+    {$ENDIF}
+    tkEnumeration : SetEnumProp(Instance,aPropInfo,aValue.AsString);
+    {$IFNDEF FPC}
+    tkClass :
+    {$ELSE}
+    tkObject :
+    {$ENDIF} SetObjectProp(Instance,aPropInfo,aValue.AsObject);
+  end;
+end;
+
+{$IFDEF FPC}
+procedure TRTTIYaml.LoadSetProperty(aInstance : TObject; aPropInfo: PPropInfo; const aValue: string);
+type
+  TCardinalSet = set of 0..SizeOf(Cardinal) * 8 - 1;
+const
+  Delims = [' ', ',', '[', ']'];
+var
+  TypeInfo: PTypeInfo;
+  W: Cardinal;
+  I, N: Integer;
+  Count: Integer;
+  EnumName: string;
+begin
+  W := 0;
+  TypeInfo := GetTypeData(GetPropType(aPropInfo))^.CompType;
+  Count := WordCount(aValue, Delims);
+  for N := 1 to Count do
+  begin
+    EnumName := ExtractWord(N, aValue, Delims);
+    try
+      I := GetEnumValue(TypeInfo, EnumName);
+      if I >= 0 then Include(TCardinalSet(W),I);
+    except
+    end;
+  end;
+  SetOrdProp(aInstance,aPropInfo,W);
+end;
+{$ENDIF}
+
+function TRTTIYaml.Serialize(aObject: TObject): TYamlObject;
+var
+  ctx: TRttiContext;
+  {$IFNDEF FPC}
+  attr : TCustomAttribute;
+  comment : string;
+  {$ENDIF}
+  rType: TRttiType;
+  rProp: TRttiProperty;
+  ypair : TYamlPair;
+  ExcludeSerialize : Boolean;
+  propertyname : string;
+begin
+  if (aObject = nil) then
+  begin
+    Result := nil;
+    Exit;
+  end;
+
+  Result := TYamlObject.Create;
+  try
+    rType := ctx.GetType(aObject.ClassInfo);
+    try
+      //s := rType.ToString;
+      for rProp in TRTTI.GetProperties(rType,roFirstBase) do
+      begin
+        ExcludeSerialize := False;
+        propertyname := rProp.Name;
+        {$IFNDEF FPC}
+        comment := '';
+        for attr in rProp.GetAttributes do
+        begin
+          if attr is TNotSerializableProperty then ExcludeSerialize := True
+          else if attr is TCommentProperty then comment := TCommentProperty(attr).Comment
+          else if  attr is TCustomNameProperty then propertyname := TCustomNameProperty(attr).Name;
+        end;
+        if ((fSerializeLevel = slPublicProperty) and (rProp.PropertyType.IsPublicType))
+            or ((fSerializeLevel = slPublishedProperty) and ((IsPublishedProp(aObject,rProp.Name)) or (rProp.Name = 'List'))) then
+        {$ENDIF}
+        begin
+          if (IsAllowedProperty(aObject,propertyname)) and (not ExcludeSerialize) then
+          begin
+            //add comment as pair
+            {$IFNDEF FPC}
+            if comment <> '' then Result.AddPair(TYamlPair.Create('#',TYamlComment.Create(Comment)));
+            {$ENDIF}
+            begin
+              if (rProp.GetValue(aObject).IsObject) and (IsGenericList(rProp.GetValue(aObject).AsObject)) then
+              begin
+                ypair := Serialize(propertyname,GetPropertyValueFromObject(rProp.GetValue(aObject).AsObject,'List'));
+              end
+              {$IFNDEF FPC}
+              else if (not rProp.GetValue(aObject).IsObject) and (IsGenericXArray(rProp.GetValue(aObject){$IFNDEF NEXTGEN}.TypeInfo.Name{$ELSE}.TypeInfo.NameFld.ToString{$ENDIF})) then
+              begin
+                ypair := Serialize(propertyname,GetFieldValueFromRecord(rProp.GetValue(aObject),'fArray'));
+              end
+              {$ENDIF}
+              else
+              begin
+                {$IFNDEF FPC}
+                ypair := Serialize(propertyname,rProp.GetValue(aObject));
+                {$ELSE}
+                ypair := Serialize(aObject,rProp.PropertyType.TypeKind,propertyname);
+                {$ENDIF}
+              end;
+              //s := jpair.YamlValue.ToString;
+              if ypair <> nil then
+              begin
+                Result.AddPair(ypair);
+              end
+              else ypair.Free;
+            end;
+            //Result.AddPair(Serialize(rProp.Name,rProp.GetValue(aObject)));
+            //s := Result.ToYaml;
+          end;
+        end;
+      end;
+    finally
+      ctx.Free;
+    end;
+  except
+    on E : Exception do
+    begin
+      Result.Free;
+      raise EYamlSerializeError.CreateFmt('Serialize error object "%s" : %s',[aObject.ClassName,e.Message]);
+    end;
+  end;
+end;
+
+function TRTTIYaml.GetValue(aAddr: Pointer; aType: TRTTIType): TValue;
+begin
+  TValue.Make(aAddr,aType.Handle,Result);
+end;
+
+function TRTTIYaml.GetValue(aAddr: Pointer; aTypeInfo: PTypeInfo): TValue;
+begin
+  TValue.Make(aAddr,aTypeInfo,Result);
+end;
+
+{$IFNDEF FPC}
+function TRTTIYaml.Serialize(const aName : string; aValue : TValue) : TYamlPair;
+var
+  ctx: TRttiContext;
+  rRec : TRttiRecordType;
+  rField : TRttiField;
+  rDynArray : TRTTIDynamicArrayType;
+  Yaml : TYamlObject;
+  yArray : TYamlArray;
+  ypair : TYamlPair;
+  yvalue : TYamlValue;
+  i : Integer;
+begin
+  Result := TYamlPair.Create(aName,nil);
+  //Result.YamlString := TYamlString(aName);
+  try
+    case avalue.Kind of
+      tkDynArray :
+        begin
+          yArray := TYamlArray.Create;
+          rDynArray := ctx.GetType(aValue.TypeInfo) as TRTTIDynamicArrayType;
+          try
+            for i := 0 to aValue.GetArrayLength - 1 do
+            begin
+              if not GetValue(PPByte(aValue.GetReferenceToRawData)^ + rDynArray.ElementType.TypeSize * i, rDynArray.ElementType).IsEmpty then
+              begin
+                yvalue := nil;
+                ypair := Serialize(aName,GetValue(PPByte(aValue.GetReferenceToRawData)^ + rDynArray.ElementType.TypeSize * i, rDynArray.ElementType));
+                try
+                  //jValue := TYamlValue(jPair.YamlValue.Clone);
+                  yvalue := ypair.Value;
+                  if yvalue <> nil then
+                  begin
+                    yArray.AddElement(yvalue);
+                    ypair.Value.Owned := False;
+                  end;
+                finally
+                  ypair.Free;
+                  if yvalue <> nil then yvalue.Owned := True;
+                end;
+              end;
+            end;
+            Result.Value := yArray;
+          finally
+            ctx.Free;
+          end;
+        end;
+      tkClass :
+        begin
+           Result.Value := TYamlValue(Serialize(aValue.AsObject));
+        end;
+      tkString, tkLString, tkWString, tkUString :
+        begin
+          Result.Value := TYamlString.Create(aValue.AsString);
+        end;
+      tkChar, tkWChar :
+        begin
+          Result.Value := TYamlString.Create(aValue.AsString);
+        end;
+      tkInteger :
+        begin
+          Result.Value := TYamlInteger.Create(aValue.AsInteger);
+        end;
+      tkInt64 :
+        begin
+          Result.Value := TYamlInteger.Create(aValue.AsInt64);
+        end;
+      tkFloat :
+        begin
+          if aValue.TypeInfo = TypeInfo(TDateTime) then
+          begin
+            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateTimeToJsonDate(aValue.AsExtended));
+          end
+          else if aValue.TypeInfo = TypeInfo(TDate) then
+          begin
+            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateToStr(aValue.AsExtended));
+          end
+          else if aValue.TypeInfo = TypeInfo(TTime) then
+          begin
+            Result.Value := TYamlString.Create(TimeToStr(aValue.AsExtended));
+          end
+          else
+          begin
+            Result.Value := TYamlFloat.Create(aValue.AsExtended);
+          end;
+        end;
+      tkEnumeration :
+        begin
+          if (aValue.TypeInfo = System.TypeInfo(Boolean)) then
+          begin
+            Result.Value := TYamlBoolean.Create(aValue.AsBoolean);
+          end
+          else
+          begin
+            //Result.YamlValue := TYamlString.Create(GetEnumName(aValue.TypeInfo,aValue.AsOrdinal));
+            if fUseEnumNames then Result.Value := TYamlString.Create(aValue.ToString)
+              else Result.Value := TYamlInteger.Create(GetEnumValue(aValue.TypeInfo,aValue.ToString));
+          end;
+        end;
+      tkSet :
+        begin
+          Result.Value := TYamlString.Create(aValue.ToString);
+        end;
+      tkRecord :
+        begin
+          rRec := ctx.GetType(aValue.TypeInfo).AsRecord;
+          try
+            Yaml := TYamlObject.Create;
+            for rField in rRec.GetFields do
+            begin
+              Yaml.AddPair(Serialize(rField.name,rField.GetValue(aValue.GetReferenceToRawData)));
+            end;
+            Result.Value := Yaml;
+          finally
+            ctx.Free;
+          end;
+        end;
+      tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
+        begin
+          //skip these properties
+          //FreeAndNil(Result);
+        end
+    else
+      begin
+        raise EYamlSerializeError.CreateFmt(cNotSupportedDataType,[aName,GetTypeName(aValue.TypeInfo)]);
+      end;
+    end;
+    if Result.Value = nil then Result.Value := TYamlNull.Create;
+  except
+    on E : Exception do
+    begin
+      Result.Free;
+      raise EYamlSerializeError.CreateFmt('Serialize error class "%s.%s" : %s',[aName,aValue.ToString,e.Message]);
+    end;
+  end;
+end;
+{$ELSE}
+function TRTTIYaml.GetPropType(aPropInfo: PPropInfo): PTypeInfo;
+begin
+  Result := aPropInfo^.PropType;
+end;
+
+function TRTTIYaml.FloatProperty(aObject : TObject; aPropInfo: PPropInfo): string;
+const
+  Precisions: array[TFloatType] of Integer = (7, 15, 18, 18, 19);
+var
+  fsettings : TFormatSettings;
+begin
+  fsettings := FormatSettings;
+  Result := StringReplace(FloatToStrF(GetFloatProp(aObject, aPropInfo), ffGeneral,
+    Precisions[GetTypeData(GetPropType(aPropInfo))^.FloatType],0),
+    '.',fsettings.DecimalSeparator,[rfReplaceAll]);
+end;
+
+function TRTTIYaml.Serialize(const aName : string; aValue : TValue) : TYamlPair;
+begin
+  Result := TYamlPair.Create(aName,nil);
+  //Result.YamlString := TYamlString(aName);
+  try
+    case avalue.Kind of
+      tkClass :
+        begin
+           Result.Value := TYamlValue(Serialize(aValue.AsObject));
+        end;
+      tkString, tkLString, tkWString, tkUString :
+        begin
+          Result.Value := TYamlString.Create(aValue.AsString);
+        end;
+      tkChar, tkWChar :
+        begin
+          Result.Value := TYamlString.Create(aValue.AsString);
+        end;
+      tkInteger :
+        begin
+          Result.Value := TYamlInteger.Create(aValue.AsInteger);
+        end;
+      tkInt64 :
+        begin
+          Result.Value := TYamlInteger.Create(aValue.AsInt64);
+        end;
+      tkFloat :
+        begin
+          if aValue.TypeInfo = TypeInfo(TDateTime) then
+          begin
+            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateTimeToJsonDate(aValue.AsExtended));
+          end
+          else if aValue.TypeInfo = TypeInfo(TDate) then
+          begin
+            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateToStr(aValue.AsExtended));
+          end
+          else if aValue.TypeInfo = TypeInfo(TTime) then
+          begin
+            Result.Value := TYamlString.Create(TimeToStr(aValue.AsExtended));
+          end
+          else
+          begin
+            Result.Value := TYamlFloat.Create(aValue.AsExtended);
+          end;
+        end;
+      tkEnumeration :
+        begin
+          if (aValue.TypeInfo = System.TypeInfo(Boolean)) then
+          begin
+            Result.Value := TYamlBoolean.Create(aValue.AsBoolean);
+          end
+          else
+          begin
+            //Result.YamlValue := TYamlString.Create(GetEnumName(aValue.TypeInfo,aValue.AsOrdinal));
+            if fUseEnumNames then Result.Value := TYamlString.Create(aValue.ToString)
+              else Result.Value := TYamlInteger.Create(GetEnumValue(aValue.TypeInfo,aValue.ToString));
+          end;
+        end;
+      tkSet :
+        begin
+          Result.Value := TYamlString.Create(aValue.ToString);
+        end;
+    else
+      begin
+        //raise EYamlDeserializeError.CreateFmt('Not supported type "%s":%d',[aName,Integer(aValue.Kind)]);
+      end;
+    end;
+    if Result.Value = nil then Result.Value := TYamlNull.Create;
+  except
+    Result.Free;
+  end;
+end;
+
+function TRTTIYaml.Serialize(aObject : TObject; aType : TTypeKind; const aPropertyName : string) : TYamlPair;
+var
+  propinfo : PPropInfo;
+  yArray : TYamlArray;
+  ypair : TYamlPair;
+  yvalue : TYamlValue;
+  i : Integer;
+  pArr : Pointer;
+  rValue : TValue;
+  rItemValue : TValue;
+  len : Integer;
+begin
+  try
+    Result := TYamlPair.Create(aPropertyName,nil);
+
+    propinfo := GetPropInfo(aObject,aPropertyName);
+    //case propinfo.PropType.Kind of
+    case aType of
+      tkDynArray :
+        begin
+          len := 0;
+          yArray := TYamlArray.Create;
+          try
+            pArr := GetDynArrayProp(aObject,aPropertyName);
+            TValue.Make(@pArr,propinfo.PropType, rValue);
+            if rValue.IsArray then
+            begin
+              len := rValue.GetArrayLength;
+              for i := 0 to len - 1 do
+              begin
+                rItemValue := rValue.GetArrayElement(i);
+                ypair := Serialize(aPropertyName,rItemValue);
+                try
+                  //jValue := TYamlValue(jPair.YamlValue.Clone);
+                  yvalue := ypair.Value;
+                  yArray.AddElement(yvalue);
+                  //jPair.YamlValue.Owned := False;
+                finally
+                  ypair.Free;
+                  //jValue.Owned := True;
+                end;
+              end;
+            end;
+            Result.Value := yArray;
+          finally
+            //DynArrayClear(pArr,propinfo.PropType);
+            pArr := nil;
+          end;
+        end;
+      tkClass :
+        begin
+          Result.Value := TYamlValue(Serialize(GetObjectProp(aObject,aPropertyName)));
+        end;
+      tkString, tkLString, tkWString, tkUString, tkAString :
+        begin
+          Result.Value := TYamlString.Create(GetStrProp(aObject,aPropertyName));
+        end;
+      tkChar, tkWChar :
+        begin
+          Result.Value := TYamlString.Create(Char(GetOrdProp(aObject,aPropertyName)));
+        end;
+      tkInteger :
+        begin
+          Result.Value := TYamlInteger.Create(GetOrdProp(aObject,aPropertyName));
+        end;
+      tkInt64 :
+        begin
+          Result.Value := TYamlInteger.Create(GetOrdProp(aObject,aPropertyName));
+        end;
+      tkFloat :
+        begin
+          if propinfo.PropType = TypeInfo(TDateTime) then
+          begin
+            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateTimeToJsonDate(GetFloatProp(aObject,aPropertyName)));
+          end
+          else if propinfo.PropType = TypeInfo(TDate) then
+          begin
+            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateToStr(GetFloatProp(aObject,aPropertyName)));
+          end
+          else if propinfo.PropType = TypeInfo(TTime) then
+          begin
+            Result.Value := TYamlString.Create(TimeToStr(GetFloatProp(aObject,aPropertyName)));
+          end
+          else
+          begin
+            //Result.YamlValue := TYamlFloatNumber.Create(GetFloatProp(aObject,aPropertyName));
+            Result.Value := TYamlFloat.Create(StrToFloat(FloatProperty(aObject,propinfo)));
+          end;
+        end;
+      tkEnumeration,tkBool :
+        begin
+          if (propinfo.PropType = System.TypeInfo(Boolean)) then
+          begin
+            Result.Value := TYamlBoolean.Create(Boolean(GetOrdProp(aObject,aPropertyName)));
+          end
+          else
+          begin
+            if fUseEnumNames then Result.Value := TYamlString.Create(GetEnumName(propinfo.PropType,GetOrdProp(aObject,aPropertyName)))
+              else Result.Value := TYamlInteger.Create(GetOrdProp(aObject,aPropertyName));
+            //Result.YamlValue := TYamlString.Create(aValue.ToString);
+          end;
+        end;
+      tkSet :
+        begin
+          Result.Value := TYamlString.Create(GetSetProp(aObject,aPropertyName));
+        end;
+      {$IFNDEF FPC}
+      tkRecord :
+        begin
+          rRec := ctx.GetType(aValue.TypeInfo).AsRecord;
+          try
+            Yaml := TYamlObject.Create;
+            for rField in rRec.GetFields do
+            begin
+              Yaml.AddPair(Serialize(rField.name,rField.GetValue(aValue.GetReferenceToRawData)));
+            end;
+            Result.YamlValue := Yaml;
+          finally
+            ctx.Free;
+          end;
+        end;
+      {$ENDIF}
+      tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
+        begin
+          //skip these properties
+          //FreeAndNil(Result);
+        end
+    else
+      begin
+
+        //raise EYamlDeserializeError.CreateFmt('Not supported type "%s":%d',[aName,Integer(aValue.Kind)]);
+      end;
+    end;
+    if Result.Value = nil then Result.Value := TYamlNull.Create;
+  except
+    on E : Exception do
+    begin
+      Result.Free;
+      {$IFNDEF FPC}
+      raise EYamlSerializeError.CreateFmt('Serialize error class "%s.%s" : %s',[aName,aValue.ToString,e.Message]);
+      {$ENDIF}
+    end;
+  end;
+end;
+{$ENDIF}
+
+
+{ TYamlSerializer}
+
+constructor TYamlSerializer.Create(aSerializeLevel: TSerializeLevel; aUseEnumNames : Boolean = True);
+begin
+  {$IFDEF FPC}
+  if aSerializeLevel = TSerializeLevel.slPublicProperty then raise EYamlSerializeError.Create('FreePascal RTTI only supports published properties');
+  {$ENDIF}
+  fSerializeLevel := aSerializeLevel;
+  fUseEnumNames := aUseEnumNames;
+  fUseYamlCaseSense := False;
+  fRTTIYaml := TRTTIYaml.Create(aSerializeLevel,aUseEnumNames);
+  fRTTIYaml.UseYamlCaseSense := fUseYamlCaseSense;
+end;
+
+function TYamlSerializer.YamlToObject(aType: TClass; const aYaml: string): TObject;
+var
+  Yaml: TYamlObject;
+begin
+  Yaml := TYamlObject.ParseYamlValue(aYaml) as TYamlObject;
+  try
+    Result := fRTTIYaml.DeserializeClass(aType,Yaml);
+  finally
+    Yaml.Free;
+  end;
+end;
+
+destructor TYamlSerializer.Destroy;
+begin
+  fRTTIYaml.Free;
+  inherited;
+end;
+
+function TYamlSerializer.YamlToObject(aObject: TObject; const aYaml: string): TObject;
+var
+  Yaml: TYamlObject;
+begin
+  Result := aObject;
+  Yaml := TYamlObject(TYamlObject.ParseYamlValue(aYaml));
+  try
+    fRTTIYaml.DeserializeObject(aObject,Yaml);
+  finally
+    Yaml.Free;
+  end;
+end;
+
+function TYamlSerializer.ObjectToYaml(aObject : TObject): string;
+var
+  Yaml: TYamlObject;
+begin
+  Yaml := fRTTIYaml.Serialize(aObject);
+  try
+    Result := Yaml.ToYaml;
+  finally
+    Yaml.Free;
+  end;
+end;
+
+procedure TYamlSerializer.SetSerializeLevel(const Value: TSerializeLevel);
+begin
+  fSerializeLevel := Value;
+  if Assigned(fRTTIYaml) then fRTTIYaml.fSerializeLevel := Value;
+end;
+
+procedure TYamlSerializer.SetUseEnumNames(const Value: Boolean);
+begin
+  fUseEnumNames := Value;
+  if Assigned(fRTTIYaml) then fRTTIYaml.UseEnumNames := Value;
+end;
+
+procedure TYamlSerializer.SetUseYamlCaseSense(const Value: Boolean);
+begin
+  fUseYamlCaseSense := Value;
+  if Assigned(fRTTIYaml) then fRTTIYaml.UseYamlCaseSense := Value;
+end;
+
+{$IFNDEF FPC}
+{ TCommentProperty }
+
+constructor TCommentProperty.Create(const aComment: string);
+begin
+  fComment := aComment;
+end;
+
+{ TCustomNameProperty }
+
+constructor TCustomNameProperty.Create(const aName: string);
+begin
+  fName := aName;
+end;
+{$ENDIF}
+
+
+end.
+
+
+
+