如何使用 Delphi (Rest.JSON)从JSON中隐藏“ownsObjects”和“listHelper”TObjectList的属性?

klh5stk1  于 11个月前  发布在  其他
关注(0)|答案(5)|浏览(94)

我正在使用 Delphi Tokyo,并试图使用TJson将对象转换为JSON。ObjectToJsonString方法存在于Rest.Json中。一个简单的对象,具有简单的属性,如String或String,这是可以的,但当添加属性TObjectList时,JSON被属性“ownsObjects”和“listHelper”污染,但WebService不接受这些字段。我如何从JSON中“隐藏”它?

u1ehiz5o

u1ehiz5o1#

您可以将JsonReflect属性放在字段上,并控制它们的序列化方式。
下面是一些示例代码,说明如何编写专门的“将此对象列表序列化为数组”属性来处理此问题-只需将单位添加到uses中并将[SerializeObjectList]添加到字段中。

unit CollectionsReflect;

interface

uses
  Generics.Collections,
  REST.JsonReflect;

type
  SerializeObjectListAttribute = class(JsonReflectAttribute)
    constructor Create;
  end;

implementation

uses
  Rtti;

type
  TListOfObjectInterceptor = class(TJSONInterceptor)
    function ObjectsConverter(Data: TObject; Field: string): TListOfObjects; override;
  end;

{ TListOfObjectInterceptor }

function TListOfObjectInterceptor.ObjectsConverter(Data: TObject;
  Field: string): TListOfObjects;
var
  ctx: TRttiContext;
  list: TList<TObject>;
begin
  list := TList<TObject>(ctx.GetType(Data.ClassInfo).GetField(Field).GetValue(Data).AsObject);
  Result := TListOfObjects(list.List);
  SetLength(Result, list.Count);
end;

{ SerializeObjectListAttribute }

constructor SerializeObjectListAttribute.Create;
begin
  inherited Create(ctObjects, rtObjects, TListOfObjectInterceptor);
end;

end.

字符串
不幸的是,相反的方式并不起作用,因为TJSONUnMarshal.PopulateFields内部似乎有一个bug,当试图从json字符串填充列表时会导致AV。

kx5bkwkv

kx5bkwkv2#

// 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":{
      },
      ...
    },
    ...
  }
*)

字符串

pkwftd7m

pkwftd7m3#

我建议你创建一个对象数组而不是列表,如果不是一般的话,那么为了序列化到JSON。这在JSON中效果更好,无论是阅读还是写。只要确保处理所涉及的内存,即释放列表中的对象,就像这样:

procedure TSomeContainerObject.BeforeDestruction;
var
  o: TSomeObjectInTheArray;
begin
  for o in fObjectArray do
    o.Free;
  inherited;
end;

字符串
我通常把它放在我的 *.dpr文件中,只是为了确保:

begin
  {$IFDEF Debug}
  ReportMemoryLeaksOnShutdown := true;
  {$ENDIF}  
  // The rest of your startup code here
end.

lymgl2op

lymgl2op4#

nikhil swami的解决方案的改进是:

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;

字符串

  • ClearJsonObjectList函数将ObjectList替换为一个列表/数组对象,并保留值。
vs3odd8k

vs3odd8k5#

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;

字符串

相关问题