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
  99. ['{9F7B2DEA-76D8-4DD1-95D0-22C22AEB5DD0}']
  100. function Map(aSrcObj : TClass1) : TClass2; overload;
  101. {$IFNDEF FPC}
  102. function Map(aSrcObj : TClass2) : TClass1; overload;
  103. procedure SetOnDoMapping(CustomProc : TMappingProc<TClass1>);
  104. procedure SetOnAfterMapping(CustomProc : TAfterMappingProc<TClass1,TClass2>);
  105. {$ELSE}
  106. //freepascal detects overload with generic types as duplicated function, added dummy field to avoid this
  107. function Map(aSrcObj : TClass2; dummy : Boolean = True) : TClass1; overload;
  108. {$ENDIF}
  109. end;
  110. TAutoMapper<TClass1, TClass2 : class, constructor> = class(TInterfacedObject, IAutoMapper<TClass1, TClass2>)
  111. private
  112. fCustomMapping : TCustomMapping;
  113. {$IFNDEF FPC}
  114. fOnDoMapping : TMappingProc<TClass1>;
  115. {$ELSE}
  116. fOnDoMapping : TMappingProc<TObject>;
  117. {$ENDIF}
  118. fOnAfterMapping : TAfterMappingProc<TClass1,TClass2>;
  119. public
  120. constructor Create;
  121. destructor Destroy; override;
  122. property CustomMapping : TCustomMapping read fCustomMapping write fCustomMapping;
  123. {$IFNDEF FPC}
  124. property OnDoMapping : TMappingProc<TClass1> read fOnDoMapping write fOnDoMapping;
  125. {$ELSE}
  126. property OnDoMapping : TMappingProc<TObject> read fOnDoMapping write fOnDoMapping;
  127. {$ENDIF}
  128. property OnAfterMapping : TAfterMappingProc<TClass1,TClass2> read fOnAfterMapping write fOnAfterMapping;
  129. function Map(aSrcObj : TClass1) : TClass2; overload;
  130. {$IFNDEF FPC}
  131. function Map(aSrcObj : TClass2) : TClass1; overload;
  132. procedure SetOnDoMapping(CustomProc : TMappingProc<TClass1>);
  133. procedure SetOnAfterMapping(CustomProc : TAfterMappingProc<TClass1,TClass2>);
  134. {$ELSE}
  135. //freepascal detects overload with generic types as duplicated function, added dummy field to avoid this
  136. function Map(aSrcObj : TClass2; dummy : Boolean = True) : TClass1; overload;
  137. {$ENDIF}
  138. end;
  139. EAutoMapperError = class(Exception);
  140. implementation
  141. { TObjMapper }
  142. class procedure TObjMapper.Map(aSrcObj : TObject; aTgtObj : TObject; aCustomMapping: TCustomMapping = nil);
  143. begin
  144. Map{$IFNDEF FPC}<TObject>{$ENDIF}(aSrcObj,aTgtObj,nil,aCustomMapping);
  145. end;
  146. {$IFNDEF FPC}
  147. class procedure TObjMapper.Map<Tm>(aSrcObj : TObject; aTgtObj : TObject; aDoMappingProc : TMappingProc<Tm>; aCustomMapping: TCustomMapping = nil);
  148. {$ELSE}
  149. class procedure TObjMapper.Map(aSrcObj : TObject; aTgtObj : TObject; aDoMappingProc : TMappingProc<TObject>; aCustomMapping: TCustomMapping = nil);
  150. {$ENDIF}
  151. var
  152. ctx : TRttiContext;
  153. rType : TRttiType;
  154. tgtprop : TRttiProperty;
  155. mapname : string;
  156. obj : TObject;
  157. manualmapping : Boolean;
  158. value : TFlexValue;
  159. {$IFNDEF FPC}
  160. clname : string;
  161. objvalue : TValue;
  162. {$ENDIF}
  163. begin
  164. //if aTgtObj = nil then aTgtObj := GetTypeData(aTgtObj.ClassInfo).classType.Create;
  165. if aTgtObj = nil then raise EAutoMapperError.Create('TObjMapper: Target Object passed must be created before');
  166. {$IFNDEF FPC}
  167. objvalue := TValue.From(aSrcObj);
  168. {$ENDIF}
  169. rType := ctx.GetType(aSrcObj.ClassInfo);
  170. for tgtprop in ctx.GetType(aTgtObj.ClassInfo).GetProperties do
  171. begin
  172. if tgtprop.IsWritable then
  173. begin
  174. if not tgtprop.PropertyType.IsInstance then
  175. begin
  176. if Assigned(aCustomMapping) and (not Assigned(aDoMappingProc)) then
  177. begin
  178. if aCustomMapping.GetMap(tgtprop.Name,mapname) then
  179. begin
  180. {$IFNDEF PROPERTYPATH_MODE}
  181. if rType.GetProperty(mapname) = nil then raise EAutoMapperError.CreateFmt('No valid custom mapping (Source: %s - Target: %s)',[mapname,tgtprop.Name]);
  182. {$IFNDEF FPC}
  183. tgtprop.SetValue(aTgtObj,rType.GetProperty(mapname).GetValue(aSrcObj))
  184. {$ELSE}
  185. SetPropValue(aTgtObj,tgtprop.Name,GetPropValue(aSrcObj,mapname));
  186. {$ENDIF}
  187. {$ELSE}
  188. if not TRTTI.PathExists(aSrcObj,mapname) then raise EAutoMapperError.CreateFmt('No valid custom mapping (Source: %s - Target: %s)',[mapname,tgtprop.Name]);
  189. TRTTI.SetPathValue(aTgtObj,tgtprop.Name,TRTTI.GetPathValue(aSrcObj,mapname));
  190. {$ENDIF}
  191. end
  192. else
  193. begin
  194. if rType.GetProperty(tgtprop.Name) <> nil then
  195. try
  196. {$IFNDEF FPC}
  197. tgtprop.SetValue(aTgtObj,rType.GetProperty(tgtprop.Name).GetValue(aSrcObj));
  198. {$ELSE}
  199. SetPropValue(aTgtObj,tgtprop.Name,GetPropValue(aSrcObj,tgtprop.Name));
  200. {$ENDIF}
  201. except
  202. on E : Exception do raise EAUtoMapperError.CreateFmt('Error mapping property "%s" : %s',[tgtprop.Name,e.message]);
  203. end;
  204. end;
  205. end
  206. else
  207. begin
  208. try
  209. if Assigned(aDoMappingProc) then
  210. begin
  211. {$IFNDEF FPC}
  212. aDoMappingProc(objvalue.AsType<Tm>,tgtprop.Name,value);
  213. manualmapping := not value.IsEmpty;
  214. {$ELSE}
  215. aDoMappingProc(aSrcObj,tgtprop.Name,value);
  216. manualmapping := not varType(value) = varEmpty;
  217. {$ENDIF}
  218. end
  219. else manualmapping := False;
  220. if manualmapping then
  221. begin
  222. {$IFNDEF FPC}
  223. tgtprop.SetValue(aTgtObj,value);
  224. {$ELSE}
  225. SetPropValue(aTgtObj,tgtprop.Name,value);
  226. {$ENDIF}
  227. end
  228. else
  229. begin
  230. {$IFNDEF FPC}
  231. if rType.GetProperty(tgtprop.Name) <> nil then tgtprop.SetValue(aTgtObj,rType.GetProperty(tgtprop.Name).GetValue(aSrcObj));
  232. {$ELSE}
  233. if rType.GetProperty(tgtprop.Name) <> nil then SetPropValue(aTgtObj,tgtprop.Name,GetPropValue(aSrcObj,tgtprop.Name));
  234. {$ENDIF}
  235. end;
  236. except
  237. on E : Exception do raise EAUtoMapperError.CreateFmt('Error mapping property "%s" : %s',[tgtprop.Name,e.message]);
  238. end;
  239. end;
  240. end
  241. else
  242. begin
  243. obj := tgtprop.GetValue(aTgtObj).AsObject;
  244. {$IFNDEF FPC}
  245. if obj = nil then obj := TObject.Create;
  246. {$ELSE}
  247. if obj = nil then obj := GetObjectProp(aSrcObj,tgtprop.Name).ClassType.Create;
  248. {$ENDIF}
  249. if obj <> nil then
  250. begin
  251. {$IFNDEF FPC}
  252. try
  253. clname := rType.GetProperty(tgtprop.Name).GetValue(aSrcObj).AsObject.ClassName;
  254. except
  255. on E : Exception do raise EAUtoMapperError.CreateFmt('Error mapping property "%s" : %s',[tgtprop.Name,e.message]);
  256. end;
  257. if clname.StartsWith('TObjectList') then TObjListMapper.Map(rType.GetProperty(tgtprop.Name).GetValue(aSrcObj).AsObject,obj,aCustomMapping)
  258. else TObjMapper.Map(rType.GetProperty(tgtprop.Name).GetValue(aSrcObj).AsObject,obj,aCustomMapping)
  259. {$ELSE}
  260. TObjMapper.Map(GetObjectProp(aSrcObj,tgtprop.Name),obj,aCustomMapping);
  261. SetObjectProp(aTgtObj,tgtprop.Name,obj);
  262. {$ENDIF}
  263. end
  264. else raise EAutoMapperError.CreateFmt('Target object "%s" not autocreated by class',[tgtprop.Name]);
  265. end;
  266. end;
  267. end;
  268. end;
  269. class function TMapper<T>.Map(aSrcObj : TObject; aCustomMapping: TCustomMapping = nil) : T;
  270. begin
  271. Result := Map{$IFNDEF FPC}<TObject>{$ENDIF}(aSrcObj,nil,aCustomMapping);
  272. end;
  273. {$IFNDEF FPC}
  274. class function TMapper<T>.Map<Tm>(aSrcObj : TObject; aDoMappingProc : TMappingProc<Tm>; aCustomMapping: TCustomMapping = nil): T;
  275. {$ELSE}
  276. class function TMapper<T>.Map(aSrcObj : TObject; aDoMappingProc : TMappingProc<TObject>; aCustomMapping: TCustomMapping = nil): T;
  277. {$ENDIF}
  278. var
  279. obj : T;
  280. begin
  281. obj := T.Create;
  282. {$IFNDEF FPC}
  283. TObjMapper.Map<Tm>(aSrcObj,obj,aDoMappingProc,aCustomMapping);
  284. {$ELSE}
  285. TObjMapper.Map(aSrcObj,obj,aDoMappingProc,aCustomMapping);
  286. {$ENDIF}
  287. Result := obj;
  288. end;
  289. class procedure TMapper<T>.Map(aSrcObj : TObject; aTgtObj : T; aCustomMapping : TCustomMapping = nil);
  290. begin
  291. {$IFNDEF FPC}
  292. Map<T>(aSrcObj,aTgtObj,nil,aCustomMapping);
  293. {$ELSE}
  294. Map(aSrcObj,aTgtObj,nil,aCustomMapping);
  295. {$ENDIF}
  296. end;
  297. {$IFNDEF FPC}
  298. class procedure TMapper<T>.Map<Tm>(aSrcObj : TObject; aTgtObj : T; aDoMappingProc : TMappingProc<Tm>; aCustomMapping : TCustomMapping = nil);
  299. {$ELSE}
  300. class procedure TMapper<T>.Map(aSrcObj : TObject; aTgtObj : T; aDoMappingProc : TMappingProc<TObject>; aCustomMapping : TCustomMapping);
  301. {$ENDIF}
  302. begin
  303. {$IFNDEF FPC}
  304. TObjMapper.Map<Tm>(aSrcObj, aTgtObj, aDoMappingProc, aCustomMapping);
  305. {$ELSE}
  306. TObjMapper.Map(aSrcObj, aTgtObj, aDoMappingProc, aCustomMapping);
  307. {$ENDIF}
  308. end;
  309. { TAutoMapper<TClass1, TClass2> }
  310. constructor TAutoMapper<TClass1, TClass2>.Create;
  311. begin
  312. fCustomMapping := TCustomMapping.Create;
  313. fOnDoMapping := nil;
  314. fOnAfterMapping := nil;
  315. end;
  316. destructor TAutoMapper<TClass1, TClass2>.Destroy;
  317. begin
  318. if Assigned(fCustomMapping) then fCustomMapping.Free;
  319. fOnDoMapping := nil;
  320. fOnAfterMapping := nil;
  321. inherited;
  322. end;
  323. function TAutoMapper<TClass1, TClass2>.Map(aSrcObj: TClass1): TClass2;
  324. var
  325. objvalue : TValue;
  326. obj : TObject;
  327. begin
  328. obj := aSrcObj as TObject;
  329. //objvalue := TValue.From(aSrcObj).AsObject;
  330. {$IFNDEF FPC}
  331. Result := TMapper<TClass2>.Map<TClass1>(obj,fOnDoMapping,fCustomMapping);
  332. {$ELSE}
  333. Result := TMapper<TClass2>.Map(obj,fOnDoMapping,fCustomMapping);
  334. {$ENDIF}
  335. if Assigned(fOnAfterMapping) then fOnAfterMapping(aSrcObj,Result);
  336. end;
  337. {$IFNDEF FPC}
  338. function TAutoMapper<TClass1, TClass2>.Map(aSrcObj: TClass2): TClass1;
  339. begin
  340. Result := TMapper<TClass1>.Map<TClass1>(aSrcObj,fOnDoMapping,fCustomMapping);
  341. end;
  342. procedure TAutoMapper<TClass1, TClass2>.SetOnAfterMapping(CustomProc: TAfterMappingProc<TClass1, TClass2>);
  343. begin
  344. fOnAfterMapping := CustomProc;
  345. end;
  346. procedure TAutoMapper<TClass1, TClass2>.SetOnDoMapping(CustomProc: TMappingProc<TClass1>);
  347. begin
  348. fOnDoMapping := CustomProc;
  349. end;
  350. {$ELSE}
  351. function TAutoMapper<TClass1, TClass2>.Map(aSrcObj: TClass2; dummy : Boolean = True): TClass1;
  352. begin
  353. Result := TMapper<TClass1>.Map(aSrcObj,fOnDoMapping,fCustomMapping);
  354. end;
  355. {$ENDIF}
  356. { TCustomMappingFields }
  357. procedure TCustomMapping.AddMap(const aName, aMapName: string);
  358. begin
  359. //add map fields
  360. fMapDictionary.Add(aName,aMapName);
  361. //add reverse lookup
  362. fMapDictionary.Add(aMapName,aName);
  363. end;
  364. constructor TCustomMapping.Create;
  365. begin
  366. fMapDictionary := TDictionary<string,string>.Create;
  367. end;
  368. destructor TCustomMapping.Destroy;
  369. begin
  370. fMapDictionary.Free;
  371. inherited;
  372. end;
  373. function TCustomMapping.GetMap(const aName: string; out vMapName: string): Boolean;
  374. begin
  375. Result := fMapDictionary.TryGetValue(aName,vMapName);
  376. end;
  377. { TListMapper }
  378. class procedure TListMapper.Map(aSrcList, aTgtList: TObject; aCustomMapping: TCustomMapping);
  379. {$IFNDEF FPC}
  380. var
  381. rtype: TRttiType;
  382. rtype2 : TRttiType;
  383. typinfo : PTypeInfo;
  384. methToArray: TRttiMethod;
  385. value: TValue;
  386. valuecop : TValue;
  387. obj : TObject;
  388. i : Integer;
  389. rprop : TRttiProperty;
  390. ctx : TRttiContext;
  391. begin
  392. rtype := ctx.GetType(aSrcList.ClassInfo);
  393. methToArray := rtype.GetMethod('ToArray');
  394. if Assigned(methToArray) then
  395. begin
  396. value := methToArray.Invoke(aSrcList,[]);
  397. Assert(value.IsArray);
  398. rtype2 := ctx.GetType(aTgtList.ClassInfo);
  399. rProp := rtype2.GetProperty('List');
  400. typinfo := GetTypeData(rProp.PropertyType.Handle).DynArrElType^;
  401. for i := 0 to value.GetArrayLength - 1 do
  402. begin
  403. if typinfo.Kind = tkClass then
  404. begin
  405. obj := typinfo.TypeData.ClassType.Create;
  406. TObjMapper.Map(value.GetArrayElement(i).AsObject,obj,aCustomMapping);
  407. TList<TObject>(aTgtList).Add(obj);
  408. end
  409. else
  410. begin
  411. valuecop := value.GetArrayElement(i);
  412. case typinfo.Kind of
  413. tkChar, tkString, tkWChar, tkWString : TList<string>(aTgtList).Add(valuecop.AsString);
  414. tkInteger, tkInt64 : TList<Integer>(aTgtList).Add(valuecop.AsInt64);
  415. tkFloat : TList<Extended>(aTgtList).Add(valuecop.AsExtended);
  416. end;
  417. end;
  418. end;
  419. end;
  420. end;
  421. {$ELSE}
  422. begin
  423. end;
  424. {$ENDIF}
  425. { TObjListMapper }
  426. class procedure TObjListMapper.Map(aSrcObjList, aTgtObjList: TObject; aCustomMapping: TCustomMapping);
  427. begin
  428. {$IFNDEF FPC}
  429. Map<TObject>(aSrcObjList,aTgtObjList,nil,aCustomMapping);
  430. {$ELSE}
  431. Map(aSrcObjList,aTgtObjList,nil,aCustomMapping);
  432. {$ENDIF}
  433. end;
  434. {$IFNDEF FPC}
  435. class procedure TObjListMapper.Map<Tm>(aSrcObjList : TObject; aTgtObjList : TObject; aDoMappingProc : TMappingProc<Tm>; aCustomMapping : TCustomMapping = nil);
  436. var
  437. rtype: TRttiType;
  438. rtype2 : TRttiType;
  439. typinfo : PTypeInfo;
  440. methToArray: TRttiMethod;
  441. value: TValue;
  442. obj : TObject;
  443. i : Integer;
  444. rprop : TRttiProperty;
  445. ctx : TRttiContext;
  446. begin
  447. rtype := ctx.GetType(aSrcObjList.ClassInfo);
  448. methToArray := rtype.GetMethod('ToArray');
  449. if Assigned(methToArray) then
  450. begin
  451. value := methToArray.Invoke(aSrcObjList,[]);
  452. Assert(value.IsArray);
  453. rtype2 := ctx.GetType(aTgtObjList.ClassInfo);
  454. rProp := rtype2.GetProperty('List');
  455. typinfo := GetTypeData(rProp.PropertyType.Handle).DynArrElType^;
  456. for i := 0 to value.GetArrayLength - 1 do
  457. begin
  458. obj := typinfo.TypeData.ClassType.Create;
  459. TObjMapper.Map<Tm>(value.GetArrayElement(i).AsObject,obj,aDoMappingProc,aCustomMapping);
  460. TObjectList<TObject>(aTgtObjList).Add(obj);
  461. end;
  462. end;
  463. end;
  464. {$ELSE}
  465. class procedure TObjListMapper.Map(aSrcObjList : TObject; aTgtObjList : TObject; aDoMappingProc : TMappingProc<TObject>; aCustomMapping : TCustomMapping = nil);
  466. begin
  467. end;
  468. {$ENDIF}
  469. { TMapper }
  470. {$IFNDEF FPC}
  471. class function TMapper.Map<T>(aSrcObj: TObject): T;
  472. begin
  473. Result := T.Create;
  474. TObjMapper.Map(aSrcObj,Result,nil);
  475. end;
  476. {$ENDIF}
  477. end.