Recent

Author Topic: json2pas code generation tool  (Read 2356 times)

mr-highball

  • Full Member
  • ***
  • Posts: 233
    • Highball Github
json2pas code generation tool
« on: December 19, 2018, 10:00:39 pm »
Hello friends,

I'm in the process of writing a code generation tool which takes json objects and converts them to pascal units. Hopefully this will aid in building out the models for consuming various web services/apis or for rapid prototyping. Some key features:
  • infer object inheritance from properties
  • clean interface
  • flexible library

I'm mainly reaching out right now to see the interest in a tool like this from other developers on the forum, because I'm nearing the point of building a frontend (console or ui is undecided right now) and could use some feedback on what features would be of use to others in the frontend and in the library, rather than just building something only usable by myself.

As of now, when provided three json objects the output from json2pas would be:
JSON
{"test_property":["hello world"], "test_strings":[""]}
{"test_object_property":{"test_property":["hello world"], "test_strings":[""]}}
{"test_array_of_objects_property":[{"test_object_property":{"test_property":["hello world"], "test_strings":[""]}}]}
UNIT
the library is still unfinished so there are missing methods, and a few improper signatures right now, but hopefully demonstrates the inheritance and basic structure of the generated code.
Code: Pascal  [Select][+][-]
  1. unit testunit;
  2.  
  3. {$mode delphi}
  4.  
  5. interface
  6. uses
  7.   fgl;
  8. type
  9.  
  10.   TTestPropertyList = TFPGList<String>;
  11.   TTestStringsList = TFPGList<String>;
  12.   //forward
  13.   ITestCompoundObj = interface;
  14.   TTestCompoundObjs = TFPGInterfacedObjectList<ITestCompoundObj>;
  15.  
  16.   ITestObj = interface
  17.     [{C961603D-2E3C-4EE6-B2A7-35C308842A2A}]
  18.     //property methods
  19.     function GetTestProperty:TTestPropertyList;
  20.     function GetTestStrings:TTestStringsList;
  21.     //properties
  22.     property TestProperty : TTestPropertyList read GetTestProperty write SetTestProperty;
  23.     property TestStrings : TTestStringsList read GetTestStrings write SetTestStrings;
  24.     //methods
  25.     function ToJSON:String;
  26.     function FromJSON:String;
  27.   end;
  28.  
  29.   ITestCompoundObj = interface
  30.     [{601C0A11-3708-4B27-9265-AC2DC3664543}]
  31.     //property methods
  32.     function GetTestObj:ITestObj;
  33.     procedure SetTestObj(Const ATestObj:ITestObj);
  34.     //properties
  35.     property TestObj : ITestObj read GetTestObj write SetTestObj;
  36.     //methods
  37.     function ToJSON:String;
  38.     function FromJSON:String;
  39.   end;
  40.  
  41.   ITestArrayObject = interface
  42.     [{39DABB47-5F26-4351-A6AB-E95E7EB417FB}]
  43.     //property methods
  44.     function GetTestArrayOfObjectsProperty:TTestCompoundObjs;
  45.     //properties
  46.     property TestArrayOfObjectsProperty : TTestCompoundObjs read GetTestArrayOfObjectsProperty;
  47.     //methods
  48.     function ToJSON:String;
  49.     function FromJSON:String;
  50.   end;
  51.  
  52.   TTestObjImpl = class(TInterfacedObject,ITestObj)
  53.   public
  54.     const
  55.       PROP_TEST_PROPERTY = 'test_property';
  56.       PROP_TEST_STRINGS = 'test_strings';
  57.   strict private
  58.     FTestProperty: TTestPropertyList;
  59.     FTestStrings: TTestStringsList;
  60.     function GetTestProperty:TTestPropertyList;
  61.     function GetTestStrings:TTestStringsList;
  62.   strict protected
  63.     function DoToJSON:String;virtual;
  64.     function FromJSON:String;virtual;
  65.   public
  66.     property TestProperty : TTestPropertyList read GetTestProperty write SetTestProperty;
  67.     property TestStrings : TTestStringsList read GetTestStrings write SetTestStrings;
  68.     function ToJSON:String;
  69.     function FromJSON:String;
  70.     constructor Create;virtual;
  71.     destructor Destroy;override;
  72.   end;
  73.  
  74.   TTestCompoundObjImpl = class(TInterfacedObject,ITestCompoundObj)
  75.   public
  76.     const
  77.       PROP_TEST_OBJ = 'test_object_property';
  78.   strict private
  79.     FTestObj: ITestObj;
  80.     function GetTestObj:ITestObj;
  81.     procedure SetTestObj(Const ATestObj:ITestObj);
  82.   strict protected
  83.     function DoToJSON:String;virtual;
  84.     function FromJSON:String;virtual;
  85.   public
  86.     property TestObj : ITestObj read GetTestObj write SetTestObj;
  87.     function ToJSON:String;
  88.     function FromJSON:String;
  89.     constructor Create;virtual;
  90.     destructor Destroy;override;
  91.   end;
  92.  
  93.   TTestArrayObjectImpl = class(TInterfacedObject,ITestArrayObject)
  94.   public
  95.     const
  96.       PROP_TEST_COMPOUND_OBJ = 'test_array_of_objects_property';
  97.   strict private
  98.     FTestArrayOfObjectsProperty: TTestCompoundObjs;
  99.     function GetTestArrayOfObjectsProperty:TTestCompoundObjs;
  100.   strict protected
  101.     function DoToJSON:String;virtual;
  102.     function FromJSON:String;virtual;
  103.   public
  104.     property TestArrayOfObjectsProperty : TTestCompoundObjs read GetTestArrayOfObjectsProperty;
  105.     function ToJSON:String;
  106.     function FromJSON:String;
  107.     constructor Create;virtual;
  108.     destructor Destroy;override;
  109.   end;
  110.  
  111. implementation
  112. uses
  113.   fpjson,jsonparser;
  114.  
  115.  
  116. function TTestObjImpl.DoFromJSON(Const AJSON:String;Out Error:String):Boolean;virtual;
  117. var
  118.   LData : TJSONData;
  119.   LObj : TJSONObject;
  120.   LArray : TJSONArray;
  121.   I : Integer;
  122. begin
  123.   //init result
  124.   Result:=False;
  125.   try
  126.     //attempt to parse JSON object
  127.     LData:=GetJSON(AJSON);
  128.     if not Assigned(LData) or (LData.JsonType <> jtObject) then
  129.       raise Exception.Create('DoFromJSON::invalid JSON object in ' + Self.Classname);
  130.    
  131.     //cast TJSONData -> TJSONObject
  132.     LObj:=TJSONObject(LData);
  133.    
  134.     //assign our array to local variable
  135.     LArray:=LObj.Arrays[PROP_TEST_PROPERTY];
  136.    
  137.     //iterate and add basic type to collection
  138.     for I:=0 to Pred(LArray.Count) do
  139.       FTestProperty.Add(LArray.Items[I].Value);
  140.    
  141.     //assign our array to local variable
  142.     LArray:=LObj.Arrays[PROP_TEST_STRINGS];
  143.    
  144.     //iterate and add basic type to collection
  145.     for I:=0 to Pred(LArray.Count) do
  146.       FTestStrings.Add(LArray.Items[I].Value);  
  147.     //success
  148.     Result:=True;
  149.   except on E:Exception do
  150.     Error:=E.Message;
  151.   end;
  152. end;
  153.  
  154. function TTestObjImpl.DoToJSON(Out JSON,Error:String):Boolean;virtual;
  155. var
  156.   LObj : TJSONObject;
  157.   LArray : TJSONArray;
  158.   I : Integer;
  159. begin
  160.   //init result
  161.   Result:=False;
  162.   try
  163.     LObj:=TJSONObject.Create;
  164.     try
  165.      
  166.       //assign new array to local var
  167.       LArray:=TJSONArray.Create
  168.       for I:=0 to Pred(FTestProperty.Count) do
  169.       begin
  170.         //add basic type for private var to local array
  171.         LArray.Add(FTestProperty[I]);
  172.       end;
  173.      
  174.       //add the array to result object (will free)
  175.       LObj.Add(PROP_TEST_PROPERTY,LArray)
  176.      
  177.       //assign new array to local var
  178.       LArray:=TJSONArray.Create
  179.       for I:=0 to Pred(FTestStrings.Count) do
  180.       begin
  181.         //add basic type for private var to local array
  182.         LArray.Add(FTestStrings[I]);
  183.       end;
  184.      
  185.       //add the array to result object (will free)
  186.       LObj.Add(PROP_TEST_STRINGS,LArray)
  187.      
  188.       //set output
  189.       JSON:=LObj.ToJSON;
  190.     finally
  191.       LObj.Free
  192.     end;  
  193.     //success
  194.     Result:=True;
  195.   except on E:Exception do
  196.     Error:=E.Message;
  197.   end;
  198. end;
  199.  
  200.  
  201.  
  202.  
  203.  
  204.  
  205. function TTestCompoundObjImpl.DoFromJSON(Const AJSON:String;Out Error:String):Boolean;virtual;
  206. var
  207.   LData : TJSONData;
  208.   LObj : TJSONObject;
  209. begin
  210.   //init result
  211.   Result:=False;
  212.   try
  213.     //attempt to parse JSON object
  214.     LData:=GetJSON(AJSON);
  215.     if not Assigned(LData) or (LData.JsonType <> jtObject) then
  216.       raise Exception.Create('DoFromJSON::invalid JSON object in ' + Self.Classname);
  217.    
  218.     //cast TJSONData -> TJSONObject
  219.     LObj:=TJSONObject(LData);
  220.     FTestObj.FromJSON(LObj.Get(PROP_TEST_OBJ,'{}'));  
  221.     //success
  222.     Result:=True;
  223.   except on E:Exception do
  224.     Error:=E.Message;
  225.   end;
  226. end;
  227.  
  228. function TTestCompoundObjImpl.DoToJSON(Out JSON,Error:String):Boolean;virtual;
  229. var
  230.   LObj : TJSONObject;
  231. begin
  232.   //init result
  233.   Result:=False;
  234.   try
  235.     LObj:=TJSONObject.Create;
  236.     try
  237.       LObj.Add(PROP_TEST_OBJ,GetJSON(FTestObj.ToJSON));
  238.      
  239.       //set output
  240.       JSON:=LObj.ToJSON;
  241.     finally
  242.       LObj.Free
  243.     end;  
  244.     //success
  245.     Result:=True;
  246.   except on E:Exception do
  247.     Error:=E.Message;
  248.   end;
  249. end;
  250.  
  251.  
  252.  
  253.  
  254.  
  255.  
  256. function TTestArrayObjectImpl.DoFromJSON(Const AJSON:String;Out Error:String):Boolean;virtual;
  257. var
  258.   LData : TJSONData;
  259.   LObj : TJSONObject;
  260.   LTestCompoundObj : ITestCompoundObj
  261. begin
  262.   //init result
  263.   Result:=False;
  264.   try
  265.     //attempt to parse JSON object
  266.     LData:=GetJSON(AJSON);
  267.     if not Assigned(LData) or (LData.JsonType <> jtObject) then
  268.       raise Exception.Create('DoFromJSON::invalid JSON object in ' + Self.Classname);
  269.    
  270.     //cast TJSONData -> TJSONObject
  271.     LObj:=TJSONObject(LData);
  272.    
  273.     //assign our array to local variable
  274.     LArray:=LObj.Arrays[PROP_TEST_COMPOUND_OBJ];
  275.    
  276.     //iterate and add object type to collection
  277.     for I:=0 to Pred(LArray.Count) do
  278.     begin
  279.       //first get a local reference
  280.       LTestCompoundObj:=TTestCompoundObjImpl.Create;
  281.    
  282.       //attempt to deserialize with json at index
  283.       if not FTestArrayOfObjectsProperty.FromJSON(LArray.Items[I].Value,Error)) then
  284.         Exit;
  285.    
  286.       //add to collection
  287.       FTestArrayOfObjectsProperty.Add(LTestCompoundObj);
  288.    
  289.       //nil local reference before iterating again
  290.       LTestCompoundObj:=nil;
  291.     end;  
  292.     //success
  293.     Result:=True;
  294.   except on E:Exception do
  295.     Error:=E.Message;
  296.   end;
  297. end;
  298.  
  299. function TTestArrayObjectImpl.DoToJSON(Out JSON,Error:String):Boolean;virtual;
  300. var
  301.   LObj : TJSONObject;
  302.   LArray : TJSONArray;
  303.   I : Integer;
  304. begin
  305.   //init result
  306.   Result:=False;
  307.   try
  308.     LObj:=TJSONObject.Create;
  309.     try
  310.      
  311.       //assign new array to local var
  312.       LArray:=TJSONArray.Create
  313.       for I:=0 to Pred(FTestArrayOfObjectsProperty.Count) do
  314.       begin
  315.         //add object type for private var to local array
  316.         LArray.Add(GetJSON(FTestArrayOfObjectsProperty[I].ToJSON));
  317.       end;
  318.      
  319.       //add the array to result object (will free)
  320.       LObj.Add(PROP_TEST_COMPOUND_OBJ,LArray)
  321.      
  322.       //set output
  323.       JSON:=LObj.ToJSON;
  324.     finally
  325.       LObj.Free
  326.     end;  
  327.     //success
  328.     Result:=True;
  329.   except on E:Exception do
  330.     Error:=E.Message;
  331.   end;
  332. end;
  333. end.
  334.  

the repo is here for anyone interested in looking over the code, but again, still a work in progress so there will be "dirty" code and full implementation code cannot be generated yet.
https://github.com/mr-highball/json2pas

thanks for the feedback,

avra

  • Hero Member
  • *****
  • Posts: 2547
    • Additional info
Re: json2pas code generation tool
« Reply #1 on: December 20, 2018, 01:19:18 pm »
I'm mainly reaching out right now to see the interest in a tool like this from other developers on the forum
:) Very interested in general, but will be able to comment when specific need comes since there is no time to dig in sooner.  %)
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

 

TinyPortal © 2005-2018