You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi 12中如何正确将JSON反序列化为TJsonObject?

Delphi中TJson.JsonToObject反序列化TJSONObject字段为空的解决方法

问题背景

使用TJson.JsonToObject将JSON响应反序列化为自定义Delphi类时,除TErrorAdditionalInfo.FInfo(TJSONObject类型)字段始终为空外,其他字段均能正常解析。相关定义如下:

数据结构

ErrorAdditionalInfo

名称类型描述
infoobject附加信息
typestring附加信息类型

ErrorDetail

名称类型描述
additionalInfoErrorAdditionalInfo[]错误附加信息
codestring错误代码
detailsErrorDetail[]错误详情
messagestring错误消息
targetstring错误目标

自定义类结构

TErrorAdditionalInfo = class
private
  FInfo: TJSONObject;
  FType: string;
public
  destructor Destroy; override;

  property Info: TJSONObject read FInfo;
  property &Type: string read FType;
end;

TErrorDetail = class
private
  FAdditionalInfo: TArray<TErrorAdditionalInfo>;
  FCode: string;
  FDetails: TArray<TErrorDetail>;
  FMessage: string;
  FTarget: string;
public
  destructor Destroy; override;

  property AdditionalInfo: TArray<TErrorAdditionalInfo> read FAdditionalInfo;
  property Code: string read FCode;
  property Details: TArray<TErrorDetail> read FDetails;
  property Message: string read FMessage;
  property Target: string read FTarget;
end;

待反序列化JSON示例

{
  "additionalInfo": {
    "info": {
      "Key1": "TextValue",
      "Key2": 123,
      "Key3": [1, 2, 3]
    },
    "type": "SomeType"
  },
  "code": "some code",
  "details": [],
  "message": "Hello world",
  "target": ""
}

问题原因

REST.Json库默认的序列化/反序列化逻辑主要针对自定义实体类和基本数据类型,不直接支持将JSON对象映射到TJSONObject类型的属性,因此无法自动填充FInfo字段。

解决方案

方法一:使用JSON拦截器(推荐)

通过自定义TJsonInterceptor拦截反序列化过程,手动处理info字段的解析,实现优雅的自动映射。

  1. 定义拦截器类,重写ReadJson方法处理info字段:
TErrorAdditionalInfoInterceptor = class(TJsonInterceptor)
public
  procedure ReadJson(const AObject: TObject; const AJson: TJSONValue); override;
end;

procedure TErrorAdditionalInfoInterceptor.ReadJson(const AObject: TObject; const AJson: TJSONValue);
var
  LErrorInfo: TErrorAdditionalInfo;
  LJsonObj: TJSONObject;
  LInfoValue: TJSONValue;
begin
  inherited;
  LErrorInfo := AObject as TErrorAdditionalInfo;
  LJsonObj := AJson as TJSONObject;
  LInfoValue := LJsonObj.GetValue('info');
  if Assigned(LInfoValue) then
    LErrorInfo.FInfo := LInfoValue.Clone as TJSONObject;
end;
  1. 在TErrorAdditionalInfo的Info属性上添加JsonInterceptor注解:
TErrorAdditionalInfo = class
private
  FInfo: TJSONObject;
  FType: string;
public
  destructor Destroy; override;

  [JsonInterceptor(TErrorAdditionalInfoInterceptor)]
  property Info: TJSONObject read FInfo;
  property &Type: string read FType;
end;
  1. 确保在析构函数中释放FInfo,避免内存泄漏:
destructor TErrorAdditionalInfo.Destroy;
begin
  FInfo.Free;
  inherited;
end;

之后再调用TJson.JsonToObject<TErrorDetail>(AResponseString),Info字段即可正确填充为目标TJSONObject。

方法二:手动解析JSON

若场景简单,可先将JSON解析为TJSONObject,再手动为FInfo字段赋值:

var
  LRootJson: TJSONObject;
  LErr: TErrorDetail;
  LAdditionalInfoJson: TJSONObject;
  LInfoJson: TJSONObject;
begin
  LRootJson := TJSONObject.ParseJSONValue(AResponseString) as TJSONObject;
  try
    // 先反序列化基础字段
    LErr := TJson.JsonToObject<TErrorDetail>(LRootJson.ToString);
    try
      // 手动提取并赋值info字段
      LAdditionalInfoJson := LRootJson.GetValue('additionalInfo') as TJSONObject;
      if Assigned(LAdditionalInfoJson) then
      begin
        LInfoJson := LAdditionalInfoJson.GetValue('info') as TJSONObject;
        if Assigned(LInfoJson) and (Length(LErr.AdditionalInfo) > 0) then
          LErr.AdditionalInfo[0].FInfo := LInfoJson.Clone as TJSONObject;
      end;
      // 后续使用LErr对象
    finally
      LErr.Free;
    end;
  finally
    LRootJson.Free;
  end;
end;

注意事项

  • 注意JSON结构与类定义的一致性:你的JSON示例中additionalInfo是单个对象,但类中AdditionalInfo是数组类型,这会导致该字段反序列化异常。需将JSON改为数组格式[{"info":..., "type":...}],或把类中的AdditionalInfo改为单个TErrorAdditionalInfo对象。

内容的提问来源于stack exchange,提问作者Mikhail Kostitsyn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 12:44:59