You are not logged in.
Line 152 needs to be changed to
result.{{fullPropName}}.Add(Variant2{{typePascal}}(Value.{{fullPropName}}[i]));
I have added Variant2 so that the generated conversion function is called instead of the typecast. The tyecast of a variant to a recordtype is not supported in sms.
Offline
Which kind of pascal type are you talking about?
This line is about {{#nestedSimpleArray}}, so here it would be simple numbers or strings.
Records are handled just after this line, by the {{#nestedRecordArray}} ... {{/nestedRecordArray}} block.
Offline
I am talking about a record that contains an array of another record.
type
Ta=record
...
end;
Tb=record
arr:array of Ta;
...
end;
so you may be right...
But a matter of fact is that the existing template generates code that can't be compiled by sms for the above data structure. I'm using such structure as a DTO in an interfaced service.
My fix resolves the issue for the above structure but I am not sure if it breaks something with arrays of simple types...
Last edited by martin.suer (2015-01-15 21:21:33)
Offline
ok, more details... I have done some more testing. (XE7,SMS2.1.2,Win8.1)
The following type in delphi
type
TRecA=packed record
v1,v2:integer;
end;
TRecB=packed record
a1:array of TRecA;
a2:array of integer;
v1:integer;
end;
results to this generated code in mORMotClient.pas (sms)
function Variant2TRecB(const Value: variant): TRecB;
begin
if VariantType(Value.a1)=jvArray then
for var i := 0 to integer(Value.a1.length)-1 do
result.a1.Add(TRecA(Value.a1[i]));
if VariantType(Value.a2)=jvArray then
for var i := 0 to integer(Value.a2.length)-1 do
result.a2.Add(Integer(Value.a2[i]));
result.v1 := Value.v1;
end;
compiling that with sms raises
Syntax Error: Not a method [line: 226, column: 35, file: mORMotClient]
Offline
and with my fix applied the generated code changes to
function Variant2TRecB(const Value: variant): TRecB;
begin
if VariantType(Value.a1)=jvArray then
for var i := 0 to integer(Value.a1.length)-1 do
result.a1.Add(Variant2TRecA(Value.a1[i]));
if VariantType(Value.a2)=jvArray then
for var i := 0 to integer(Value.a2.length)-1 do
result.a2.Add(Variant2Integer(Value.a2[i]));
result.v1 := Value.v1;
end;
which then calls the right conversion function Variant2RecA but breaks the typecast for Integer in the next for loop. So my fix doesn't work.
The type of the array member must be taken into account there
Offline
found the problem in the context, both arrays are tagged as simple arrays:
{
name: "TRecB",
fields:
[
{
typeWrapper: "wArray",
typeSource: "",
typeDelphi: null,
typePascal: null,
typeCS: null,
typeJava: null,
isArray: true,
propName: "a1",
fullPropName: "a1",
isSimple: null,
nestedSimpleArray: {
typeWrapper: "wRecord",
typeSource: "TRecA",
typeDelphi: "TRecA",
typePascal: "TRecA",
typeCS: "TRecA",
typeJava: "TRecA",
isRecord: true,
toVariant: "TRecA2Variant",
fromVariant: "Variant2TRecA",
nestedIdentation: " ",
isSimple: null
}
},
{
typeWrapper: "wArray",
typeSource: "",
typeDelphi: null,
typePascal: null,
typeCS: null,
typeJava: null,
isArray: true,
propName: "a2",
fullPropName: "a2",
isSimple: null,
nestedSimpleArray: {
typeWrapper: "wInteger",
typeSource: "Integer",
typeDelphi: "Integer",
typePascal: "Integer",
typeCS: "integer",
typeJava: "int",
nestedIdentation: " ",
isSimple: true
}
},
{
typeWrapper: "wInteger",
typeSource: "Integer",
typeDelphi: "Integer",
typePascal: "Integer",
typeCS: "integer",
typeJava: "int",
propName: "v1",
fullPropName: "v1",
isSimple: true
}
]
}
Offline
used SMS 2.1.2 from Oktober
Offline
The problem is with TRecA.
It is an unmanaged record, i.e. it contains only non managed types (and no string, array or variant).
So in fact, there won't be any RTTI generated by the compiler.
Under Delphi 7, TypeInfo(TRecA) even does not compile!
So you should not use a record as TRecA as stand-alone.
This is a compiler limitation, not a mORMot limitation.
What you should write is:
type
TRecB=packed record
a1:array of packed record
v1,v2:integer;
end;
a2:array of integer;
v1:integer;
end;
Then, the wrapper generated code will be:
function Variant2TRecB(const Value: variant): TRecB;
begin
if VariantType(Value.a)=jvArray then begin
var tmp: TRecB;
tmp.J.SetLength(1);
for var n := 0 to integer(Value.a.length)-1 do begin
var source := Value.a[n];
var dest := tmp.J[0];
dest.v1 := source.v1;
dest.v2 := source.v2;
result.a.Add(dest);
end;
end;
if VariantType(Value.a2)=jvArray then
for var i := 0 to integer(Value.a2.length)-1 do
result.a2.Add(Integer(Value.a2[i]));
result.v1 := Value.v1;
end;
Which sounds quite correct.
Offline
Hi ab,
I can't confirm that. I have changed the TRecB to your proposal (cut & pasted directly from the forum) and the generated code then looks like this:
function Variant2TRecB(const Value: variant): TRecB;
begin
if VariantType(Value.a1)=jvArray then
for var i := 0 to integer(Value.a1.length)-1 do
result.a1.Add(:TRecB.:1(Value.a1[i]));
if VariantType(Value.a2)=jvArray then
for var i := 0 to integer(Value.a2.length)-1 do
result.a2.Add(Integer(Value.a2[i]));
result.v1 := Value.v1;
end;
the context is:
{
name: "TRecB",
fields:
[
{
typeWrapper: "wArray",
typeSource: "",
typeDelphi: null,
typePascal: null,
typeCS: null,
typeJava: null,
isArray: true,
propName: "a1",
fullPropName: "a1",
isSimple: null,
nestedSimpleArray: {
typeWrapper: "wRecord",
typeSource: ":TRecB.:1",
typeDelphi: ":TRecB.:1",
typePascal: ":TRecB.:1",
typeCS: ":TRecB.:1",
typeJava: ":TRecB.:1",
isRecord: true,
toVariant: ":TRecB.:12Variant",
fromVariant: "Variant2:TRecB.:1",
nestedIdentation: " ",
isSimple: null
}
},
{
typeWrapper: "wArray",
typeSource: "",
typeDelphi: null,
typePascal: null,
typeCS: null,
typeJava: null,
isArray: true,
propName: "a2",
fullPropName: "a2",
isSimple: null,
nestedSimpleArray: {
typeWrapper: "wInteger",
typeSource: "Integer",
typeDelphi: "Integer",
typePascal: "Integer",
typeCS: "integer",
typeJava: "int",
nestedIdentation: " ",
isSimple: true
}
},
{
typeWrapper: "wInteger",
typeSource: "Integer",
typeDelphi: "Integer",
typePascal: "Integer",
typeCS: "integer",
typeJava: "int",
propName: "v1",
fullPropName: "v1",
isSimple: true
}
]
}
Last edited by martin.suer (2015-01-16 09:57:21)
Offline
also the generated types for the record are
:TRecB.:1 = record
v1: Integer;
v2: Integer;
end;
TRecB = record
a1: array of :TRecB.:1;
a2: array of Integer;
v1: Integer;
end;
Offline
In fact, if you define:
const __TRecB = 'a1 [v1,v2:integer] a2:array of integer v1:integer';
...
TTextWriter.RegisterCustomJSONSerializerFromText(TypeInfo(TRecB),__TRecB);
as with Delphi 7, everything is fine under XE7.
So there seems to be an issue with the record definition as retrieved from enhanced RTTI (Delphi 2010+).
Offline
I could arrange with defining the text constants and calling RegisterCustomJSONSerializerFromText but that doesn't work either.
In your post http://synopse.info/forum/viewtopic.php … 438#p14438 your generated code "sounds quite correct" but doesn't compile either.
The J in variable tmp is not defined.
tmp.J.SetLength(1);
Offline
Should be fixed by http://synopse.info/fossil/info/2908dff5b2
But I still need to fix the problem with enhanced RTTI (Delphi 2010+).
I want it to work directly, as expected.
Offline
I think I have fix the code generation problem for nested arrays of record with enhanced RTTI (Delphi 2010+).
See http://synopse.info/fossil/info/612863b69f
Now it seems consistent with what is expected by the code generators.
More feedback is welcome!
Offline