2014-09-30 64 views
-1

當我嘗試解組不合時宜的JSON對象時,我期望從UnMarshall函數獲得對象引用,但它會出現nil。但是,當我關閉我的應用程序時,該對象會產生內存泄漏。如何安全UnMarshal JSON對象

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

+0

哪個對象沒有被銷燬。問題中的代碼似乎沒有問題。 – 2014-09-30 16:56:35

+0

在Unmarshal中創建的對象。該函數創建該對象並引發異常,但不會執行任何結果,它將返回零並且該對象處於活動狀態。 – Lucas 2014-09-30 17:00:15

+0

傳遞nil作爲參數在函數中得到了很好的處理,它通過「assert(JsonObj <> nil)」在「CreateObject(JsonObj:TJSONObject)」中進行檢查; – Lucas 2014-09-30 17:06:39

回答

0

的事情是你(可能)使用,如果您創建一個解組對象,並在不同的對待所有對象:

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; 

希望它有助於。

+0

如果'oUnMarshalObject.Unmarshal()'引發一個異常,那麼'oUnMarshalResult'永遠不會被分配。所以這裏的代碼與問題中的代碼意義相同。 -1 – 2014-09-30 17:49:16

+0

不要工作。沒有被破壞的參考不是TJSONUnMarshal,是未編組的對象。 – Lucas 2014-09-30 17:56:03

+0

大衛,是的,應該是一個除了那裏,但意識是如果OVNI對象創建TJSONUnMarshal責任下,摧毀它(TJSONUnMarshal)可以釋放它(解組對象)。 – oPsDCadarn 2014-09-30 18:29:57

0

Unmarshal的函數返回一個新創建的對象,必須這樣來實現:

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

如果在Unmarshal沒有這樣try/except塊,並且看不到的代碼來檢查,那麼它只要它升起就會泄漏。

從外面可以做的並不多。這樣的錯誤不能從外部很容易地修復。一旦物體泄漏,你無法控制它來銷燬它。

您當然應該提交QC報告。在短期內,你可能需要修改Unmarshal代碼,並重新編譯,添加缺少的try/except


我想,其他的方式來處理這個問題是停喂本功能輸入導致異常。

  1. 如果例外是由於傳輸失敗造成的,請對發送的數據進行散列並檢查接收時的散列以減輕問題。
  2. 如果異常是由於客戶端和服務器之間的版本不兼容,請加強版本檢查。
  3. 如果異常是由於世俗的編程錯誤引起的,請修復錯誤。