You are not logged in.
Pages: 1
Hi @ab, I have a problem when implementing TSynPersistent parameter for services.
I have this classes:
/// Opciones para cuando se importa desde un archivo CSV.
TCDICSVOptions = class(TSynPersistent)
private
fcompressed: Boolean;
ffilename: RawUTF8;
ffieldsep: RawUTF8;
published
/// Indica si el archivo está comprimido
property compressed: Boolean read fcompressed write fcompressed;
/// Nombre del archivo desde el cuál importar.
property filename: RawUTF8 read ffilename write ffilename;
/// Separador de campos dentro del CSV.
property fieldsep: RawUTF8 read ffieldsep write ffieldsep;
end;
/// Opciones para cuando en la tabla se va a importar.
TCDICreateOptions = class(TSynPersistent)
private
fshortname: RawUTF8;
fdescription: RawUTF8;
fmediatype: RawUTF8;
fvarfields: RawJSON;
published
property mediatype: RawUTF8 read fmediatype write fmediatype;
property shortname: RawUTF8 read fshortname write fshortname;
property description: RawUTF8 read fdescription write fdescription;
property varfields: RawJSON read fvarfields write fvarfields;
end;
/// Opciones sobre la tabla donde se importará
TCDITableOptions = class(TSynPersistent)
private
ftablename: RawUTF8;
fcommitreccount: Integer;
fdeleterecords: Integer;
fcreateoptions: TCDICreateOptions;
published
property tablename: RawUTF8 read ftablename write ftablename;
property deleterecords: Integer read fdeleterecords write fdeleterecords;
property commitreccount: Integer read fcommitreccount write fcommitreccount;
property createoptions: TCDICreateOptions read fcreateoptions write fcreateoptions;
end;
and I have this service:
function ContactDataImport(const aCSVOptions: TCDICSVOptions; const aTableOptions: TCDITableOptions; const aMapOptions: RawJSON): TServiceCustomAnswer;
and I have this POST AJAX JSON request:
https://192.168.69.89:8898/svc/DBServic … DataImport
with this body:
[{"filename":"\\TecnoVoz\\IVRData\\ImportARISTest.csv","fieldsep":"|"},{"tablename":"CP1","deleterecords":0,"commitreccount":2,"createoptions":{"mediatype":"CALL","shortname":"CP1","description":"Importando con ARIS","varfields":[1,25,90]}},{"fields":["PHONE=1,2,,3","V01_TM=4","V25_TM=","V90_TM=6"]}]
with the first argument (TCDICSVOptions) I haven't problem, but with the second (TCDITableOptions) I have the following error:
{
errorCode: 406
errorText: "Shared execution failed (probably due to bad input parameters) for IDBService.ContactDataImport"
}
I suspect from the varfields property, this is an array of integer and I think that am not putting the correct data type.
Can you tell me how to implement an array on class inherited from TSynPersistent that can be serialized and work con AJAX client ?
Thanks in advance.
EMartin.
Esteban
Offline
Offline
When debugging I can see that the second argument aTableOption has the problem, more specific on property "createoptions". The problem that I can see is on mORMot.pas.TPropInfo.ClassFromJSON.
This is the problem that I can notice (see //--> marks):
function TPropInfo.ClassFromJSON(Instance: TObject; From: PUTF8Char;
var Valid: boolean; Options: TJSONToObjectOptions): PUTF8Char;
var Field: ^TObject;
tmp: TObject;
begin
valid := false;
result := nil;
if (@self=nil) or (PropType^.Kind<>tkClass) or (Instance=nil) then
exit;
if SetterIsField then
// setter to field -> direct in-memory access
Field := SetterAddr(Instance) else //--> THIS LINE IS EXECUTED: Field := SetterAddr(Instance)
{$ifndef FPC}
if SetProc<>0 then begin
// it is a setter method -> create a temporary object
tmp := PropType^.ClassCreate;
try
result := JSONToObject(tmp,From,Valid,nil,Options);
if not Valid then
FreeAndNil(tmp) else begin
SetOrdProp(Instance,PtrInt(tmp)); // PtrInt(tmp) is OK for CPU64
if j2oSetterExpectsToFreeTempInstance in Options then
FreeAndNil(tmp);
end;
except
on Exception do
tmp.Free;
end;
exit;
end else
{$endif}
if GetterIsField then
// no setter -> use direct in-memory access from getter (if available)
Field := GetterAddr(Instance) else
// no setter, nor direct field offset -> impossible to set the instance
exit;
result := JSONToObject(Field^,From,Valid,nil,Options); //--> "Field^" parameter has and addres but is nil when dereferencing and the "Valid" parameter return with False
//--> in this point the "From" parameter have the following value:
//--> {"mediatype":"CALL","shortname":"CP1","description":"Importando con ARIS","varfields":[1,25,90]}},{"fields":["PHONE=1,2,,3","V01_TM=4","V25_TM=","V90_TM=6"]}]
end;
the JSONToObject function abort the parse in the marked line:
function JSONToObject(var ObjectInstance; From: PUTF8Char; var Valid: boolean;
TObjectListItemClass: TClass; Options: TJSONToObjectOptions): PUTF8Char;
var P: PPropInfo;
Value: TObject absolute ObjectInstance;
...
begin
Valid := false;
result := From;
if Value=nil then //--> Value is nil because Field^ is nil when JSONToObject is called from TPropInfo.ClassFromJSON
exit;
...
end;
I hope that this help.
Thanks.
EMartin.
Esteban
Offline
Your TCDITableOptions class does NOT allocate the nested TSynPersistent fields.
So their fields are defined as nil.
So it is not possible to unserialize their JSON.
Try to define TCDITableOptions as TSynAutoCreateFields (without any setter for nested TSynPersistent).
It will let the serialization work as exception.
Offline
Thanks @ab, I had forgotten of TSynAutoCreateFields, with this works fine.
Esteban
Offline
Pages: 1