You are not logged in.
Hi,
I search for many hours without found a solution
I have a complex structure of class with TObjectList.
I can serialize JSON from the object but if I unserialize to object, all my TObjectList have no data and isValid result if false
Could you help me
This is my code
CLASS DECLARATION
type
TBaseClass = class(TSynAutoCreateFields)
private
FID: RawUTF8;
published
property ID : RawUTF8 read FID write FID;
end;
type
TGroup = class(TBaseClass)
private
FName: RawUTF8;
published
property Name : RawUTF8 read FName write FName;
end;
type
TGroups = class(TSynAutoCreateFields)
private
FGroupID: RawUTF8;
FUserID: RawUTF8;
FGroup: TGroup;
function GetGroup: TGroup;
published
property UserID : RawUTF8 read FUserID write FUserID;
property GroupID : RawUTF8 read FGroupID write FGroupID;
property Group : TGroup read FGroup;
end;
type
TUser = class(TBaseClass)
private
FUsername: RawUTF8;
FFirstName: TNullableUTF8Text;
FLastName: TNullableUTF8Text;
FGroups: TObjectList;
FCanSynchronize: boolean;
function GetGroups(Index: Integer): TGroups;
published
property Username : RawUTF8 read FUsername write FUsername;
property FirstName : TNullableUTF8Text read FFirstName write FFirstName;
property LastName : TNullableUTF8Text read FLastName write FLastName;
property Groups: TObjectList read FGroups;
end;
type
TCompany = class(TBaseClass)
private
FCanSynchronize: boolean;
FType: Integer;
FName: RawUTF8;
published
property CanSynchronize : boolean read FCanSynchronize write FCanSynchronize;
property Name : RawUTF8 read FName write FName;
property Types : Integer read FType write FType;
end;
type
TSession = class(TBaseClass)
private
FUserID: RawUTF8;
FUser: TUser;
FCompanyID: RawUTF8;
FCompany: TCompany;
function GetCompany: TCompany;
function GetUser: TUser;
published
property UserID : RawUTF8 read FUserID write FUserID;
property User : TUser read FUser;
property CompanyID : RawUTF8 read FCompanyID write FCompanyID;
property Company : TCompany read FCompany;
end;
type
TSessions = class(TSynAutoCreateFields)
private
FSession: TSession;
function GetSession: TSession;
published
property Session : TSession read FSession;
end;
GENERATE JSON (WORK)
var
lSessions : TSessions;
begin
lSessions := TSessions.Create;
lSessions.Session.UserID := ('d0d49a49-7cd2-4336-a85e-0bd60584178e');
lSessions.Session.User.Username := 'admin';
lSessions.Session.User.Groups.Add(TGroups.Create); //Add one group into JSON
TGroups(lSessions.Session.User.Groups[0]).UserID := ('d0d49a49-7cd2-4336-a85e-0bd60584178e');
TGroups(lSessions.Session.User.Groups[0]).Group.Name := 'TEST';
lSessions.Session.CompanyID := ('a58907b7-8be2-4a14-9a82-0bd60581fad0');
lSessions.Session.Company.Name := 'Acomba Demo';
TJSONSerializer.RegisterClassForJSON([TSessions,TUser,TCompany,TGroups,TGroup]);
Memo1.Text := ObjectToJSON(lSessions, [woHumanReadable, woObjectListWontStoreClassName]);
//I must to declare woObjectListWontStoreClassName because the REAL JSON come from another system and doesn't have ClassName field
//But if I undeclare woObjectListWontStoreClassName deserialization work
FreeAndNil(lSessions);
JSON RESULT
{
"Session": {
"UserID": "d0d49a49-7cd2-4336-a85e-0bd60584178e",
"User": {
"Username": "admin",
"FirstName": null,
"LastName": null,
"Groups":
[{
"UserID": "d0d49a49-7cd2-4336-a85e-0bd60584178e",
"GroupID": "",
"Group": {
"Name": "TEST",
"ID": ""
}
}
],
"ID": ""
},
"CompanyID": "a58907b7-8be2-4a14-9a82-0bd60581fad0",
"Company": {
"CanSynchronize": false,
"Name": "Acomba Demo",
"Types": 0,
"ID": ""
},
"ID": ""
}
}
LOAD JSON INTO OBJECT
var
lSessions : TSessions;
isValid : boolean;
begin
lSessions := TSessions.Create;
TJSONSerializer.RegisterClassForJSON([TSessions,TUser,TCompany,TGroups,TGroup]);
JSONToObject(lSessions, @Memo1.Text[1], isValid, TSessions);
FreeAndNil(lSessions);
My question is, could I use TObjectList without ClassName field into JSON ?
Or how I can change my structure with arrays at least TObjectList ?
Thank you
Offline
It is not possible, since the TObjectList property has no RTTI information.
What you may do is use a TGroupsObjArray = array of TGroups instead of the TObjectList for storing the array.
Then, serialization should work as expected.
Offline
Ok thank you
That was I expected
I'll ready try with TGroupsArray= array of TGroups but not work when deserialize
My array is always empty even I tried TJSONSerializer.RegisterObjArrayForJSON(TypeInfo(TGroupsArray),TGroups);
Can you give me an exemple with array and unserialize ?
Thank
Offline
I found solution with Collection
This is my code for someone need it
CLASS DEFINITION
type
TBaseClass = class(TSynAutoCreateFields)
private
FID: RawUTF8;
published
property ID : RawUTF8 read FID write FID;
end;
type
TGroup = class(TBaseClass)
private
FName: RawUTF8;
published
property Name : RawUTF8 read FName write FName;
end;
type
//CHANGE CLASS TYPE HERE FOR TCollectionItemAutoCreateFields
TGroups = class(TCollectionItemAutoCreateFields)
private
FGroupID: RawUTF8;
FUserID: RawUTF8;
FGroup: TGroup;
published
property UserID : RawUTF8 read FUserID write FUserID;
property GroupID : RawUTF8 read FGroupID write FGroupID;
property Group : TGroup read FGroup;
end;
//THIS IS NEW CLASS FOR MANAGE COLLECTION AND ACCESS LIKE AN ARRAY
type
TGroupsCollection = class(TInterfacedCollection)
private
function GetCollItem(aIndex: Integer): TGroups;
protected
class function GetClass: TCollectionItemClass; override;
public
function Add: TGroups;
property Item[aIndex: Integer]: TGroups read GetCollItem; default;
end;
type
TUser = class(TBaseClass)
private
FUsername: RawUTF8;
FFirstName: TNullableUTF8Text;
FLastName: TNullableUTF8Text;
FGroups: TGroupsCollection;
FCanSynchronize: boolean;
published
property Username : RawUTF8 read FUsername write FUsername;
property FirstName : TNullableUTF8Text read FFirstName write FFirstName;
property LastName : TNullableUTF8Text read FLastName write FLastName;
property Groups: TGroupsCollection read FGroups;
end;
type
TCompany = class(TBaseClass)
private
FCanSynchronize: boolean;
FType: Integer;
FName: RawUTF8;
published
property CanSynchronize : boolean read FCanSynchronize write FCanSynchronize;
property Name : RawUTF8 read FName write FName;
property Types : Integer read FType write FType;
end;
type
TSession = class(TBaseClass)
private
FUserID: RawUTF8;
FUser: TUser;
FCompanyID: RawUTF8;
FCompany: TCompany;
published
property UserID : RawUTF8 read FUserID write FUserID;
property User : TUser read FUser;
property CompanyID : RawUTF8 read FCompanyID write FCompanyID;
property Company : TCompany read FCompany;
end;
type
TSessions = class(TSynAutoCreateFields)
private
FSession: TSession;
function GetSession: TSession;
published
property Session : TSession read FSession;
end;
CODE FOR CLASS TGroupsCollection
function TGroupsCollection.Add: TGroups;
begin
result := TGroups(inherited Add);
end;
class function TGroupsCollection.GetClass: TCollectionItemClass;
begin
result := TGroups;
end;
function TGroupsCollection.GetCollItem(aIndex: Integer): TGroups;
begin
result := TGroups(GetItem(aIndex));
end;
CREATE JSON FILE
lSessions := TSessions.Create;
lSessions.Session.UserID := ('d0d49a49-7cd2-4336-a85e-0bd60584178e');
lSessions.Session.User.Username := 'admin';
with lSessions.Session.User.Groups.Add do
begin
Group.Name := 'ADMIN';
end;
with lSessions.Session.User.Groups.Add do
begin
Group.Name := 'INVITE';
end;
lSessions.Session.CompanyID := ('a58907b7-8be2-4a14-9a82-0bd60581fad0');
lSessions.Session.Company.Name := 'Acomba Demo';
Memo1.Text := ObjectToJSON(lSessions, [woHumanReadable]);
FreeAndNil(lSessions);
JSON CREATED
{
"Session": {
"UserID": "d0d49a49-7cd2-4336-a85e-0bd60584178e",
"User": {
"Username": "admin",
"FirstName": null,
"LastName": null,
"Groups":
[{
"UserID": "",
"GroupID": "",
"Group": {
"Name": "ADMIN",
"ID": ""
}
},{
"UserID": "",
"GroupID": "",
"Group": {
"Name": "INVITE",
"ID": ""
}
}
],
"ID": ""
},
"CompanyID": "a58907b7-8be2-4a14-9a82-0bd60581fad0",
"Company": {
"CanSynchronize": false,
"Name": "Acomba Demo",
"Types": 0,
"ID": ""
},
"ID": ""
}
}
UNSERIALIZE JSON INTO OBJECT
lSessions := TSessions.Create;
JSONToObject(lSessions, @Memo1.Text[1], isValid, nil, [j2oIgnoreUnknownProperty]);
FreeAndNil(lSessions);
Now you can access Groups like this : lSessions.session.user.groups[0].Group.Name or lSessions.session.user.groups.item[0].Group.Name
Offline
Sure
I'll email it today.
Just for your information, I base ma code on "20 - DTO interface based service" exemple
Offline
Maybe I'll need to use array at least of CollectionItem
Could you give me a little exemple to use array in class with my class structure ?
Thank you
Offline
Is it possible for the to skip serialization for objects with no values assigned to them with this model using TSynPersistent?
Last edited by dzun (2016-02-17 00:03:12)
Offline
I think if you set j2oIgnoreUnknownProperty in JSONToObject option will skip item if you don't have it in your class
Offline
in current version , it is still need use array instead of the TObjectList for storing the array?
Windows 7 64bit. Delphi XE10.2 Professional.
Offline
TObjectList has no type information about the actual class it stores.
TObjectList<> generic version neither (even on newer versions of the compiler, Delphi RTTI is broken in this aspect).
This is why T*ObjArray, and its associated ObjArray*() functions, is a good way of storing a list of objects.
For both SOA and ORM.
Offline
I was try to use TObjectList<T> generic version , can not find a way to register the class T .
I suppose that , if there is a way to notice the framework which CLASS to convert , that must be work .
generic type is a trend ..
Windows 7 64bit. Delphi XE10.2 Professional.
Offline
serializing seem work pretty good, difficult part is deserializing
Windows 7 64bit. Delphi XE10.2 Professional.
Offline
/sub
I have hard time also to deserialize into TObjectList. For me, I can't use TCollectionItem or array.
There is a possibility to register the class so the deserialize have enough info to produce TObjectList of T, or TObjectList<T> even it's only for Windows?
Or can you implement something like this? Even if will not support old versions of Delphi or FPC. I think will be high use for many people with specific case and I think in time FPC will catch up with generics.
Or can be simple TObjectList and the user provide the class as parameter or something like this.
Thank you.
Offline
Plain TObjectList doesn't support enough information for deserialization.
It is a dead end.
What could be done, is register TObjectList<T> with its plain T class...
Any commit is welcome.
Offline
I use the following code and it's worked fine:
procedure TMainForm1.Refresh;
var
LTable: RawJSON;
LObjectList: TObjectList;
LValid: Boolean;
begin
...
LObjectList := TObjectList.Create();
try
JSONToObject(LObjectList, PUTF8Char(LTable), LValid, TSQLMyRecord);
...
finally
LObjectList.Free();
end;
end;
Note the last parameter to JSONToObject.
Offline
@Chaa which version you are using ?
raising error ... Invalid variant op
Windows 7 64bit. Delphi XE10.2 Professional.
Offline
I use 1.18.3759, but it should work with latest mORMot version.
It's documented at:
https://synopse.info/files/html/api-1.1 … ONTOOBJECT
- won't handle TObjectList (even if ObjectToJSON is able to serialize them) since has no way of knowing the object type to add (TCollection.Add is missing), unless:
1. you set the TObjectListItemClass property as expected, and provide a TObjectList object, or
2. woStoreClassName option has been used at ObjectToJSON() call and the corresponding classes have been previously registered by TJSONSerializer.RegisterClassForJSON() (or Classes.RegisterClass)
So, if you specify class for TObjectList items, that should work.
Offline
JSONObject parse = (JSONObject) JSON.parse(resp);
JSONArray itemArray = parse.getJSONArray("items");
for (int i = 0; i < itemArray.size(); i++) {
JSONObject item = itemArray.getJSONObject(i);
System.out.println(item.getString("seqNo")
+ item.getString("caseDate")
+ item.getString("caseNumber")
+ item.getString("court") + item.getString("amount"));
}
{
"total": 2,
"items": [
{
"seqNo": 1,
"caseDate": "2017-06-09",
"caseNumber": "1212",
"court": "court1",
"amount": "3.000000"
},
{
"seqNo": 2,
"caseDate": "2017-06-09",
"caseNumber": "2233",
"court": "court2",
"amount": "12.000000"
}
]
}
parse by jasonfast , no RTTI reqiured.
Windows 7 64bit. Delphi XE10.2 Professional.
Offline