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

问题描述 投票:0回答:5

我正在使用 Delphi Tokyo 并尝试使用 TJson 将对象转换为 json。 Rest.Json 中存在 ObjectToJsonString 方法。 具有简单属性(例如 String 或 Integer)的简单对象没问题,但是当添加属性 TObjectList 时,json 会被属性“ownsObjects”和“listHelper”污染,但 WebService 不接受这些字段。我怎样才能从 Json 中“隐藏”它?

json delphi delphi-10.2-tokyo
5个回答
2
投票

您可以将

JsonReflect
属性放在字段上并控制它们的序列化方式。

这里是一些示例代码,说明如何编写您自己的专用“将此对象列表序列化为数组”属性来处理该问题 - 只需将单位添加到使用中并将

[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
内部似乎存在一个错误,在尝试从 json 字符串填充列表时会导致 AV。


0
投票
    // 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
投票

我建议您创建一个对象数组而不是列表,如果不是一般情况下,则为了序列化为 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.

0
投票

对 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 作为对象,并保留值。

-1
投票
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;
© www.soinside.com 2019 - 2024. All rights reserved.