Icon View Thread

The following is the text of the current message along with any replies.
Messages 1 to 4 of 4 total
Thread JSON: Array Properties Not Recognized
Thu, Dec 3 2015 9:13 PMPermanent Link

Doug B

After having read this topic:

http://www.elevatesoft.com/forums?action=view&category=ewb&id=ewb_general&msg=5818&start=1&keywords=i%20parse%20json&searchbody=True&forum=EWB_General#5818

I implemented custom code to read the contents of an Integer array property.

However, I'm having trouble when attempting to save the array property.  It looks like array properties aren't even recognized as I never see the code display my array property:

In WebCore:

procedure TPersistent.SaveProperties(AWriter: TWriter);
var
  TempCount: Integer;
  I: Integer;
  TempName: String;
begin
  TempCount:=PropertyCount;
  for I:=0 to TempCount-1 do
     begin
     TempName:=PropertyName(I);
window.alert(TempName); <<========================================
     if (TempName <> '') then
        SaveProperty(AWriter,TempName);
     end;
end;

Here's what I'm trying to do with my TPersistent descendant class:

procedure TTestObject.SaveProperty(AWriter: TWriter; const AName: String);
var
 PropName: string;
 Count: Integer;
 HasElements: Boolean;
 i: Integer;
begin
 PropName := AName;
window.alert(PropName);
 if (PropName <> '') then
 begin
   if not SameText(PropName,'TestIntArray') then
     inherited SaveProperty(AWriter, AName)
   else
   begin
     AWriter.PropertyName(PropName);
     Count := Length(fTestIntArray);
     HasElements := (Count > 0);
     AWriter.BeginArray(HasElements);
     for i := 0 to Count-1 do
     begin
       AWriter.Append(IntToStr(fTestIntArray[i]));
       if (i < Count-1) then
         AWriter.Separator;
     end;
     AWriter.EndArray(HasElements);
   end;
 end;
end;

In addition, the call to AWriter.Append() won't compile unless you move it out of the protected section of TPersistent.

Any tips on how to achieve this?

Thanks,
Doug
Fri, Dec 4 2015 12:53 PMPermanent Link

Tim Young [Elevate Software]

Elevate Software, Inc.

Avatar

Email timyoung@elevatesoft.com

Doug,

<< However, I'm having trouble when attempting to save the array property.  It looks like array properties aren't even recognized as I never see the code display my array property: >>

Please post the class definition and implementation for the TTestObject class.

Tim Young
Elevate Software
www.elevatesoft.com
Fri, Dec 4 2015 3:21 PMPermanent Link

Doug B

Here is the test unit.

Thanks,
Doug

unit TestCases;

interface

uses WebCore, WebDOM;

type
  TNested = class(TPersistent)
    fValue: Integer;
    fDescription: string;
  published
    property Value: Integer read fValue write fValue;
    property Description: string read fDescription write fDescription;
  end;

  TTestIntArray = array of Integer;

  TComposite = class(TPersistent)
    fField: string;
    fNested: TNested;
    fTestIntArray: TTestIntArray;
  protected
    procedure SaveProperty(AWriter: TWriter; const AName: String); override;
  public
    constructor Create; override;
    destructor Destroy; override;
    function ToJson: string;
  published
    property Field: string read fField write fField;
    property Nested: TNested read fNested write fNested;
    property TestIntArray: TTestIntArray read fTestIntArray write fTestIntArray;
  end;

function TestJson: string;

implementation

constructor TComposite.Create;
begin
 inherited Create;
 fNested := TNested.Create;
 SetLength(fTestIntArray, 5);
end;

destructor TComposite.Destroy;
begin
 fNested.Free;
 inherited Destroy;
end;

procedure TComposite.SaveProperty(AWriter: TWriter; const AName: String);
var
 PropName: string;
 Count: Integer;
 HasElements: Boolean;
 i: Integer;
begin
 PropName := AName;
window.alert(PropName);
 if (PropName <> '') then
 begin
   if not SameText(PropName,'TestIntArray') then
     inherited SaveProperty(AWriter, AName)
   else
   begin
     AWriter.PropertyName(PropName);
     Count := Length(fTestIntArray);
     HasElements := (Count > 0);
     AWriter.BeginArray(HasElements);
     for i := 0 to Count-1 do
     begin
       AWriter.Append(IntToStr(fTestIntArray[i]));
       if (i < Count-1) then
         AWriter.Separator;
     end;
     AWriter.EndArray(HasElements);
   end;
 end;
end;

function TComposite.ToJson: string;
var
 Writer: TWriter;
begin
 Writer := TWriter.Create;
 try
   Writer.Initialize;
   Save(Writer);
   Result := Writer.Output;
 finally
   Writer.Free;
 end;
end;
   
function TestJson: string;
var
 c: TComposite;
begin
 c := TComposite.Create;
 try
   c.Field := 'field';
   c.Nested.Value := 10;
   c.Nested.Description := 'description';
   Result := c.ToJson;
 finally
   c.Free;
 end;
end;

end.
Mon, Dec 7 2015 3:30 PMPermanent Link

Tim Young [Elevate Software]

Elevate Software, Inc.

Avatar

Email timyoung@elevatesoft.com

Doug,

You can't use SaveProperty with array properties because array properties aren't published for the purposes of persistence, even if they are marked as published.  EWB doesn't have the ability to automatically handle them because there can be lots of case-specific details involved with instantiation, sizing, etc.

Also, be sure to include the "private" scope keyword before your private variables in your classes.  Failure to do so will cause them to be treated as special "design public" variables, which means that they will be public and will also have information about them included in the RTTI, which you don't need/want.

This is the correct code:

unit Unit2;

interface

uses WebCore;

type
 TNested = class(TPersistent)
 private
   fValue: Integer;
   fDescription: string;
 published
   property Value: Integer read fValue write fValue;
   property Description: string read fDescription write fDescription;
 end;

 TTestIntArray = array of Integer;

 TComposite = class(TPersistent)
 private
   fField: string;
   fNested: TNested;
   fTestIntArray: TTestIntArray;
 protected
   procedure SaveProperties(AWriter: TWriter); override;
 public
   constructor Create; override;
   destructor Destroy; override;
   function ToJson: string;
 published
   property Field: string read fField write fField;
   property Nested: TNested read fNested write fNested;
   property TestIntArray: TTestIntArray read fTestIntArray write fTestIntArray;
 end;

function TestJson: string;

implementation

constructor TComposite.Create;
begin
inherited Create;
fNested := TNested.Create;
SetLength(fTestIntArray, 5);
end;

destructor TComposite.Destroy;
begin
fNested.Free;
inherited Destroy;
end;

procedure TComposite.SaveProperties(AWriter: TWriter);
var
Count: Integer;
HasElements: Boolean;
i: Integer;
begin
  inherited SaveProperties(AWriter);
  AWriter.PropertyName('TestIntArray');
  Count := Length(fTestIntArray);
  HasElements := (Count > 0);
  AWriter.BeginArray(HasElements);
  for i := 0 to Count-1 do
  begin
    AWriter.IntegerArrayElement(fTestIntArray[i]);  // Just use your Append hack for now
    if (i < Count-1) then
      AWriter.Separator;
  end;
  AWriter.EndArray(HasElements);
end;

function TComposite.ToJson: string;
var
Writer: TWriter;
begin
Writer := TWriter.Create;
try
  Writer.Initialize;
  Save(Writer);
  Result := Writer.Output;
finally
  Writer.Free;
end;
end;
  
function TestJson: string;
var
c: TComposite;
begin
c := TComposite.Create;
try
  c.Field := 'field';
  c.Nested.Value := 10;
  c.Nested.Description := 'description';
  Result := c.ToJson;
finally
  c.Free;
end;
end;

end.

Tim Young
Elevate Software
www.elevatesoft.com
Image