如何安全地UnMarshal JSON对象

时间:2014-09-30 16:51:47

标签: json delphi unmarshalling datasnap delphi-xe7

当我尝试解组一个格式不正确的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

2 个答案:

答案 0 :(得分: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;

希望它有所帮助。

答案 1 :(得分:0)

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

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

如果try中没有此类except / Unmarshal块,并且我看不到要检查的代码,那么只要它引发就会泄漏。

你可以从外面做很多事情。像这样的bug无法从外部轻松修复。一旦物体泄漏,你就无法抓住它来摧毁它。

您当然应该提交质量控制报告。在短期内,您可能需要修改Unmarshal代码并重新编译,以添加缺少的try / except


我认为处理问题的另一种方法是停止提供导致异常的此功能输入。

  1. 如果异常是由传输失败引起的,请对传输的数据进行哈希处理,并在收到时检查哈希以缓解问题。
  2. 如果例外是由客户端和服务器之间的版本不兼容引起的,请加强版本检查。
  3. 如果异常是由于普通的编程错误引起的,请修复错误。