Quick.AutoMapper.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. { ***************************************************************************
  2. Copyright (c) 2015-2018 Kike Pérez
  3. Unit : Quick.AutoMapper
  4. Description : Auto Mapper object properties
  5. Author : Kike Pérez
  6. Version : 1.5
  7. Created : 25/08/2018
  8. Modified : 16/10/2019
  9. This file is part of QuickLib: https://github.com/exilon/QuickLib
  10. ***************************************************************************
  11. Licensed under the Apache License, Version 2.0 (the "License");
  12. you may not use this file except in compliance with the License.
  13. You may obtain a copy of the License at
  14. http://www.apache.org/licenses/LICENSE-2.0
  15. Unless required by applicable law or agreed to in writing, software
  16. distributed under the License is distributed on an "AS IS" BASIS,
  17. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. See the License for the specific language governing permissions and
  19. limitations under the License.
  20. *************************************************************************** }
  21. unit Quick.AutoMapper;
  22. {$i QuickLib.inc}
  23. interface
  24. uses
  25. SysUtils,
  26. Generics.Collections,
  27. typinfo,
  28. Quick.Value,
  29. {$IFDEF FPC}
  30. Variants,
  31. {$ENDIF}
  32. RTTI,
  33. Quick.RTTI.Utils;
  34. //enable use of property paths (like namespaces) in custom mapping
  35. {$DEFINE PROPERTYPATH_MODE}
  36. type
  37. {$IFNDEF FPC}
  38. TFlexValue = TValue;
  39. {$ELSE}
  40. TFlexValue = variant;
  41. {$ENDIF}
  42. {$IFNDEF FPC}
  43. TMappingProc<TClass1> = reference to procedure(const aSrcObj : TClass1; const aTargetName : string; out Value : TFlexValue);
  44. TAfterMappingProc<TClass1,TClass2> = reference to procedure(const aSrcObj : TClass1; aTgtObj : TClass2);
  45. {$ELSE}
  46. TMappingProc<TObject> = procedure(const aSrcObj : TObject; const aTargetName : string; out Value : TFlexValue) of object;
  47. TAfterMappingProc<TClass1,TClass2> = procedure(const aSrcObj : TClass1; aTgtObj : TClass2) of object;
  48. {$ENDIF}
  49. TCustomMapping = class
  50. private
  51. fMapDictionary : TDictionary<string,string>;
  52. public
  53. constructor Create;
  54. destructor Destroy; override;
  55. procedure AddMap(const aName, aMapName : string);
  56. function GetMap(const aName : string; out vMapName : string) : Boolean;
  57. end;
  58. TObjMapper = class
  59. public
  60. class procedure Map(aSrcObj : TObject; aTgtObj : TObject; aCustomMapping: TCustomMapping = nil); overload;
  61. {$IFNDEF FPC}
  62. class procedure Map<Tm>(aSrcObj : TObject; aTgtObj : TObject; aDoMappingProc : TMappingProc<Tm>; aCustomMapping: TCustomMapping = nil); overload;
  63. {$ELSE}
  64. class procedure Map(aSrcObj : TObject; aTgtObj : TObject; aDoMappingProc : TMappingProc<TObject>; aCustomMapping: TCustomMapping = nil); overload;
  65. {$ENDIF}
  66. end;
  67. TListMapper = class
  68. public
  69. class procedure Map(aSrcList, aTgtList: TObject; aCustomMapping: TCustomMapping);
  70. end;
  71. TObjListMapper = class
  72. public
  73. class procedure Map(aSrcObjList : TObject; aTgtObjList : TObject; aCustomMapping : TCustomMapping = nil); overload;
  74. {$IFNDEF FPC}
  75. class procedure Map<Tm>(aSrcObjList : TObject; aTgtObjList : TObject; aDoMappingProc : TMappingProc<Tm>; aCustomMapping : TCustomMapping = nil); overload;
  76. {$ELSE}
  77. class procedure Map(aSrcObjList : TObject; aTgtObjList : TObject; aDoMappingProc : TMappingProc<TObject>; aCustomMapping : TCustomMapping = nil); overload;
  78. {$ENDIF}
  79. end;
  80. {$IFNDEF FPC}
  81. TMapper = class
  82. public
  83. class function Map<T : class, constructor>(aSrcObj : TObject) : T;
  84. end;
  85. {$ENDIF}
  86. TMapper<T : class, constructor> = class
  87. public
  88. class function Map(aSrcObj : TObject; aCustomMapping: TCustomMapping = nil): T; overload;
  89. class procedure Map(aSrcObj : TObject; aTgtObj : T; aCustomMapping : TCustomMapping = nil); overload;
  90. {$IFNDEF FPC}
  91. class function Map<Tm>(aSrcObj : TObject; aDoMappingProc : TMappingProc<Tm>; aCustomMapping: TCustomMapping = nil): T; overload;
  92. class procedure Map<Tm>(aSrcObj : TObject; aTgtObj : T; aDoMappingProc : TMappingProc<Tm>; aCustomMapping: TCustomMapping = nil); overload;
  93. {$ELSE}
  94. class function Map(aSrcObj : TObject; aDoMappingProc : TMappingProc<TObject>; aCustomMapping: TCustomMapping = nil): T; overload;
  95. class procedure Map(aSrcObj : TObject; aTgtObj : T; aDoMappingProc : TMappingProc<TObject>; aCustomMapping: TCustomMapping);
  96. {$ENDIF}
  97. end;
  98. IAutoMapper<TClass1, TClass2 : class, constructor> = interface['{9F7B2DEA-76D8-4DD1-95D0-22C22AEB5DD0}']
  99. function Map(aSrcObj : TClass1) : TClass2; overload;
  100. {$IFNDEF FPC}
  101. function Map(aSrcObj : TClass2) : TClass1; overload;
  102. procedure SetOnDoMapping(CustomProc : TMappingProc<TClass1>);
  103. procedure SetOnAfterMapping(CustomProc : TAfterMappingProc<TClass1,TClass2>);
  104. {$ELSE}
  105. //freepascal detects overload with generic types as duplicated function, added dummy field to avoid this
  106. function Map(aSrcObj : TClass2; dummy : Boolean = True) : TClass1; overload;
  107. {$ENDIF}
  108. end;
  109. TAutoMapper<TClass1, TClass2 : class, constructor> = class(TInterfacedObject, IAutoMapper<TClass1, TClass2>)
  110. private
  111. fCustomMapping : TCustomMapping;
  112. {$IFNDEF FPC}
  113. fOnDoMapping : TMappingProc<TClass1>;
  114. {$ELSE}
  115. fOnDoMapping : TMappingProc<TObject>;
  116. {$ENDIF}
  117. fOnAfterMapping : TAfterMappingProc<TClass1,TClass2>;
  118. public
  119. constructor Create;
  120. destructor Destroy; override;
  121. property CustomMapping : TCustomMapping read fCustomMapping write fCustomMapping;
  122. {$IFNDEF FPC}
  123. property OnDoMapping : TMappingProc<TClass1> read fOnDoMapping write fOnDoMapping;
  124. {$ELSE}
  125. property OnDoMapping : TMappingProc<TObject> read fOnDoMapping write fOnDoMapping;
  126. {$ENDIF}
  127. property OnAfterMapping : TAfterMappingProc<TClass1,TClass2> read fOnAfterMapping write fOnAfterMapping;
  128. function Map(aSrcObj : TClass1) : TClass2; overload;
  129. {$IFNDEF FPC}
  130. function Map(aSrcObj : TClass2) : TClass1; overload;
  131. procedure SetOnDoMapping(CustomProc : TMappingProc<TClass1>);
  132. procedure SetOnAfterMapping(CustomProc : TAfterMappingProc<TClass1,TClass2>);
  133. {$ELSE}
  134. //freepascal detects overload with generic types as duplicated function, added dummy field to avoid this
  135. function Map(aSrcObj : TClass2; dummy : Boolean = True) : TClass1; overload;
  136. {$ENDIF}
  137. end;
  138. EAutoMapperError = class(Exception);
  139. implementation
  140. { TObjMapper }
  141. class procedure TObjMapper.Map(aSrcObj : TObject; aTgtObj : TObject; aCustomMapping: TCustomMapping = nil);
  142. begin
  143. Map{$IFNDEF FPC}<TObject>{$ENDIF}(aSrcObj,aTgtObj,nil,aCustomMapping);
  144. end;
  145. {$IFNDEF FPC}
  146. class procedure TObjMapper.Map<Tm>(aSrcObj : TObject; aTgtObj : TObject; aDoMappingProc : TMappingProc<Tm>; aCustomMapping: TCustomMapping = nil);
  147. {$ELSE}
  148. class procedure TObjMapper.Map(aSrcObj : TObject; aTgtObj : TObject; aDoMappingProc : TMappingProc<TObject>; aCustomMapping: TCustomMapping = nil);
  149. {$ENDIF}
  150. var
  151. ctx : TRttiContext;
  152. rType : TRttiType;
  153. tgtprop : TRttiProperty;
  154. mapname : string;
  155. obj : TObject;
  156. manualmapping : Boolean;
  157. value : TFlexValue;
  158. {$IFNDEF FPC}
  159. clname : string;
  160. objvalue : TValue;
  161. {$ENDIF}
  162. begin
  163. //if aTgtObj = nil then aTgtObj := GetTypeData(aTgtObj.ClassInfo).classType.Create;
  164. if aTgtObj = nil then raise EAutoMapperError.Create('TObjMapper: Target Object passed must be created before');
  165. {$IFNDEF FPC}
  166. objvalue := TValue.From(aSrcObj);
  167. {$ENDIF}
  168. rType := ctx.GetType(aSrcObj.ClassInfo);
  169. for tgtprop in ctx.GetType(aTgtObj.ClassInfo).GetProperties do
  170. begin
  171. if tgtprop.IsWritable then
  172. begin
  173. if not tgtprop.PropertyType.IsInstance then
  174. begin
  175. if Assigned(aCustomMapping) and (not Assigned(aDoMappingProc)) then
  176. begin
  177. if aCustomMapping.GetMap(tgtprop.Name,mapname) then
  178. begin
  179. {$IFNDEF PROPERTYPATH_MODE}
  180. if rType.GetProperty(mapname) = nil then raise EAutoMapperError.CreateFmt('No valid custom mapping (Source: %s - Target: %s)',[mapname,tgtprop.Name]);
  181. {$IFNDEF FPC}
  182. tgtprop.SetValue(aTgtObj,rType.GetProperty(mapname).GetValue(aSrcObj))
  183. {$ELSE}
  184. SetPropValue(aTgtObj,tgtprop.Name,GetPropValue(aSrcObj,mapname));
  185. {$ENDIF}
  186. {$ELSE}
  187. if not TRTTI.PathExists(aSrcObj,mapname) then raise EAutoMapperError.CreateFmt('No valid custom mapping (Source: %s - Target: %s)',[mapname,tgtprop.Name]);
  188. TRTTI.SetPathValue(aTgtObj,tgtprop.Name,TRTTI.GetPathValue(aSrcObj,mapname));
  189. {$ENDIF}
  190. end
  191. else
  192. begin
  193. if rType.GetProperty(tgtprop.Name) <> nil then
  194. try
  195. {$IFNDEF FPC}
  196. tgtprop.SetValue(aTgtObj,rType.GetProperty(tgtprop.Name).GetValue(aSrcObj));
  197. {$ELSE}
  198. SetPropValue(aTgtObj,tgtprop.Name,GetPropValue(aSrcObj,tgtprop.Name));
  199. {$ENDIF}
  200. except
  201. on E : Exception do raise EAUtoMapperError.CreateFmt('Error mapping property "%s" : %s',[tgtprop.Name,e.message]);
  202. end;
  203. end;
  204. end
  205. else
  206. begin
  207. try
  208. if Assigned(aDoMappingProc) then
  209. begin
  210. {$IFNDEF FPC}
  211. aDoMappingProc(objvalue.AsType<Tm>,tgtprop.Name,value);
  212. manualmapping := not value.IsEmpty;
  213. {$ELSE}
  214. aDoMappingProc(aSrcObj,tgtprop.Name,value);
  215. manualmapping := not varType(value) = varEmpty;
  216. {$ENDIF}
  217. end
  218. else manualmapping := False;
  219. if manualmapping then
  220. begin
  221. {$IFNDEF FPC}
  222. tgtprop.SetValue(aTgtObj,value);
  223. {$ELSE}
  224. SetPropValue(aTgtObj,tgtprop.Name,value);
  225. {$ENDIF}
  226. end
  227. else
  228. begin
  229. {$IFNDEF FPC}
  230. if rType.GetProperty(tgtprop.Name) <> nil then tgtprop.SetValue(aTgtObj,rType.GetProperty(tgtprop.Name).GetValue(aSrcObj));
  231. {$ELSE}
  232. if rType.GetProperty(tgtprop.Name) <> nil then SetPropValue(aTgtObj,tgtprop.Name,GetPropValue(aSrcObj,tgtprop.Name));
  233. {$ENDIF}
  234. end;
  235. except
  236. on E : Exception do raise EAUtoMapperError.CreateFmt('Error mapping property "%s" : %s',[tgtprop.Name,e.message]);
  237. end;
  238. end;
  239. end
  240. else
  241. begin
  242. obj := tgtprop.GetValue(aTgtObj).AsObject;
  243. {$IFNDEF FPC}
  244. if obj = nil then obj := TObject.Create;
  245. {$ELSE}
  246. if obj = nil then obj := GetObjectProp(aSrcObj,tgtprop.Name).ClassType.Create;
  247. {$ENDIF}
  248. if obj <> nil then
  249. begin
  250. {$IFNDEF FPC}
  251. try
  252. clname := rType.GetProperty(tgtprop.Name).GetValue(aSrcObj).AsObject.ClassName;
  253. except
  254. on E : Exception do raise EAUtoMapperError.CreateFmt('Error mapping property "%s" : %s',[tgtprop.Name,e.message]);
  255. end;
  256. if clname.StartsWith('TObjectList') then TObjListMapper.Map(rType.GetProperty(tgtprop.Name).GetValue(aSrcObj).AsObject,obj,aCustomMapping)
  257. else TObjMapper.Map(rType.GetProperty(tgtprop.Name).GetValue(aSrcObj).AsObject,obj,aCustomMapping)
  258. {$ELSE}
  259. TObjMapper.Map(GetObjectProp(aSrcObj,tgtprop.Name),obj,aCustomMapping);
  260. SetObjectProp(aTgtObj,tgtprop.Name,obj);
  261. {$ENDIF}
  262. end
  263. else raise EAutoMapperError.CreateFmt('Target object "%s" not autocreated by class',[tgtprop.Name]);
  264. end;
  265. end;
  266. end;
  267. end;
  268. class function TMapper<T>.Map(aSrcObj : TObject; aCustomMapping: TCustomMapping = nil) : T;
  269. begin
  270. Result := Map{$IFNDEF FPC}<TObject>{$ENDIF}(aSrcObj,nil,aCustomMapping);
  271. end;
  272. {$IFNDEF FPC}
  273. class function TMapper<T>.Map<Tm>(aSrcObj : TObject; aDoMappingProc : TMappingProc<Tm>; aCustomMapping: TCustomMapping = nil): T;
  274. {$ELSE}
  275. class function TMapper<T>.Map(aSrcObj : TObject; aDoMappingProc : TMappingProc<TObject>; aCustomMapping: TCustomMapping = nil): T;
  276. {$ENDIF}
  277. var
  278. obj : T;
  279. begin
  280. obj := T.Create;
  281. {$IFNDEF FPC}
  282. TObjMapper.Map<Tm>(aSrcObj,obj,aDoMappingProc,aCustomMapping);
  283. {$ELSE}
  284. TObjMapper.Map(aSrcObj,obj,aDoMappingProc,aCustomMapping);
  285. {$ENDIF}
  286. Result := obj;
  287. end;
  288. class procedure TMapper<T>.Map(aSrcObj : TObject; aTgtObj : T; aCustomMapping : TCustomMapping = nil);
  289. begin
  290. {$IFNDEF FPC}
  291. Map<T>(aSrcObj,aTgtObj,nil,aCustomMapping);
  292. {$ELSE}
  293. Map(aSrcObj,aTgtObj,nil,aCustomMapping);
  294. {$ENDIF}
  295. end;
  296. {$IFNDEF FPC}
  297. class procedure TMapper<T>.Map<Tm>(aSrcObj : TObject; aTgtObj : T; aDoMappingProc : TMappingProc<Tm>; aCustomMapping : TCustomMapping = nil);
  298. {$ELSE}
  299. class procedure TMapper<T>.Map(aSrcObj : TObject; aTgtObj : T; aDoMappingProc : TMappingProc<TObject>; aCustomMapping : TCustomMapping);
  300. {$ENDIF}
  301. begin
  302. {$IFNDEF FPC}
  303. TObjMapper.Map<Tm>(aSrcObj, aTgtObj, aDoMappingProc, aCustomMapping);
  304. {$ELSE}
  305. TObjMapper.Map(aSrcObj, aTgtObj, aDoMappingProc, aCustomMapping);
  306. {$ENDIF}
  307. end;
  308. { TAutoMapper<TClass1, TClass2> }
  309. constructor TAutoMapper<TClass1, TClass2>.Create;
  310. begin
  311. fCustomMapping := TCustomMapping.Create;
  312. fOnDoMapping := nil;
  313. fOnAfterMapping := nil;
  314. end;
  315. destructor TAutoMapper<TClass1, TClass2>.Destroy;
  316. begin
  317. if Assigned(fCustomMapping) then fCustomMapping.Free;
  318. fOnDoMapping := nil;
  319. fOnAfterMapping := nil;
  320. inherited;
  321. end;
  322. function TAutoMapper<TClass1, TClass2>.Map(aSrcObj: TClass1): TClass2;
  323. var
  324. objvalue : TValue;
  325. obj : TObject;
  326. begin
  327. obj := aSrcObj as TObject;
  328. //objvalue := TValue.From(aSrcObj).AsObject;
  329. {$IFNDEF FPC}
  330. Result := TMapper<TClass2>.Map<TClass1>(obj,fOnDoMapping,fCustomMapping);
  331. {$ELSE}
  332. Result := TMapper<TClass2>.Map(obj,fOnDoMapping,fCustomMapping);
  333. {$ENDIF}
  334. if Assigned(fOnAfterMapping) then fOnAfterMapping(aSrcObj,Result);
  335. end;
  336. {$IFNDEF FPC}
  337. function TAutoMapper<TClass1, TClass2>.Map(aSrcObj: TClass2): TClass1;
  338. begin
  339. Result := TMapper<TClass1>.Map<TClass1>(aSrcObj,fOnDoMapping,fCustomMapping);
  340. end;
  341. procedure TAutoMapper<TClass1, TClass2>.SetOnAfterMapping(CustomProc: TAfterMappingProc<TClass1, TClass2>);
  342. begin
  343. fOnAfterMapping := CustomProc;
  344. end;
  345. procedure TAutoMapper<TClass1, TClass2>.SetOnDoMapping(CustomProc: TMappingProc<TClass1>);
  346. begin
  347. fOnDoMapping := CustomProc;
  348. end;
  349. {$ELSE}
  350. function TAutoMapper<TClass1, TClass2>.Map(aSrcObj: TClass2; dummy : Boolean = True): TClass1;
  351. begin
  352. Result := TMapper<TClass1>.Map(aSrcObj,fOnDoMapping,fCustomMapping);
  353. end;
  354. {$ENDIF}
  355. { TCustomMappingFields }
  356. procedure TCustomMapping.AddMap(const aName, aMapName: string);
  357. begin
  358. //add map fields
  359. fMapDictionary.Add(aName,aMapName);
  360. //add reverse lookup
  361. fMapDictionary.Add(aMapName,aName);
  362. end;
  363. constructor TCustomMapping.Create;
  364. begin
  365. fMapDictionary := TDictionary<string,string>.Create;
  366. end;
  367. destructor TCustomMapping.Destroy;
  368. begin
  369. fMapDictionary.Free;
  370. inherited;
  371. end;
  372. function TCustomMapping.GetMap(const aName: string; out vMapName: string): Boolean;
  373. begin
  374. Result := fMapDictionary.TryGetValue(aName,vMapName);
  375. end;
  376. { TListMapper }
  377. class procedure TListMapper.Map(aSrcList, aTgtList: TObject; aCustomMapping: TCustomMapping);
  378. {$IFNDEF FPC}
  379. var
  380. rtype: TRttiType;
  381. rtype2 : TRttiType;
  382. typinfo : PTypeInfo;
  383. methToArray: TRttiMethod;
  384. value: TValue;
  385. valuecop : TValue;
  386. obj : TObject;
  387. i : Integer;
  388. rprop : TRttiProperty;
  389. ctx : TRttiContext;
  390. begin
  391. rtype := ctx.GetType(aSrcList.ClassInfo);
  392. methToArray := rtype.GetMethod('ToArray');
  393. if Assigned(methToArray) then
  394. begin
  395. value := methToArray.Invoke(aSrcList,[]);
  396. Assert(value.IsArray);
  397. rtype2 := ctx.GetType(aTgtList.ClassInfo);
  398. rProp := rtype2.GetProperty('List');
  399. typinfo := GetTypeData(rProp.PropertyType.Handle).DynArrElType^;
  400. for i := 0 to value.GetArrayLength - 1 do
  401. begin
  402. if typinfo.Kind = tkClass then
  403. begin
  404. obj := typinfo.TypeData.ClassType.Create;
  405. TObjMapper.Map(value.GetArrayElement(i).AsObject,obj,aCustomMapping);
  406. TList<TObject>(aTgtList).Add(obj);
  407. end
  408. else
  409. begin
  410. valuecop := value.GetArrayElement(i);
  411. case typinfo.Kind of
  412. tkChar, tkString, tkWChar, tkWString : TList<string>(aTgtList).Add(valuecop.AsString);
  413. tkInteger, tkInt64 : TList<Integer>(aTgtList).Add(valuecop.AsInt64);
  414. tkFloat : TList<Extended>(aTgtList).Add(valuecop.AsExtended);
  415. end;
  416. end;
  417. end;
  418. end;
  419. end;
  420. {$ELSE}
  421. begin
  422. end;
  423. {$ENDIF}
  424. { TObjListMapper }
  425. class procedure TObjListMapper.Map(aSrcObjList, aTgtObjList: TObject; aCustomMapping: TCustomMapping);
  426. begin
  427. {$IFNDEF FPC}
  428. Map<TObject>(aSrcObjList,aTgtObjList,nil,aCustomMapping);
  429. {$ELSE}
  430. Map(aSrcObjList,aTgtObjList,nil,aCustomMapping);
  431. {$ENDIF}
  432. end;
  433. {$IFNDEF FPC}
  434. class procedure TObjListMapper.Map<Tm>(aSrcObjList : TObject; aTgtObjList : TObject; aDoMappingProc : TMappingProc<Tm>; aCustomMapping : TCustomMapping = nil);
  435. var
  436. rtype: TRttiType;
  437. rtype2 : TRttiType;
  438. typinfo : PTypeInfo;
  439. methToArray: TRttiMethod;
  440. value: TValue;
  441. obj : TObject;
  442. i : Integer;
  443. rprop : TRttiProperty;
  444. ctx : TRttiContext;
  445. begin
  446. rtype := ctx.GetType(aSrcObjList.ClassInfo);
  447. methToArray := rtype.GetMethod('ToArray');
  448. if Assigned(methToArray) then
  449. begin
  450. value := methToArray.Invoke(aSrcObjList,[]);
  451. Assert(value.IsArray);
  452. rtype2 := ctx.GetType(aTgtObjList.ClassInfo);
  453. rProp := rtype2.GetProperty('List');
  454. typinfo := GetTypeData(rProp.PropertyType.Handle).DynArrElType^;
  455. for i := 0 to value.GetArrayLength - 1 do
  456. begin
  457. obj := typinfo.TypeData.ClassType.Create;
  458. TObjMapper.Map<Tm>(value.GetArrayElement(i).AsObject,obj,aDoMappingProc,aCustomMapping);
  459. TObjectList<TObject>(aTgtObjList).Add(obj);
  460. end;
  461. end;
  462. end;
  463. {$ELSE}
  464. class procedure TObjListMapper.Map(aSrcObjList : TObject; aTgtObjList : TObject; aDoMappingProc : TMappingProc<TObject>; aCustomMapping : TCustomMapping = nil);
  465. begin
  466. end;
  467. {$ENDIF}
  468. { TMapper }
  469. {$IFNDEF FPC}
  470. class function TMapper.Map<T>(aSrcObj: TObject): T;
  471. begin
  472. Result := T.Create;
  473. TObjMapper.Map(aSrcObj,Result,nil);
  474. end;
  475. {$ENDIF}
  476. end.