Browse Source

New Quick.YAML.Serializer

Unknown 6 years ago
parent
commit
2f44e2ac94
1 changed files with 1569 additions and 0 deletions
  1. 1569 0
      Quick.YAML.Serializer.pas

+ 1569 - 0
Quick.YAML.Serializer.pas

@@ -0,0 +1,1569 @@
+{ ***************************************************************************
+
+  Copyright (c) 2015-2019 Kike Pérez
+
+  Unit        : Quick.YAML.Serializer
+  Description : YAML Serializer
+  Author      : Kike Pérez
+  Version     : 1.0
+  Created     : 12/04/2019
+  Modified    : 27/04/2019
+
+  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 DELPHIRX103_UP}
+    System.Generics.Collections,
+    {$ENDIF}
+  {$ENDIF}
+  DateUtils,
+  Quick.Commons,
+  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);
+  public
+    constructor Create(aSerializeLevel: TSerializeLevel; aUseEnumNames : Boolean = True);
+    destructor Destroy; override;
+    property SerializeLevel : TSerializeLevel read fSerializeLevel;
+    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;
+                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 DELPHIRX103_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;
+
+  Result := aType.Create;
+  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;
+      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;
+        {$ENDIF}
+      else
+        begin
+          {$IFNDEF FPC}
+          //avoid return unicode escaped chars if string
+          if aProperty.PropertyType.TypeKind in [tkString, tkLString, tkWString, tkUString] then
+            {$IFDEF DELPHIRX103_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 value <> 'null' then Result := JsonDateToDateTime(value);
+          end
+          else if aTypeInfo = TypeInfo(TDate) then
+          begin
+            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
+            Result := JsonDateToDateTime(value);
+          end
+          else if propinfo.PropType = TypeInfo(TDate) then
+          begin
+            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.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 rType.GetProperties 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
+            Result.Value := TYamlString.Create(DateTimeToJsonDate(aValue.AsExtended));
+          end
+          else if aValue.TypeInfo = TypeInfo(TDate) then
+          begin
+            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
+            Result.Value := TYamlString.Create(DateTimeToJsonDate(aValue.AsExtended));
+          end
+          else if aValue.TypeInfo = TypeInfo(TDate) then
+          begin
+            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
+            Result.Value := TYamlString.Create(DateTimeToJsonDate(GetFloatProp(aObject,aPropertyName)));
+          end
+          else if propinfo.PropType = TypeInfo(TDate) then
+          begin
+            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
+    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
+  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.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.
+
+
+
+