For reasons not really relevant to the question I want to use generics in my TRemotable classes. I've found that Soap.OPToSOAPDomConv.pas has some problems with this. It's using the old RTTI which I guess can't handle generics so the classes is not serialized into xml.
I've managed to change Soap.OPToSOAPDomConv.pas so that it works with generics. My main question is if it is considered ok to do changes in the Delphi source files? If it isn't, is there a better way to do this? As long as it's just me using it I guess there is no big problems, but it's hard to distribute the source to others, and then there's also future changes in Delphi to consider. The rest of this lenghty post is just details about what I'm actually doing :-)
I've changed this in Soap.OPToSOAPDomConv.pas (row 3759)
if SerializeProps then
begin
{ Serialized published properties }
Count := GetTypeData(Instance.ClassInfo)^.PropCount;
if Count > 0 then
begin
CheckedElemURI := False;
GetMem(PropList, Count * SizeOf(Pointer));
try
GetPropInfos(Instance.ClassInfo, PropList);
To: (not the prettiest implementation I guess)
New variables in the procedure:
Context: TRttiContext;
RttiProperty: TRttiProperty;
Row 3759:
if SerializeProps then
begin
{ Serialized published properties }
Count := 0;
for RttiProperty in Context.GetType(Instance.ClassInfo).GetProperties do
begin
if RttiProperty.Visibility = mvPublished then //The old method only read published
Count := Count + 1; //RTTI scoping [mvPublished] requires changes to
end; //soap.InvRegistry
begin
CheckedElemURI := False;
GetMem(PropList, Count * SizeOf(Pointer));
try
I := 0;
for RttiProperty in Context.GetType(Instance.ClassInfo).GetProperties do
if RttiProperty.Visibility = mvPublished then
begin
PropList[I] := TRttiInstanceProperty(RttiProperty).PropInfo;
I := I + 1;
end;
Some details as to what I am doing is probably helpful. The background is that the imported wsdl from the SOAP Web Service generates a huge unit, that consists of about 2000 classes and 300k rows of code. The web service design is out of my control. The WSDL Importer makes all of these classes visible in RTTI, which consumes the RTTI space and the unit won't compile.
I've refactored the code here and there and now have a working implementation. While refactoring I found that I could cut away some 50000 rows of redundant code by using generics. Since Delphi won't compile the imported wsdl "as is" anyway I will have to maintain the unit manually whenever new methods becomes available in the web service, so I want to make it as readable as possible.
Basically I'm changing according to below. The sample has very simplified classes, and the sample actually has more lines in the refactored code, but considering the original classes has a lot of procedures etc this method really makes the unit a lot more readable, and it's also easier to compose the classes.
TLCar = class(TRemotable)
private
FEngine: string;
FName: string;
published
property Name: string read FName write FName;
property Engine: string read FEngine write FEngine;
end;
TLBicycle = class(TRemotable)
private
FPedals: string;
FName: string;
published
property Name: string read FName write FName;
property Pedals: string read FPedals write FPedals;
end;
TListCarRequest = class(TRemotable)
private
FreturnedTags: TLCar;
published
property returnedTags: TLCar read FreturnedTags write FreturnedTags;
end;
TListBiCycleRequest = class(TRemotable)
private
FreturnedTags: TLBicycle;
published
property returnedTags: TLBicycle read FreturnedTags write FreturnedTags;
To:
TCommonReturnedTags = class(TRemotable)
private
FName: string;
published
property Name: string read FName write FName;
end;
TLCar = class(TCommonReturnedTags)
private
FEngine: string;
published
property Engine: string read FEngine write FEngine;
end;
TLBicycle = class(TCommonReturnedTags)
private
FPedals: string;
published
property Pedals: string read FPedals write FPedals;
end;
TGenericListRequest<T: TCommonReturnedTags, constructor> = class(TRemotable)
private
FreturnedTags: T;
published
property returnedTags: T read FreturnedTags write FreturnedTags;
end;
TListCarRequest = class(TGenericListRequest<TLCar>)
end;
TListBiCycleRequest = class(TGenericListRequest<TLBicycle>)
end;
Kind Regards,
Dan
There are two things to consider when making modifications such as this. First of all, can the change have impact on existing functionality. As in this case I would say that it is safe because the functionality is new to this operation, so there shouldn't be any unexpected behavior. Second part is the evolution development environment. Problem with the evolution of environment is that bindings between actions may change and that can lead to unexpected things. At this moment it is alright to assume that XE2 to has had it's share of updates. If it wouldn't, you would have to keep an eye when patching or updating. The second kind of change like the one from XE2 to XE3 can be handled better. Just put the following in top of Soap.OPToSOAPDomConv.pas:
{$IFNDEF VER230}
{$MESSAGE ERROR 'Intended to be used with XE2'}
{$ENDIF}
When get error while compiling you might remember vaguely that there was something about that file... So in short, it is not bad things as far as try to evaluate impact and adapt to environment changes. Hopefully this was what you wanted to know.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With