#1 2015-09-29 14:24:08

EMartin
Member
From: Buenos Aires - Argentina
Registered: 2013-01-09
Posts: 332

Array of Integer in TSynPersistent class

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

#2 2015-09-29 14:43:40

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,206
Website

Re: Array of Integer in TSynPersistent class

varfields is defined as RawJSON, so it should accept any kind of valid JSON.

Could you use the debugger and find out on which exact parameter the input parameter failed to parse?

Offline

#3 2015-09-29 15:26:48

EMartin
Member
From: Buenos Aires - Argentina
Registered: 2013-01-09
Posts: 332

Re: Array of Integer in TSynPersistent class

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

#4 2015-09-30 11:59:04

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,206
Website

Re: Array of Integer in TSynPersistent class

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

#5 2015-09-30 15:28:53

EMartin
Member
From: Buenos Aires - Argentina
Registered: 2013-01-09
Posts: 332

Re: Array of Integer in TSynPersistent class

Thanks @ab, I had forgotten of TSynAutoCreateFields, with this works fine.


Esteban

Offline

Board footer

Powered by FluxBB