Simple JSON deserialization of records incorrect (Delphi Sydney [10.4.1]) Simple JSON deserialization of records incorrect (Delphi Sydney [10.4.1]) json json

Simple JSON deserialization of records incorrect (Delphi Sydney [10.4.1])


To solve the problem temporarily, I have the following quick solution for you:

  • Make a copy of the standard library Data.DBXJSONReflect and name it e.g. Data.TempFix.DBXJSONReflect.
  • Change all includes/uses in your project accordingly.

After that navigate in Data.TempFix.DBXJSONReflect to line 2993:

jsonFieldVal := TJSONArray(JsonValue).Items[I];

And replace it with the following code:

try  jsonFieldVal := TJSONArray(JsonValue).Items[I];except  on e:Exception do    if e is EArgumentOutOfRangeException then      continue    else      raise;end;

After that the whole method should look like this:

function TJSONUnMarshal.JSONToTValue(JsonValue: TJSONValue; rttiType: TRttiType): TValue;var  tvArray: array of TValue;  Value: string;  I: Integer;  elementType: TRttiType;  Data: TValue;  recField: TRTTIField;  attrRev: TJSONInterceptor;  jsonFieldVal: TJSONValue;  ClassType: TClass;  Instance: Pointer;begin  // null or nil returns empty  if (JsonValue = nil) or (JsonValue is TJSONNull) then    Exit(TValue.Empty);  // for each JSON value type  if JsonValue is TJSONNumber then    // get data "as is"    Value := TJSONNumber(JsonValue).ToString  else if JsonValue is TJSONString then    Value := TJSONString(JsonValue).Value  else if JsonValue is TJSONTrue then    Exit(True)  else if JsonValue is TJSONFalse then    Exit(False)  else if JsonValue is TJSONObject then    // object...    Exit(CreateObject(TJSONObject(JsonValue)))  else  begin    case rttiType.TypeKind of      TTypeKind.tkDynArray, TTypeKind.tkArray:        begin          // array          SetLength(tvArray, TJSONArray(JsonValue).Count);          if rttiType is TRttiArrayType then            elementType := TRttiArrayType(rttiType).elementType          else            elementType := TRttiDynamicArrayType(rttiType).elementType;          for I := 0 to Length(tvArray) - 1 do            tvArray[I] := JSONToTValue(TJSONArray(JsonValue).Items[I],              elementType);          Exit(TValue.FromArray(rttiType.Handle, tvArray));        end;      TTypeKind.tkRecord, TTypeKind.tkMRecord:        begin          TValue.Make(nil, rttiType.Handle, Data);          // match the fields with the array elements          I := 0;          for recField in rttiType.GetFields do          begin            Instance := Data.GetReferenceToRawData;            try              jsonFieldVal := TJSONArray(JsonValue).Items[I];            except              on e:Exception do                if e is EArgumentOutOfRangeException then                  continue                else                  raise;            end;            // check for type reverter            ClassType := nil;            if recField.FieldType.IsInstance then              ClassType := recField.FieldType.AsInstance.MetaclassType;            if (ClassType <> nil) then            begin              if HasReverter(ClassType, FIELD_ANY) then                RevertType(recField, Instance,                  Reverter(ClassType, FIELD_ANY),                  jsonFieldVal)              else              begin                attrRev := FieldTypeReverter(recField.FieldType);                if attrRev = nil then                   attrRev := FieldReverter(recField);                if attrRev <> nil then                  try                    RevertType(recField, Instance, attrRev, jsonFieldVal)                  finally                    attrRev.Free                  end                else                 recField.SetValue(Instance, JSONToTValue(jsonFieldVal,                      recField.FieldType));              end            end            else              recField.SetValue(Instance, JSONToTValue(jsonFieldVal,                  recField.FieldType));            Inc(I);          end;          Exit(Data);        end;    end;  end;  // transform value string into TValue based on type info  Exit(StringToTValue(Value, rttiType.Handle));end;