Git Product home page Git Product logo

delphi-neon's Introduction

Neon - JSON Serialization Library for Delphi


Neon Library

What is Neon

Top language GitHub release GitHub issues GitHub PR GitHub commit activity GitHub last commit GitHub contributors GitHub license

Neon is a serialization library for Delphi that helps you to convert (back and forth) objects and other values to JSON. It supports simple Delphi types but also complex class and records. Neon has been designed with REST in mind, to exchange pure data between applications with no "metadata" or added fields, in fact Neon is the default JSON serialization engine for the WiRL REST Library.

Please take a look at the Demos to see Neon in action.

Neon Main Demo

This is the main demo where you can see how you can serialize/deserialize simple types, records, classes, Delphi specific types (TStringList, TDataSet, etc...):

Neon Mega Demo

Neon Benchmarks Demo

This new demo tries to compare the standard TJSON serialization engine with the TNeon engine, with a few changes you can compare TNeon with other serialization engines out there:

Neon Benchmarks Demo

A Neon Introduction by Holger Flick (Video)

Modern Delphi web development #7

General Features

Configuration

Extensive configuration through INeonConfiguration interface:

  • Word case (Unchanged, UPPERCASE, lowercase, PascalCase, camelCase, snake_case)
  • CuStOM CAse (through anonymous method)
  • Member types (Fields, Properties)
  • Option to ignore the "F" if you choose to serialize the fields
  • Member visibility (private, protected, public, published)
  • Custom serializer registration
  • Use UTC date in serialization
  • Auto creation of nil (object) members

Delphi Types Support

Neon supports the (de)serialization of most Delphi standard types, records, array and of course classes. Classes can be complex as you want them to be, can contain array, (generic) lists, sub-classes, record, etc...

Simple values

  • Basic types: string, Integer, Double, Boolean, TDateTime

Complex values

  • Dynamic Arrays of (basic types, records, classes, etc...)
  • Records with fields of (basic types, records, classes, arrays, etc...)
  • Classes with fields of (basic types, records, classes, arrays, etc...)
  • Generic lists
  • Dictionaries (key must be of type string)
  • Streamable classes

Custom Serializers

  • Inherit from TCustomSerializer and register the new serializer class in the configuration

Todo

Code
  • More Unit Tests

Prerequisite

This library has been tested with Delphi 12 Athens, Delphi 11 Alexandria, Delphi 10.4 Sydney, Delphi 10.3 Rio, Delphi 10.2 Tokyo, but with a minimum amount of work it should compile with Delphi XE7 and higher

Libraries/Units dependencies

This library has no dependencies on external libraries/units.

Delphi units used:

  • System.JSON (DXE6+)
  • System.Rtti (D2010+)
  • System.Generics.Collections (D2009+)

Installation

Simply add the source path "Source" to your Delphi project path and.. you are good to go!

Code Examples

Serialize an object

Using TNeon utility class

The easiest way to serialize and deserialize is to use the TNeon utility class:

Object serialization:

var
  LJSON: TJSONValue;
begin
  LJSON := TNeon.ObjectToJSON(AObject);
  try
    Memo1.Lines.Text := TNeon.Print(LJSON, True);
  finally
    LJSON.Free;
  end;
end;

Object deserialization:

var
  LJSON: TJSONValue;
begin
  LJSON := TJSONObject.ParseJSONValue(Memo1.Lines.Text);
  try
    TNeon.JSONToObject(AObject, LJSON, AConfig);
  finally
    LJSON.Free;
  end;

Using TNeonSerializer and TNeonDeserializer classes

Using the TNeonSerializerJSON and TNeonDeserializerJSON classes you have more control over the process.

Object serialization:

var
  LJSON: TJSONValue;
  LWriter: TNeonSerializerJSON;
begin
  LWriter := TNeonSerializerJSON.Create(AConfig);
  try
    LJSON := LWriter.ObjectToJSON(AObject);
    try
      Memo1.Lines.Text := TNeon.Print(LJSON, True);
      MemoError.Lines.AddStrings(LWriter.Errors);
    finally
      LJSON.Free;
    end;
  finally
    LWriter.Free;
  end;
end;

Object deserialization:

var
  LJSON: TJSONValue;
  LReader: TNeonDeserializerJSON;
begin
  LJSON := TJSONObject.ParseJSONValue(Memo1.Lines.Text);
  if not Assigned(LJSON) then
    raise Exception.Create('Error parsing JSON string');

  try
    LReader := TNeonDeserializerJSON.Create(AConfig);
    try
      LReader.JSONToObject(AObject, LJSON);
      MemoError.Lines.AddStrings(LWriter.Errors);
    finally
      LReader.Free;
    end;
  finally
    LJSON.Free;
  end;

Neon configuration

It's very easy to configure Neon,

var
  LConfig: INeonConfiguration;
begin
  LConfig := TNeonConfiguration.Default
    .SetMemberCase(TNeonCase.SnakeCase)     // Case settings
    .SetMembers(TNeonMembers.Properties)    // Member type settings
    .SetIgnoreFieldPrefix(True)             // F Prefix settings
    .SetVisibility([mvPublic, mvPublished]) // Visibility settings

    // Custom serializer registration
    .GetSerializers.RegisterSerializer(TGUIDSerializer)
  ;
end;

Paolo Rossi

delphi-neon's People

Contributors

carlobarazzetta avatar ccy avatar davidevisconti avatar dominikcz avatar fatih-duman avatar ganacereddine avatar gcarneiroa avatar gliden avatar holgerflick avatar jensmertelmeyer avatar mattiavicari avatar paolo-rossi avatar patrickbs96 avatar paustr avatar rjantz2 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

delphi-neon's Issues

Delphi 2010

In my opinion Delphi 2010 is too old :(

In your code I see "string.split" or "string.isEmpty" from System.SysUtils.TStringHelper

TTime Serialization

The TTime is serialized as TDateTime.

12:15:00 is serialized as 1899-12-30T12:15:00.000Z instead of 12:15:00.

Best regards.

Deserialising GUID to TGUID exception: "EInvalidCast"

I can reproduce this exception with the newest version of neon-json with the code below.

program NeonBugTGUID;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  SysUtils,system.json,
    Neon.Core.Types,
    Neon.Core.Attributes,
    Neon.Core.Persistence,
    Neon.Core.Persistence.JSON,
    Neon.Core.Utils;

type
  TMyData = class
  private
  public
    ID: TGUID;
end;

var
  JSONString: string;
  MyData: TMyData;
  JSONValue: TJSONValue;
  config: INeonConfiguration;
begin
  config:=TNeonConfiguration.Default;
  config.SetMembers([TNeonMembers.Fields]);
  try
    JSONString := '{"ID": "B7A1A8D1-82D3-4D02-99C7-6A538B066FC4"}';
    MyData := TMyData.Create;
    JSONValue := TJSONObject.ParseJSONValue(JSONString);

    try
      TNeon.JSONToObject(MyData, JSONValue, config);
      WriteLn('GUID aus JSON gelesen: ', GUIDToString(MyData.ID));
    finally
      JSONValue.Free;
    end;

    ReadLn;
  finally
    MyData.Free;
  end;
end.

Error deserializing nested array json

I am trying to deserialize the following json below, and the component is causing an error in the method.

function TNeonDeserializerJSON.ReadEnumerable(const AParam: TNeonDeserializerParam; const AData: TValue): Boolean;

This is because I have an array within an array, and the elements of the last array are merged between integers and string.
When the system tries to call ReadDataMember again passing LItemValue as an integer, it does not recognize and gives an error.
Would you help me ?

{ "iTotalRecords": 34, "iTotalDisplayRecords": 34, "aaData": [ [ 1, 1, 1, "Papel de 5 cm", "Sim", "Nรฃo", "Nรฃo", " " ], [ 2, 1, 1, "Papel de 6 cm", "Sim", "Nรฃo", "Nรฃo", " " ], [ 3, 1, 1, "Papel de 7 cm", "Sim", "Nรฃo", "Nรฃo", " " ], [ 4, 1, 1, "Papel de 8 cm", "Sim", "Nรฃo", "Nรฃo", " " ], [ 5, 1, 1, "Papel de 9 cm", "Sim", "Nรฃo", "Nรฃo", " " ], [ 6, 1, 1, "Papel de 10 cm", "Sim", "Nรฃo", "Nรฃo", " " ], [ 7, 1, 1, "Papel de 11 cm", "Sim", "Nรฃo", "Nรฃo", " " ], [ 8, 1, 1, "Papel de 12 cm", "Sim", "Nรฃo", "Nรฃo", " " ], [ 9, 1, 1, "Papel de 15 cm", "Sim", "Nรฃo", "Nรฃo", " " ], [ 10, 1, 1, "Papel de 17 cm", "Sim", "Nรฃo", "Nรฃo", " " ], [ 11, 1, 1, "Papel de 20 cm", "Sim", "Nรฃo", "Nรฃo", " " ], [ 12, 1, 1, "Papel de 25 cm", "Sim", "Nรฃo", "Nรฃo", " " ], [ 13, 1, 1, "Papel de 30 cm", "Sim", "Nรฃo", "Nรฃo", " " ], [ 14, 1, 1, "Papel de 35 cm", "Sim", "Nรฃo", "Nรฃo", " " ], [ 15, 1, 1, "Papel de 40 cm", "Sim", "Nรฃo", "Nรฃo", " " ], [ 16, 1, 1, "Papel de 45 cm", "Sim", "Nรฃo", "Nรฃo", " " ], [ 17, 1, 1, "Papel de 50 cm", "Sim", "Nรฃo", "Nรฃo", " " ], [ 18, 1, 1, "Papel de 60 cm", "Sim", "Nรฃo", "Nรฃo", " " ], [ 19, 1, 1, "Papel de 13 cm", "Sim", "Nรฃo", "Nรฃo", " " ], [ 20, 1, 1, "Envelope 12 x 10", "Sim", "Nรฃo", "Nรฃo", " " ], [ 21, 1, 1, "Envelope 10 x 18", "Sim", "Nรฃo", "Nรฃo", " " ], [ 22, 1, 1, "Envelope 12 x 15", "Sim", "Nรฃo", "Nรฃo", " " ], [ 23, 1, 1, "Envelope 12 x 28", "Sim", "Nรฃo", "Nรฃo", " " ], [ 24, 1, 1, "Envelope 15 x 17", "Sim", "Nรฃo", "Nรฃo", " " ], [ 25, 1, 1, "Envelope 15 x 29", "Sim", "Nรฃo", "Nรฃo", " " ], [ 26, 1, 1, "Envelope 20 x 24", "Sim", "Nรฃo", "Nรฃo", " " ], [ 27, 1, 1, "Envelope 20 x 40", "Sim", "Nรฃo", "Nรฃo", " " ], [ 28, 1, 1, "Envelope 25 x 27", "Sim", "Nรฃo", "Nรฃo", " " ], [ 29, 1, 1, "Envelope 25 x 35", "Sim", "Nรฃo", "Nรฃo", " " ], [ 30, 1, 1, "Envelope 30 x 36", "Sim", "Nรฃo", "Nรฃo", " " ], [ 32, 1, 1, "SMS PESADO 1200X1200", "Sim", "Nรฃo", "Nรฃo", " " ], [ 34, 1, 1, "PAPEL GRAU CIRURGICO", "Sim", "Sim", "Sim", " " ], [ 35, 1, 1, "SMS", "Sim", "Sim", "Nรฃo", " " ], [ 36, 1, 1, "Tecido", "Sim", "Sim", "Nรฃo", " " ] ] }

Memory leak trying to deserialize a complex object when it comes a null value in a child object

You can test it with the NeonMainDemo project:

  • Go to 'Complex Types' tab.
  • Set {"name": "Paolo", "Note": null} in the Serialize memo.
  • Press Complex Object at Deserialize.
  • Close the application.
  • How can this be avoided?
  • Is there a way to not have to create the properties in the constructor of the parent object?
    TPerson.Create constructor;
    begin
    FNote: = TNote.Create;
    ...

Thanks and great job!

Wrong interpretation of [NeonInclude(IncludeIf.NotEmpty)] ?

Hi,
i'm not sure, but from my perpective there is a bug in serialization of properities:

[NeonInclude(IncludeIf.NotEmpty)]
property description: string read Getdescription;

"description" will not be serialized when Getdescription() returns a value ...
I'd expect the serialization of "description" in this case ..
Greetings Andy

Nullable<Enum> - Not using custom names

I have tested in my application and with your application to use a Nullable value. Your example is the TClassOfNullables with Nullable

It is not using the NeonEnumNames when used in this manner Nullable

Regards,
Jacques

Add ValueToJSONString (or similar) to JSON persistence

Unless I've missed it, it would be nice for TNeon to have a ValueToJSONString method. Currently I'm using this helper method:

class function TNeonHelper.ValueToJSONString(const AValue: TValue): string;
var
  LJSON: TJSONValue;
begin
  LJSON := ValueToJSON(AValue);
  try
    Result := LJSON.ToString;
  finally
    LJSON.Free;
  end;
end;

Saves having to manage the TJSONValue yourself.. and the reverse:

class function TNeonHelper.JSONStringToValue<T>(const AJSON: string): T;
begin
  Result := JSONStringToValue<T>(AJSON, nil);
end;

class function TNeonHelper.JSONStringToValue<T>(const AJSON: string; const AConfig: INeonConfiguration): T;
var
  LJSON: TJSONValue;
begin
  LJSON := TJSONObject.ParseJSONValue(AJSON);
  if LJSON = nil then
    LJSON := TJSONObject.Create;
  try
    if AConfig = nil then
      Result := JSONToValue<T>(LJSON)
    else
      Result := JSONToValue<T>(LJSON, AConfig);
  finally
    LJSON.Free;
  end;
end;

Failing Tests

When I run the test project I get the following errors:

Failing Tests

  Neon.Tests.Types.Simple.TTestSimpleTypes.TestDateTime.TestDateOnly
  Message: Expected "2019-12-23T00:00:00.000Z" is not equal to actual ""

  Neon.Tests.Types.Simple.TTestSimpleTypes.TestDateTime.TestDateTime
  Message: Expected "2019-12-23T01:01:01.000Z" is not equal to actual ""```

Exception when reading dynamic array of arrays

Using the following code:

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Controls.Presentation, FMX.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    procedure DynArrayTest;
    procedure DynGridTest;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

uses
  System.IOUtils, System.Rtti, System.JSON,
  Neon.Core.Persistence, Neon.Core.Persistence.JSON;

type
  TNeonHelper = class helper for TNeon
  public
    class function JSONStringToValue<T>(const AJSON: string): T; overload;
    class function JSONStringToValue<T>(const AJSON: string; const AConfig: INeonConfiguration): T; overload;
  end;

  TRow = TArray<Int64>;

  TGrid = TArray<TRow>;

  TTest = record
    Grid: TGrid;
    constructor Create(const AWidth, AHeight: Integer);
  end;

  TTest2 = record
    Row: TRow;
    constructor Create(const AWidth: Integer);
  end;

class function TNeonHelper.JSONStringToValue<T>(const AJSON: string): T;
begin
  Result := JSONStringToValue<T>(AJSON, nil);
end;

class function TNeonHelper.JSONStringToValue<T>(const AJSON: string; const AConfig: INeonConfiguration): T;
var
  LJSON: TJSONValue;
begin
  LJSON := TJSONObject.ParseJSONValue(AJSON);
  if LJSON = nil then
    LJSON := TJSONObject.Create;
  try
    if AConfig = nil then
      Result := JSONToValue<T>(LJSON)
    else
      Result := JSONToValue<T>(LJSON, AConfig);
  finally
    LJSON.Free;
  end;
end;

{ TTest }

constructor TTest.Create(const AWidth, AHeight: Integer);
var
  I: Integer;
begin
  SetLength(Grid, AHeight);
  for I := 0 to AHeight - 1 do
    SetLength(Grid[I], AWidth);
end;

{ TTest2 }

constructor TTest2.Create(const AWidth: Integer);
begin
  SetLength(Row, AWidth);
end;

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
begin
  // DynArrayTest;
  DynGridTest;
end;

procedure TForm1.DynArrayTest;
var
  LTest2: TTest2;
  LFileName: string;
begin
  LFileName := TPath.Combine(TPath.GetTempPath, 'test2.json');
  LTest2 := TTest2.Create(5);
  TFile.WriteAllText(LFileName, TNeon.ValueToJSONString(TValue.From(LTest2)));
  LTest2 := TNeon.JSONStringToValue<TTest2>(TFile.ReadAllText(LFileName));
end;

procedure TForm1.DynGridTest;
var
  LTest: TTest;
  LFileName: string;
begin
  LFileName := TPath.Combine(TPath.GetTempPath, 'test.json');
  LTest := TTest.Create(5, 7);
  TFile.WriteAllText(LFileName, TNeon.ValueToJSONString(TValue.From(LTest)));
  LTest := TNeon.JSONStringToValue<TTest>(TFile.ReadAllText(LFileName));
end;

end.

The DynGridTest method manages to serialize the JSON for LTest, however it fails to deserialize. The root cause is the TRttiUtils.CreateNewValue method in Neon.Core.Utils which does not handle tkDynArray, thus raises an exception.

we need a TNeon.Print with the param TJSONAncestor.TJSONOutputOptions

e.g.

class function Print(AJSONValue: TJSONValue; OutputOptions: TJSONAncestor.TJSONOutputOptions; APretty: Boolean): string; overload; static;
var
  LWriter: TStringWriter;
begin
  LWriter := TStringWriter.Create;
  try
    TNeon.PrintToWriter(AJSONValue, LWriter, OutputOptions, APretty);
    Result := LWriter.ToString;
  finally
    LWriter.Free;
  end;
end;

class procedure TNeon.PrintToWriter(AJSONValue: TJSONValue; AWriter: TTextWriter;
  OutputOptions: TJSONAncestor.TJSONOutputOptions; APretty: Boolean);
var
  LJSONString: String;
begin
  LJSONString := AJSONValue.ToJSON(OutputOptions);
  PrintToWriter(LJSONString, AWriter, APretty);
end;

Serialization errors on Custom Managed Records with complex types

Add a new field to your TPerson class in Demo.Neon.Entities for this TExampleCMR to replicate "invalid pointer operation" exception on serialization

  TExampleCMR = Record
  Public
    Info:string;
    KeyPairs: TDictionary<string, string>;

    class operator Initialize(out Dest:TExampleCMR);
    class operator Finalize(var Dest:TExampleCMR);
  End;
...

class operator TExampleCMR.Initialize(out Dest:TExampleCMR);
begin
  Dest.KeyPairs := TDictionary<string, string>.Create;
end;
class operator TExampleCMR.Finalize(var Dest:TExampleCMR);
begin
  Dest.KeyPairs.Free;
end;

Problem on deserialize objectLists inside objectLists

Hi i'm having problem deserializing a complex class, i already seen the complex deserialization on the demos, but my class is little bit more complex, i have ObjectLists inside ObjectLists.
I don't know if i'm doing something wrong when declaring those models, but the property Numeros which is a TObjectList<TNumero> inside the property Enderecos it's not being deserialized.

Here's my model classes(Getters and Setters implementation omitted for code clarity) :

TCliente :

type
  TCliente = class(TComponent)
  public
    constructor Create(AOwner: TComponent); override;
  published
    property idCliente: integer read FidCliente write SetidCliente;
    property NomeFantasia: string read FNomeFantasia write SetNomeFantasia;
    property Enderecos: TObjectList<TEndereco> read FEnderecos write SetEnderecos;
    property NovoCampoString: string read FNovoCampoString write SetNovoCampoString;
  end;

implementation

{ TCliente }

constructor TCliente.Create(AOwner: TComponent);
begin
  inherited;
  Enderecos := TObjectList<TEndereco>.Create;
end;

TEndereco:

type
  TEndereco = class(TComponent)
  public
    constructor Create(AOwner: TComponent); override;
  published
    property idCliente: integer read FidCliente write SetidCliente;
    property idEndereco: integer read FidEndereco write SetidEndereco;
    property Logradouro: string read FLogradouro write SetLogradouro;
    property Bairro: string read FBairro write SetBairro;
    property Cidade: string read FCidade write SetCidade;
    property Numeros: TObjectList<TNumero> read FNumeros write SetNumeros;
  end;

implementation

{ TEndereco }

constructor TEndereco.Create(AOwner: TComponent);
begin
  inherited;
  Numeros := TObjectList<TNumero>.Create(True);
end;

And TNumero:

type
  TNumero = class(TComponent)
  published
    property Numero: string read FNumero write SetNumero;
    property Cor: string read FCor write SetCor;
  end;

implementation

When i manually populate the instance of TCliente class, serialization goes perfectly.
The Neon library serialize the following code :

Cliente := TCliente.Create(self);
Cliente.NomeFantasia := 'Alan';
Cliente.idCliente := 10;
Cliente.Senha := '1234';

Endereco := TEndereco.Create(self);
Endereco.idCliente := 10;
Endereco.idEndereco := 1;
Endereco.Logradouro := 'Rua salvador Simรตes';
Endereco.Bairro := 'Ipiranga';
Endereco.Cidade := 'Sรฃo Paulo';

Numero := TNumero.Create(self);
Numero.Numero := '801';
Numero.Cor := 'Preto';
Endereco.numeros.Add(Numero);

Numero := TNumero.Create(self);
Numero.Numero := '111';
Numero.Cor := 'Amarelo';
Endereco.numeros.Add(Numero);

Cliente.Enderecos.Add(Endereco);

Endereco := TEndereco.Create(self);
Endereco.idCliente := 10;
Endereco.idEndereco := 2;
Endereco.Logradouro := 'Avenida Senador Vergueiro';
Endereco.Bairro := 'Jardim Hollywood';
Endereco.Cidade := 'Sรฃo Bernardo do Campo';

Cliente.Enderecos.Add(Endereco);
LJSON := LWriter.ObjectToJSON(Cliente);

into this json :

{
    "idCliente": 10,
    "NomeFantasia": "Alan",
    "Enderecos": [
        {
            "idCliente": 10,
            "idEndereco": 1,
            "Logradouro": "Rua salvador Simรตes",
            "Bairro": "Ipiranga",
            "Cidade": "Sรฃo Paulo",
            "Numeros": [
                {
                    "Numero": "801",
                    "Cor": "Preto"
                },
                {
                    "Numero": "111",
                    "Cor": "Amarelo"
                }
            ]
        },
        {
            "idCliente": 10,
            "idEndereco": 2,
            "Logradouro": "Avenida Senador Vergueiro",
            "Bairro": "Jardim Hollywood",
            "Cidade": "Sรฃo Bernardo do Campo",
            "Numeros": []
        }
    ],
    "NovoCampoString": ""
}

But when deserialize this exactly same json into a TCliente object using this code :

var
  LJSON: TJSONValue;
  LReader: TNeonDeserializerJSON;
  LConfig: INeonConfiguration;
  Cliente: TCliente;
  LWriter: TNeonSerializerJSON;
begin
  memoError.Lines.Clear;
  mmoDeSerializar.Lines.Clear;

  LJSON := TJSONObject.ParseJSONValue(Memo1.Lines.Text); // < same json generated by the serialization

  Cliente := TCliente.Create(self);
  try
    LConfig := TNeonConfiguration.Default.SetVisibility([mvPublished]).SetPrettyPrint(True);
    LReader := TNeonDeserializerJSON.Create(LConfig);
    try
      LReader.JSONToObject(Cliente, LJSON);
      memoError.Lines.AddStrings(LReader.Errors);

      LWriter := TNeonSerializerJSON.Create(LConfig);
      mmoDeSerializar.Lines.Add(LWriter.ObjectToJSON(Cliente).ToString);
    finally
      LReader.Free;
    end;
  finally
    Cliente.Free;
    LJSON.Free;
  end;
end;

The Neon library don't deserialize the "Numeros" object, just the "Enderecos"
Here is the result:

{
    "idCliente": 10,
    "NomeFantasia": "",
    "Enderecos": [
        {
            "idCliente": 10,
            "idEndereco": 1,
            "Logradouro": "Rua salvador Simรตes",
            "Bairro": "Ipiranga",
            "Cidade": "Sรฃo Paulo"
        },
        {
            "idCliente": 10,
            "idEndereco": 2,
            "Logradouro": "Avenida Senador Vergueiro",
            "Bairro": "Jardim Hollywood",
            "Cidade": "Sรฃo Bernardo do Campo"
        }
    ],
    "NovoCampoString": ""
}

Please, can you help-me find what's wrong ?

Thank you!

TCustomSerializer for Simple Type (not for Class)

Please how to implement TCustomSerializer for TBytes?
The content of TBytes would be a container for a Binary Data, Encrepted Data, ... So marshaling TBytes is made by Base64 encoding/decoding.

  TBytesSerializer = class(TCustomSerializer)
  protected
    class function GetTargetInfo:PTypeInfo;override;
    class function CanHandle(AType:PTypeInfo):Boolean;override;
  public
    function Serialize(const AValue:TValue;ANeonObject:TNeonRttiObject;AContext:ISerializerContext):TJSONValue;override;
    function Deserialize(AValue:TJSONValue;const AData:TValue;ANeonObject:TNeonRttiObject;AContext:IDeserializerContext):TValue;override;
  end;

implementation

class function TBytesSerializer.GetTargetInfo: PTypeInfo;
begin
  Result := TypeInfo(TBytes);
end;

class function TBytesSerializer.CanHandle(AType: PTypeInfo): Boolean;
begin
  Result := (AType=GetTargetInfo);
end;

function TBytesSerializer.Serialize(const AValue:TValue;ANeonObject:TNeonRttiObject;AContext:ISerializerContext):TJSONValue;
var
  LBytes  : TBytes;
  LBase64 : string;
begin
  SetLength(LBytes,AValue.GetArrayLength);
  if Length(LBytes)>0 then 
  begin
    AValue.ExtractRawData(LBytes);
    LBase64 := TBase64.Encode(LBytes);
  end
  else LBase64 := '';
  Result := TJSONString.Create(LBase64);
end;

function TBytesSerializer.Deserialize(AValue:TJSONValue;const AData:TValue;ANeonObject:TNeonRttiObject;AContext:IDeserializerContext):TValue;
var
  LBytes : TBytes;
begin
  LBytes := TBase64.Decode(AValue.Value);
  AData.Make(LBytes,GetTargetInfo,Result);
end;

Best regards.

Unwanted behavior when deserializing empty strings or enums

Hello Paolo
I have updated Delphi-Neon recently and I found different behavior comparing to the version before. I use deserialization from JSON and classes with Nullable<> types.

In short, the problem is with deserializing an empty string from JSON to Nullable<> type. It is deserialized with flag HasValue = false, but should be true.

Here's a simple example that shows the behavior and what's wrong with that. There are 4 test methods. Look for '//FAIL' comment in runTest2 below:

program Example1Proj;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils,
  System.Generics.Collections,
  System.TypInfo,
  System.Json,
  Neon.Core.Types,
  Neon.Core.Attributes,
  Neon.Core.Nullables,
  Neon.Core.Persistence,
  Neon.Core.Persistence.JSON;

type
  TExampleEnumNames = class
  public const
    cEMPTY = '';
    cENUM1 = 'ENUM1';
    EnumNames = cEMPTY + ',' + cENUM1;
  end;

  [NeonEnumNames(TExampleEnumNames.Enumnames)]
  TExampleEnum = (
    evEMPTY,
    evENUM1
  );

  TExampleClass = class
  private
    FExampleEnum: Nullable<TExampleEnum>;
    FExampleString: Nullable<string>;

  public

    [NeonInclude(IncludeIf.NotNull)]
    property exampleEnum: Nullable<TExampleEnum> read FExampleEnum write FExampleEnum;
    [NeonInclude(IncludeIf.NotNull)]
    property exampleString: Nullable<string> read FExampleString write FExampleString;
  end;


function getNeonConfig: INeonConfiguration;
begin
  result := TNeonConfiguration.Default;
  result.SetMemberCase(TNeonCase.Unchanged);
  result.SetMembers([TNeonMembers.Fields, TNeonMembers.Properties]);
  result.SetIgnoreFieldPrefix(True);
  result.SetVisibility([mvPublic, mvPublished]);
  result.SetUseUTCDate(false);
  result.SetEnumAsInt(false);
end;


procedure DeserializeObject(AObject: TObject; const AJson: string);
var
  LJSON: TJSONValue;
  lConfig: INeonConfiguration;
  LReader: TNeonDeserializerJSON;
begin
  lConfig := getNeonConfig;

  LJSON := TJSONObject.ParseJSONValue(AJson);
  if not Assigned(LJSON) then
    raise ENeonException.Create('Unable to parse json');
  try
    LReader := TNeonDeserializerJSON.Create(lConfig);
    try
      LReader.JSONToObject(AObject, LJSON);
      if LReader.Errors.Count > 0 then
        raise ENeonException.Create(LReader.Errors.Text);
    finally
      LReader.Free;
    end;
  finally
    LJSON.Free;
  end;
end;

procedure runTest1;
var
  testObj: TExampleClass;
begin
  testObj := TExampleClass.Create;
  DeserializeObject(testObj, '{ "exampleString": "ABC", "exampleEnum": "ENUM1" }');

  assert(testObj <> nil); //OK
  assert(testObj.exampleString.HasValue = true); //OK
  assert(testObj.exampleString.Equals('ABC')); //OK

  assert(testObj.exampleEnum.HasValue = true); //OK
  assert(testObj.exampleEnum = evENUM1); //OK
end;

procedure runTest2;
var
  testObj: TExampleClass;
begin
  testObj := TExampleClass.Create;
  DeserializeObject(testObj, '{ "exampleString": "", "exampleEnum": "" }');

  { Below there are two fails that I consider as invalid behavior }
  assert(testObj <> nil); //OK
  assert(testObj.exampleString.HasValue = true); //FAIL
  assert(testObj.exampleString.Equals('')); //OK

  assert(testObj.exampleEnum.HasValue = true); //FAIL
  assert(testObj.exampleEnum = evEMPTY); //OK
end;

procedure runTest3;
var
  testObj: TExampleClass;
  z: string;
begin
  testObj := TExampleClass.Create;
  DeserializeObject(testObj, '{ "exampleString": null, "exampleEnum": null }');

  assert(testObj <> nil); //OK
  assert(testObj.exampleString.HasValue = false); //OK
  //assert(testObj.exampleString.Equals('')); //OK - can't test this; it has no value

  assert(testObj.exampleEnum.HasValue = false); //OK
  //assert(testObj.exampleEnum = evEMPTY); //OK - cant't test this; it has no value
end;

procedure runTest4;
var
  testObj: TExampleClass;
begin
  testObj := TExampleClass.Create;
  DeserializeObject(testObj, '{}');

  assert(testObj <> nil); //OK
  assert(testObj.exampleString.HasValue = false); //OK
  //assert(testObj.exampleString.Equals('')); //OK - can't test this; it has no value

  assert(testObj.exampleEnum.HasValue = false); //OK
  //assert(testObj.exampleEnum = evEMPTY); //OK - cant't test this; it has no value
end;

begin
  try
    runTest1;
    runTest2;
    runTest3;
    runTest4;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

In my opinion it works wrong because of the method in Neon.Core.Utils.pas:

      class function TJSONUtils.IsNotEmpty(const AJSON: TJSONValue): Boolean;

There wasn't that method in previous version of Neon and it worked as expected. Now I have this issue. When the string is set and empty in JSON, it should be deserialized as: Value = '' and HasValue = 'True'

So I think that these 2 lines in mentioned method should be removed:

    if AJSON is TJSONString then
      Exit(not (AJSON as TJSONString).Value.IsEmpty);`

When the value is regarded as empty, there is no attempt to deserialize it and HasValue is not set.

Thank you

Read static array issue

In Neon.Core.Persistence.JSON.
function : TNeonDeserializerJSON.ReadArray
Lines : 1228

LItemValue := ReadDataMember(LParam, Result, True);
Should be follow:
LItemValue := ReadDataMember(LParam, AData.GetArrayElement(LIndex), True);

suggestion: Record serializer

This Serializer would be used for Records.

type
  Serializer =
  record
    class function Marshal<T>(const Data:T):string;inline;static;
    class function Unmarshal<T>(const JsonText:string;out Data:T):Boolean;inline;static;
  end;

implementation

class function Serializer.Marshal<T>(const Data:T):string;
begin
  try
    Result := TNeon.ValueToJSON(TValue.From(Data)).ToJSON;
  except
    Result := '{null}';
  end;
end;

class function Serializer.Unmarshal<T>(const JsonText:string;out Data:T):Boolean;
var
  AJSON : TJSONObject;
begin
  AJSON  := TJSONObject.Create;
  Result := False;
  try
    AJSON.Parse(BytesOf(JsonText),0);
    Data   := TNeon.JSONToValue<T>(AJSON);
    Result := True;
  except
    Data := default(T);
  end;
  FreeAndNil(AJSON);
end;

Best regards.

error generating swagger json

I have a problem converting this structure into swagger.json.
If I am calling the /swagger endpoint from WiRL the service crashes.
If I call the GET endpoint that returns this structure then it works fine.

TObjectA = class;

TObjectA = class 
private 
   FNodes: TObjectDictionary<string, TObjectA>
public
   property Nodes : TObjectDictionary<string, TObjectA> read FNodes write FNodes;
end;

How can I fix this problem?

Thanks

Insufficient RTTI available

Hello,

Please note that this exception is raised when this record needed to be serialized:

TFaceLandmark =
record
  KeyPoints : array[1..68] of TPointFloat;
end;

Project raised exception class EInsufficientRtti with message 'Insufficient RTTI available to support this operation'.

Best regards.

Hints and warnings

The library currently compiles with the following hints/warnings:

[dcc32 Warning] Neon.Core.Persistence.JSON.pas(1504): W1002 Symbol 'MinExtended' is specific to a platform
[dcc32 Warning] Neon.Core.Persistence.JSON.pas(1505): W1002 Symbol 'MaxExtended' is specific to a platform
[dcc32 Hint] Neon.Core.Persistence.JSON.pas(1492): H2077 Value assigned to 'LMin' never used
[dcc32 Hint] Neon.Core.Persistence.JSON.pas(1498): H2077 Value assigned to 'LMin' never used
[dcc32 Hint] Neon.Core.Persistence.JSON.pas(1504): H2077 Value assigned to 'LMin' never used
[dcc32 Hint] Neon.Core.Persistence.JSON.pas(1510): H2077 Value assigned to 'LMin' never used
[dcc32 Hint] Neon.Core.Persistence.JSON.pas(1516): H2077 Value assigned to 'LMin' never used
[dcc32 Warning] Neon.Core.Persistence.JSON.pas(1534): W1036 Variable 'LMax' might not have been initialized

Readme.MD not updated?

You have an example line in the Readme file that is:
Memo1.Lines.Text := TJSONUtils.PrettyPrint(LJSON);
But it there does not appear to be a PrettyPrint method in the TJSONUtils class. And it is managed by the Serializer Config.

Help to convert json string to object

Please I am trying a single sample using your demo:

  TResponseConsoleMessage = class
  private
    Fname       : String;
    Fvalue      : String;
  public
    property name        : String            read Fname;
    property value       : String            read Fvalue;
end;

Then I use:

procedure TfrmSerializationComplex.Button1Click(Sender: TObject);
var
  LChats: TResponseConsoleMessage;
  LJSON: TJSONValue;
begin
  MemoW.Lines.Text:='{"name":"DomCompleted","value":"teste"}';
  LChats := TResponseConsoleMessage.Create();
  LJSON := TJSONObject.ParseJSONValue(MemoW.Lines.Text);
  try
    TNeon.JSONToObject(LChats, LJSON, frmConfiguration.BuildSerializerConfig);
  finally
    LJSON.Free;
    LChats.Free;
  end;
end;

But the problem is the Object LChats is always empty. The fields contain empty string after to use JsonToObject.

What am I doing wrong?

Return null instead of empty in Tdatatime

function TNeonSerializerJSON.WriteDate(const AValue: TValue; ANeonObject: TNeonRttiObject): TJSONValue;
begin
case ANeonObject.NeonInclude.Value of
IncludeIf.NotEmpty, IncludeIf.NotDefault:
begin
if AValue.AsExtended = 0 then
Exit(nil);
end;
end;

if AValue.AsType <> 0 then
Result := TJSONString.Create(TJSONUtils.DateToJSON(AValue.AsType, FConfig.UseUTCDate))
else
Result := TJSONNull.Create;

end;

Memory leak on Nullable<class>

Hi, Great library. Does way more than all the others !

If I create a property like
property Prop: Nullable<TObject> read FProp write FProp;
and in the constructor have
FProp := TObject.Create;
if I assign nil to the property in my code like

var x: TMyData;
x := TMyData.Create; // constructor creates instance of TObject for FProp
x.Prop := nil;

x.Prop is not freed. I could free it manually, but in the TNeon.JSONToObject I don't get that opportunity and the object leaks. eg, Json string is
{}
ie there is no Prop in the JSON string. This creates the object correctly but rather than having a nil value for Prop, it has a TObject there and the HasValue property for Prop is true even though it had no value in the JSON.

I looked at the available attributes and couldn't find one that would solve this. Is this a bug or have I done something wrong ?

I think I can get around it by processing the JSON objects and removing any TJsonClass entries that have nothing in them.

MORE DETAIL

It seems the constructor works as expected, so no problem there. It also seems the correct way to destroy a Nullable<TObject> in the destructor is
if FProp.HasValue then
TObject(FProp).Free;

and to assign a nil to the property
TObject(x.Prop).Free;
x.Prop := nil;

and to assign a new non-nil object

TObject(x.Prop).Free;
x.Prop := TObject.Create;

If I make sure I do all this, then no leaks occur.

ReadEnum should use TJSONBool

TNeonDeserializerJSON.ReadEnum should use TJSONBool instead of TJSONTrue and TJSONFalse.

type
  TClassWithBool = class
  private
    FBoolProp: Boolean;
  public
    property BoolProp: Boolean read FBoolProp write FBoolProp;
  end;

procedure TestBool;
var
  LJSON: TJSONObject;
  LReader: TNeonDeserializerJSON;
  LClass: TClassWithBool;
begin
  LClass := nil;
  LReader := nil;
  LJSON := TJSONObject.Create;
  try
    LJSON.AddPair('BoolProp', True);
    LReader := TNeonDeserializerJSON.Create(TNeonConfiguration.Default);
    LClass := TClassWithBool.Create;
    LReader.JSONToObject(LClass, LJSON);
    ShowMessage(LReader.Errors.Text); // => Error converting member [BoolProp] of type [TClassWithBool]: Invalid JSON value. Boolean expected
  finally
    LJSON.Free;
    LClass.Free;
    LReader.Free;
  end;
end;

Suggested changes

function TNeonDeserializerJSON.ReadEnum(const AParam: TNeonDeserializerParam): TValue;
var
  LIndex, LOrdinal: Integer;
  LTypeData: PTypeData;
begin
  if AParam.RttiType.Handle = System.TypeInfo(Boolean) then
  begin
    if AParam.JSONValue is TJSONBool then
      Result := (AParam.JSONValue as TJSONBool).AsBoolean
    else
      raise ENeonException.Create('Invalid JSON value. Boolean expected');
  end

[...]

Cardinal field value which is greater than maxint will lead to convert error.

Unfortunately i don't remember details (fixed that in my project more than 3 months ago) but:

There are problems with deserialization of unsigned types (cardinal/dword/etc).
when you trying to deserialize json to object which has cardinal field and you have numberic value in src json which is greater than maxint - you will receive convert error.

borrowed solution:

unit ReqRes.JSON.Cardinal;

interface
uses
  Neon.Core.Persistence;

procedure RegisterCardinalSerializers(ARegistry: TNeonSerializerRegistry);
implementation
uses
  System.TypInfo,
  System.Json,
  System.Rtti,
  System.SysUtils,
  ReqRes.JSON,
  Neon.Core.Utils,
  Neon.Core.Types,
  Neon.Core.Serializers.RTL;

type
  TCardinalDigestSerializer = class(TCustomSerializer)
  protected
    class function GetTargetInfo: PTypeInfo; override;
    class function CanHandle(AType: PTypeInfo): Boolean; override;
  public
    function Serialize(const AValue: TValue; ANeonObject: TNeonRttiObject; AContext: ISerializerContext): TJSONValue; override;
    function Deserialize(AValue: TJSONValue; const AData: TValue; ANeonObject: TNeonRttiObject; AContext: IDeserializerContext): TValue; override;
  end;

{ TCardinalDigestSerializer }

class function TCardinalDigestSerializer.CanHandle(AType: PTypeInfo): Boolean;
begin
  Result := AType = GetTargetInfo;
end;

function TCardinalDigestSerializer.Deserialize(AValue: TJSONValue;
  const AData: TValue; ANeonObject: TNeonRttiObject;
  AContext: IDeserializerContext): TValue;
var
  lValue: Cardinal;
begin
  if AValue is TJSONNull then
    Exit(TValue.From<Cardinal>(0));
  lValue := StrToUInt(AValue.Value);
  Result := TValue.From<Cardinal>(lValue);
end;

class function TCardinalDigestSerializer.GetTargetInfo: PTypeInfo;
begin
  Result := System.TypeInfo(Cardinal);
end;

function TCardinalDigestSerializer.Serialize(const AValue: TValue; ANeonObject: TNeonRttiObject; AContext: ISerializerContext): TJSONValue;
begin
  Result := TJSONNumber.Create(AValue.AsType<Cardinal>);
end;

procedure RegisterCardinalSerializers(ARegistry: TNeonSerializerRegistry);
begin
  ARegistry.RegisterSerializer(TCardinalDigestSerializer);
end;

end.

Multithread - Access violation when a json is deserialized

I'm experiencing an access violation issue when there is a high level of concurrency with multithreading. I have a service that receives JSON data to insert a record into a database table. I'm using Neon to deserialize the JSON and map it to a class.

When I receive a request in my service, I handle it like this:

TTask.Run(
  procedure
  begin
    TPersistencia.Insert(StompFrame.Body, FConf, StompFrame, Self.FStompClient);
  end
);

In my tests, I sent the exact same JSON 1000 times, and occasionally, during the execution of the process, an access violation occurs when TNeonDeserializerJSON attempts to read the JSON to populate the class:

LReader := TNeonDeserializerJSON.Create(LConfig);
LReader.JSONToObject(LClasseTabela, LJSON);  //<< AV occurs here

If I remove TTask, it works fine but is slower, and I need it to be faster. How can I address this problem?

Here is the callstacks of Delphi:
image

Empty fields

Hello,

Is it possible to include into serialized Json only fields having values different from default (Empty) ones: 0, '', [], ...

Best regards.

There's a way to show null values on DeSerialize ?

Hello Paolo, congratulations on your fantastic library, i believe its the best i've tested so far.
I'm only missing one thing, there's a way to print null values on Deserializing ?

I have a nullable property and i want to show it on json body like "MyProperty": null, its possible ?

i'm trying with the demo, but can't get the null values to show.

paolo

Thank you in advance!

Unintentional free of property in Neon.Core.Persistence.JSON

I've been having a problem with deserializing a class I have. It seems to destroy the property when it should not.

The code is in line 1247 (method TNeonDeserializerJSON.ReadMembers) and the 2 lines are

    LMemberValue := ReadDataMember(LParam, LNeonMember.GetValue);
    LNeonMember.SetValue(LMemberValue);

if I have a class with a property like

property MyProp: TObject read GetMyProp write SetMyProp;

and the SetMyProp looks like this

Procedure SomeObject.SetMyProp(Value: TObject);
begin
if Assigned(FMyProp) then
FMyProp.Free;
FMyProp := Value;
end;

then the 2 mentioned lines perform as follows.

The 1st line gets a copy of the object into LMemberValue
The second line then tries to set the value to the same value, but this ends up disposing of the value.

I suspect this is possibly a technicalality of the code and may not really be a bug, but might be something that cannot easily be remedied. Perhaps a new attribute could solve it. In the mean time I'll try to disable my free in the property setter until after the deserializing has completed.

Another solution would be not to free it in the setter but have the caller free it before setting it, but that doesn't quite feel right.

Any thoughts ?

Deserialize sub-objects which are not created in constructor

Hi,
Our team wants to use Neon library for complex type with sub-objects. When the sub-objects are created in constructor everything works prefectly, but we want to have them unassigned unless they are provided in json.
For example :
We have a class

TPerson = class
  private
    Fname: string;
    FSurname: string;
    FNote: TNote;
  published
    property Name: string read Fname write Fname;

    [NeonProperty('LastName')]
    property Surname: string read FSurname write FSurname;
    property Note: TNote read FNote write FNote;
  end;

When we want to deserialize json:

  {
    "Name":"Paolo",
    "LastName":"Rossi",
    "Note":{
        "Text":"ADFGH"
    }
}

the Note property is skipped and remains nil.

Is it possible to assign the Note property without creating it first in TPerson's constructor?

request

Can I set the number of decimal places for persistence?

How do I use Arrays and Records ?

Passing a record to TNeon.ObjectToJSON doesn't work, and a class containing an array will not be completely serialised (the array field won't even be in the JSON).

Sub-Type & Object serialization

Hello,

When a record embeds an object, the Serialization is done but Deserialization omits the object (would be recreated).

When a Sub-Type of TDateTime is used (TCustomDatetime = type TDateTime), it is serialized to Float.

type
  TSubDateTime = type TDateTime;

  TPersonObject=class
  private
    FP1 : Integer;
    FP2 : TBytes;
    FP3 : string;
  public
    property P1 : Integer read FP1 write FP1;
    property P2 : TBytes  read FP2 write FP2;
    property P3 : string  read FP3 write FP3;
  end;

  TPersonData=
  record
    First ,
    Last  : string;
    Birth : TSubDateTime;
    O     : TPersonObject;
  end;
procedure TForm1.SubTypeBtnClick(Sender: TObject);
var
  LObject : TPersonObject;
  Data    : TPersonData;
  LValue  : TValue;
  LJSON   : TJSONValue;
  sJSON   : string;
begin
  Data   := default(TPersonData);
  Data.O := TPersonObject.Create;
  with Data.O do
  begin
    P1 := 11;
    P2 := [65,66,67];
    P3 := 'Object';
  end;
  with Data do
  begin
    First := 'First';
    Last  := 'Last';
    Birth := Now;
  end;
  LValue           := TValue.From(Data);
  LJSON            := TNeon.ValueToJSON(LValue);
  sJSON            := LJSON.ToJSON;
  Memo1.Lines.Text := '----- Serialize -----';
  Memo1.Lines.Add(sJSON);
  FreeAndNil(LJSON);
  FreeAndNil(Data.O);
  /////////////////////////////////////////////////////////
  LJSON  := TJSONObject.ParseJSONValue(sJSON);
  Data   := TNeon.JSONToValue<TPersonData>(LJSON);
  FreeAndNil(LJSON);
  /////////////////////////////////////////////////////////
  LValue := TValue.From(Data);
  LJSON  := TNeon.ValueToJSON(LValue);
  sJSON  := LJSON.ToJSON;
  FreeAndNil(LJSON);
  Memo1.Lines.Add('----- Deserialize/Serialize -----');
  Memo1.Lines.Add(sJSON);
  if Assigned(Data.O) then FreeAndNil(Data.O);
end;

Best regards.

Set of Enum

I am trying to use a set of ENUM e.g.

[NeonEnumNames('Low Speed,Medium Speed,High Speed')]
TEnumSpeed = (Low, Medium, High);

TEnumSpeedSet = set of TEnumSpeed

In this use case it does not use the NeonEnumNames.

I have then tried to change it to an array:

TEnumSpeedSet = Array of TEnumSpeed

It then creates it correctly, but when serializing back to object it fails?

Any suggestion

Functions ReadFloat and ReadInt64 don't compile in Delphi < 10.3 / 10.4

The functions TNeonDeserializerJSON.ReadFloat and TNeonDeserializerJSON.ReadInt64 in the Source/Neon.Core.Persistence.JSON.pas cause compilation errors in my Delphi version 10.2.

As it turns out System.JSON.TJSONNumber.AsType<T> (line 1523) is only supported from Delphi versions 10.3 up.
See https://docwiki.embarcadero.com/Libraries/Tokyo/en/System.JSON.TJSONNumber_Methods and https://docwiki.embarcadero.com/Libraries/Rio/en/System.JSON.TJSONNumber_Methods

And System.Rtti.TValue.Make<T> (line 1553) is only supported from Delphi 10.4 up.
See https://docwiki.embarcadero.com/Libraries/Rio/en/System.Rtti.TValue.Make and https://docwiki.embarcadero.com/Libraries/Sydney/en/System.Rtti.TValue.Make

Best regards,
Marcus

Error Compilig TBase64 class

I had to add 'public' to let 'overload' method accepted. With visibility default 'published' the class did not compile.

TBase64 = class
public
class function Encode(const ASource: TBytes): string; overload;
class function Encode(const ASource: TStream): string; overload;

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.