+unit JsonDataObjectUnmarshall;
+ JSONNameAttribute = class(TCustomAttribute)
+ constructor Create(const name: string);
+ property Name: string read fName;
+ JSONClassAttribute = class(TCustomAttribute)
+ constructor Create(itemClass: TClass);
+ property ItemClass: TClass read fItemClass;
+procedure Unmarshall(const obj: TObject; const data: string); overload;
+constructor JSONNameAttribute.Create(const name: string);
+constructor JSONClassAttribute.Create(itemClass: TClass);
+ fItemClass := itemClass;
+procedure Unmarshall(const obj: TObject; const jsonObj: TJsonObject); overload;
+ function FieldByJsonName(t: TRttiType; const name: string): TRttiField;
+ for Result in t.GetFields do
+ for a in Result.GetAttributes do
+ if (a is JSONNameAttribute) and (JSONNameAttribute(a).Name = name) then
+ function GetClassByAttribute(f: TRttiField): TClass;
+ for a in f.GetAttributes do
+ if a is JSONClassAttribute then
+ Exit(JSONClassAttribute(a).ItemClass);
+ function GetDefaultCtor(t: TRttiType): TRttiMethod;
+ for Result in t.GetMethods do
+ if (Result.MethodKind = mkConstructor) and (Length(Result.GetParameters) = 0) then
+ t := ctx.GetType(obj.ClassInfo);
+ for i := 0 to jsonObj.Count - 1 do
+ f := FieldByJsonName(t, jsonObj.Names[i]);
+ item := jsonObj.Items[i];
+ // TODO: support all kinds of types
+ case f.FieldType.TypeKind of
+ subObj := f.GetValue(obj).AsObject;
+ Unmarshall(subObj, item.ObjectValue)
+ itemClass := GetClassByAttribute(f);
+ if itemClass <> nil then
+ ctor := GetDefaultCtor(ctx.GetType(itemClass));
+ subObj := ctor.Invoke(itemClass, []).AsObject;
+ Unmarshall(subObj, item.ObjectValue);
+ f.SetValue(obj, subObj);
+ subIntf := f.GetValue(obj).AsInterface;
+ Unmarshall(subIntf as TObject, item.ObjectValue)
+ itemClass := GetClassByAttribute(f);
+ if itemClass <> nil then
+ ctor := GetDefaultCtor(ctx.GetType(itemClass));
+ subObj := ctor.Invoke(itemClass, []).AsObject;
+ Unmarshall(subObj, item.ObjectValue);
+ subObj.GetInterface(TRttiInterfaceType(f.FieldType).GUID, subIntf);
+ TValue.Make(@subIntf, f.FieldType.Handle, v);
+ jdtString: f.SetValue(obj, item.Value);
+procedure Unmarshall(const obj: TObject; const data: string); overload;
+ jsonObj := TJsonObject.Parse(data) as TJsonObject;
+ Unmarshall(obj, jsonObj);