I'm using Delphi Tokyo and trying to convert an object into a json using TJson. ObjectToJsonString method present in Rest.Json. A simple object with simple properties such as String or Integer it's ok, but when a add a property TObjectList, the json is poluted with the properties "ownsObjects" and "listHelper", but the WebService doesn't accept these fields. How can I "hide" it from a Json?
How to hide "ownsObjects" and "listHelper" TObjectList's properties from a Json using Delphi (Rest.JSON)?
2.4k Views Asked by Fernando Vallim At
6
There are 6 best solutions below
1
On
function TSrvMethContab.GetConecctions: TJSONObject;
var
lContext : TDbContext ;
lLista : TList<TConexions>;
jResult : TJSONObject;
begin
lContext := TDbContext.Create(strConexion);
try
lLista := lContext.Select<TConexions>();
jResult := TJson.ObjectToJsonObject(lLista);
jResult.RemovePair('listHelper');
Result := jResult;
finally
lContext.Free;
end;
end;
1
On
// How to hide “ownsObjects” and “listHelper” TObjectList's properties from a Json
type
TSameClass = class(...)
....
public
...
function GetAsJson: string;
...
end;
...
// метод любого класса Txxxxx для получения его json, у которого, для всех его
// переменных с типом TObjectList, будут очищены “ownsObjects” и “listHelper” свойства
function TSameClass.GetAsJson: string;
procedure ClearJsonObjectList(AJson: TJSONObject);
var je: TJSONObject.TEnumerator;
begin
// проходим по всему дереву json и удаляем ненужные нам пары
je := AJson.GetEnumerator();
while je.MoveNext() do
if je.Current.JsonValue is TJSONObject then
// рекурсивный вызов
ClearJsonObjectList(je.Current.JsonValue as TJSONObject)
else
// если есть этот Pair, то есть и другой
if Assigned(AJson.RemovePair('listHelper')) then
AJson.RemovePair('ownsObjects');
end;
var j: TJSONObject;
begin
// получаем json класса, в котором могут быть или не быть TObjectList с ненужными нам парами
j := TJson.ObjectToJsonObject(Self);
// в этой процедуре очищаем полученный json от этих пар
ClearJsonObjectList(j);
// возвращаем результат в виде строки json
Result := j.ToString;
end;
(*
// example
// json before ClearJsonObjectList --------------->
{
"content":{
"checkClose":{
"payments":{
"ownsObjects":true, <<-- must be removed
"listHelper":[ <<-- must be removed
]
},
...
},
"positions":{
"ownsObjects":true, <<-- must be removed
"listHelper":[ <<-- must be removed
]
},
...
},
...
}
// json after ClearJsonObjectList --------------->
{
"content":{
"checkClose":{
"payments":{
},
...
},
"positions":{
},
...
},
...
}
*)
0
On
I recommend that you create an array of objects instead of a list, if not generally, then for the purpose of serialization to JSON. This works much better with JSON, both reading and writing. Just make sure to handle the memory involved, i.e. free the objects in the list, something like this:
procedure TSomeContainerObject.BeforeDestruction;
var
o: TSomeObjectInTheArray;
begin
for o in fObjectArray do
o.Free;
inherited;
end;
I usually put this in my *.dpr file just to make sure:
begin
{$IFDEF Debug}
ReportMemoryLeaksOnShutdown := true;
{$ENDIF}
// The rest of your startup code here
end.
0
On
an improvement on nikhil swami's solution is:
procedure ClearJsonObjectList(AJson: TJSONObject);
function GetAsObjectList(AJson: TJSONObject): TJSONPair;
var
ownsObjects, listHelper: TJSONPair;
begin
Result := nil;
if AJson.Count = 2 then
begin
ownsObjects := AJson.Get('ownsObjects');
listHelper := AJson.Get('listHelper');
if Assigned(ownsObjects) and Assigned(listHelper) then
if (ownsObjects.JsonValue is TJSONBool) and (listHelper.JsonValue is TJSONArray) then
begin
AJson.RemovePair(ownsObjects.JsonString.Value);
AJson.RemovePair(listHelper.JsonString.Value);
Result := listHelper;
end;
end;
end;
var
index: integer;
itemName: string;
itemValue: TJSONObject;
list: TJSONPair;
begin
for index := Pred(AJson.Count) downto 0 do
if AJson.Pairs[index].JsonValue is TJSONObject then
begin
itemValue := TJSONObject(AJson.Pairs[index].JsonValue);
list := GetAsObjectList(itemValue);
if Assigned(list) then
begin
itemName := AJson.Pairs[index].JsonString.Value;
AJson.RemovePair(itemName);
AJson.AddPair(itemName, list.JsonValue);
end
else
ClearJsonObjectList(itemValue);
end;
end;
- the ClearJsonObjectList function will replace the ObjectList as an object with a list/array, keeping the values.
1
On
uses
System.Json;
Function GetNode(AJson, ANode: String): String;
var
JsonArray: TJSONArray;
JsonValue: TJSONValue;
begin
JSonValue := TJSonObject.ParseJSONValue(AJson);
if Assigned(JSonValue) and (JSonValue is TJSONObject) then
JsonArray := TJSONObject(JSonValue).GetValue(ANode) as TJSONArray;
Result := JsonArray.ToString
end;
Example of use:
StringJson := GetNode(DirtyJsonString, 'listHelper');
You can put the
JsonReflectattribute on fields and control how they are being serialized.Here is some example code of how to write your own specialized "serialize this object list as array" attribute that takes care of that - just add the unit to the uses and add
[SerializeObjectList]to your field.Unfortunately the opposite way does not work this way as there seems to be a bug inside of
TJSONUnMarshal.PopulateFieldsthat causes an AV when trying to populate the list from the json string.