-1

当我尝试解组格式不正确的 JSON 对象时,我希望来自 UnMarshall 函数的对象引用,但它为零。但是,当我关闭我的应用程序时,该对象会产生内存泄漏。

TMyObject = class
private
  FName: String;
end;

AJSON := TJSONObject.ParseJSONValue('{ type: "MyObject.TMyObject", id: 1, fields: { FName: "David", FAge: 20 } }');

//FAge attribute don't exists in TMyObject, so it raises an exception when unmarshalling


with TJSONUnMarshal.Create() do  
begin  
  try
    Result := Unmarshal( AJSON );
    //First chance exception at $77322F71. Exception class EConversionError with message 'Internal: Field FAge cannot be found in type TMyObject'. Process MyApp.exe (3056)
  finally
    Free();
  end;
  //Here the result is nil, but internally the object was created and is alive
end

function TJSONUnMarshal.Unmarshal(Data: TJSONValue): TObject;
  var
    Root: TJSONObject;
begin
  if not (Data is TJSONObject) then
    raise EConversionError.Create(SCannotCreateObject);

  // clear previous warnings
  ClearWarnings;
  Root := TJSONObject(Data);
  try
    Result := CreateObject(Root)
  finally
    FObjectHash.Clear;
  end;
end;

如果 JSON 对象不是预期的格式,它会引发异常,但不会破坏对象创建的引用,也不会在函数中返回它。

因此,使用我的服务器的人可以调用一些函数,并且没有任何保证发送到请求中的 JSON 格式正确。

我该如何处理这种情况?有一种方法可以使用相应的类验证 JSON 对象吗?

ps:我用的是Delphi XE7

4

2 回答 2

0

Unmarshal这样返回一个新创建的对象的函数必须像这样实现:

function CreateObj: TObject;
begin
  Result := TObject.Create;
  try
    // do stuff with Result
  except
    Result.Free;
    raise;
  end;
end;

如果没有这样的try/exceptUnmarshal,并且我看不到要检查的代码,那么它会在它引发时泄漏。

你可以从外面做的不多。像这样的错误不能从外部轻易修复。一旦对象泄漏,您将无法抓住它来破坏它。

您当然应该提交 QC 报告。短期内你可能需要修改Unmarshal代码,重新编译,添加缺少的try/except


我想解决问题的另一种方法是停止提供导致异常的函数输入。

  1. 如果异常是由于传输失败造成的,则对传输的数据进行哈希处理并在接收时检查哈希值以缓解问题。
  2. 如果异常是由于客户端和服务器之间的版本不兼容,请加强版本检查。
  3. 如果异常是由于普通的编程错误引起的,请修复错误。
于 2014-09-30T18:19:02.890 回答
0

如果您创建一个 Unmarshal 对象并将所有对象分开处理,那么事情就是您的(也许)使用:

AJSON := TJSONObject.ParseJSONValue('{ type: "MyObject.TMyObject", id: 1, fields: { FName: "David", FAge: 20 } }');

try
  if Assigned(AJSON) then
    UnmarshalThisObject(AJSON);  
finally
  FreeAndNil(AJSON);
end;

procedure UnmarshalThisObject(AJSON: TJSONObject);
var
  oUnMarshalObject: TJSONUnMarshal;
  oUnMarshalResult: TUnmarshalType {dont know};
begin
  if Assigned(AJSON) then
  begin
    oUnMarshalObject := TJSONUnMarshal.Create();
    try
      oUnMarshalResult := oUnMarshalObject.Unmarshal(AJSON);
    finally
      FreeAndNil(oUnMarshalResult);
      FreeAndNil(oUnMarshalObject);
    end;
  end;
end;

希望能帮助到你。

于 2014-09-30T17:42:53.603 回答