JSON reader not working if you have nested temp-tables using

Posted by jbijker on 02-Jul-2019 12:57

We have a funny situation where we have a dataset with multiple tables, some nested. We use the same SERIALIZE-NAME on the nested tables to keep the format across the tables the same, but this seems to cause problems when doing a READ-JSON. READ-XML seems to work 100%.

A simplified test case - we have parent1 and parent2, each with its nested child1 and child2, but we use a serialize-name of child on both of them:

DEFINE TEMP-TABLE parent1 NO-UNDO SERIALIZE-NAME "parent1"
  FIELD cID AS CHARACTER SERIALIZE-NAME "id"
  FIELD cName AS CHARACTER SERIALIZE-NAME "name".

DEFINE TEMP-TABLE parent2 NO-UNDO SERIALIZE-NAME "parent2"
  FIELD cID AS CHARACTER SERIALIZE-NAME "id"
  FIELD cName AS CHARACTER SERIALIZE-NAME "name".

DEFINE TEMP-TABLE child1 NO-UNDO SERIALIZE-NAME "child"
  FIELD cID AS CHARACTER SERIALIZE-HIDDEN
  FIELD cValue AS CHARACTER SERIALIZE-NAME "value".

DEFINE TEMP-TABLE child2 NO-UNDO SERIALIZE-NAME "child"
  FIELD cID AS CHARACTER SERIALIZE-HIDDEN
  FIELD cValue AS CHARACTER SERIALIZE-NAME "value".

DEFINE DATASET dsTest SERIALIZE-NAME "test"
  FOR parent1, child1, parent2, child2
  DATA-RELATION pc1 FOR parent1, child1 RELATION-FIELD(cID, cID) NESTED
  DATA-RELATION pc2 FOR parent2, child2 RELATION-FIELD(cID, cID) NESTED.

DEFINE VARIABLE lcData AS LONGCHAR NO-UNDO.

CREATE parent2.
ASSIGN
  parent2.cID = "2"
  parent2.cName = "parent2".

CREATE child2.
ASSIGN
  child2.cID = "2"
  child2.cValue = "test2".

DATASET dsTest:WRITE-JSON("longchar", lcData, TRUE).

MESSAGE STRING(lcData) VIEW-AS ALERT-BOX.

The JSON that comes back is

---------------------------
Message (Press HELP to view stack trace)
---------------------------
{"test": {
  "parent2": [
    {
      "id": "2",
      "name": "parent2",
      "child": [
        {
          "value": "test2"
        }
      ]
    }
  ]
}}
---------------------------
OK   Help   
---------------------------

Now when I try to read this exact JSON back into the dataset it's not behaving:

DEFINE TEMP-TABLE parent1 NO-UNDO SERIALIZE-NAME "parent1"
  FIELD cID AS CHARACTER SERIALIZE-NAME "id"
  FIELD cName AS CHARACTER SERIALIZE-NAME "name".

DEFINE TEMP-TABLE parent2 NO-UNDO SERIALIZE-NAME "parent2"
  FIELD cID AS CHARACTER SERIALIZE-NAME "id"
  FIELD cName AS CHARACTER SERIALIZE-NAME "name".

DEFINE TEMP-TABLE child1 NO-UNDO SERIALIZE-NAME "child"
  FIELD cID AS CHARACTER SERIALIZE-HIDDEN
  FIELD cValue AS CHARACTER SERIALIZE-NAME "value".

DEFINE TEMP-TABLE child2 NO-UNDO SERIALIZE-NAME "child"
  FIELD cID AS CHARACTER SERIALIZE-HIDDEN
  FIELD cValue AS CHARACTER SERIALIZE-NAME "value".

DEFINE DATASET dsTest SERIALIZE-NAME "test"
  FOR parent1, child1, parent2, child2
  DATA-RELATION pc1 FOR parent1, child1 RELATION-FIELD(cID, cID) NESTED
  DATA-RELATION pc2 FOR parent2, child2 RELATION-FIELD(cID, cID) NESTED.

DEFINE VARIABLE lcData AS LONGCHAR NO-UNDO.

lcData = '~{"test": ~{
  "parent2": [
    ~{
      "id": "2",
      "name": "parent2",
      "child": [
        ~{
          "value": "test2"
        ~}
      ]
    ~}
  ]
~}~}'.

DATASET dsTest:READ-JSON("longchar", lcData).

FOR EACH parent1:
    DISPLAY parent1. /* displays nothing, this is correct */
END.

FOR EACH child1:
    DISPLAY child1. /* displays test2 with no id, this is wrong */
END.

FOR EACH parent2:
    DISPLAY parent2. /* displays parent2, this is correct */
END.

FOR EACH child2:
    DISPLAY child2. /* displays nothing, this is wrong */
END.

This looks like a bug to me. Anyone has an idea to get past this? We're using OE 11.7.4.

All Replies

Posted by mircea.alexandru on 02-Jul-2019 13:52

Hi,

It's actually not a bug, but I do agree that it's funny :).

You have defined the temp-table field to be serialize-hidden (FIELD cID AS CHARACTER SERIALIZE-HIDDEN), but ABL needs a value on that field to "link" to the parent temp-table record. Since you are not supplying it, it will just use the field default value, which does not help.

If you do want to use something like that in your json structure, you may want to use PARENT-ID-RELATION instead of DATA-RELATION, which will use a RECID to the parent record as a "link".

Posted by marian.edu on 02-Jul-2019 18:22

Clearly a bug imho, all relations are defined as nested so the parser should be able to know that a 'child' node inside 'parent2' is actually a 'child2' record and also set it's parent id even if set as serialize hidden. It seems to be confused by the serialize-name which is the same for both child tables, if you change the serialize-name for child2 and update the name in the json it will yield the correct results.


Even more, if you change the serialize name to the second child table to be different from 'child' the result will still be wrong because it will create one correct record in parent 2 table and one erroneous record in child 1 table with no parent id set and this should not happen.

Having a 'child' property at dataset level also incorrectly creates records in the child table although those are bound to be inside of a parent node given the nested option set on the data relation.

lcData = '~{"test": ~{
  "parent2": [
    ~{
      "id": "2",
      "name": "parent2"
    ~}
  ],
  "child": [
        ~{
          "value": "test2"
        ~}
      ]
  
~}~}'.
 

Marian Edu

Acorn IT 
www.acorn-it.com
www.akera.io
+40 740 036 212

Posted by jbijker on 03-Jul-2019 08:37

Even when making use of PARENT-ID-RELATION it's still misbehaving:

DEFINE TEMP-TABLE parent1 NO-UNDO SERIALIZE-NAME "parent1"

 FIELD cName AS CHARACTER SERIALIZE-NAME "name".

DEFINE TEMP-TABLE parent2 NO-UNDO SERIALIZE-NAME "parent2"

 FIELD cName AS CHARACTER SERIALIZE-NAME "name".

DEFINE TEMP-TABLE child1 NO-UNDO SERIALIZE-NAME "child"

 FIELD rID AS RECID SERIALIZE-HIDDEN

 FIELD cValue AS CHARACTER SERIALIZE-NAME "value".

DEFINE TEMP-TABLE child2 NO-UNDO SERIALIZE-NAME "child"

 FIELD rID AS RECID SERIALIZE-HIDDEN

 FIELD cValue AS CHARACTER SERIALIZE-NAME "value".

DEFINE DATASET dsTest SERIALIZE-NAME "test"

 FOR parent1, child1, parent2, child2

 PARENT-ID-RELATION pc1 FOR parent1, child1 PARENT-ID-FIELD rID

 PARENT-ID-RELATION pc2 FOR parent2, child2 PARENT-ID-FIELD rID.

DEFINE VARIABLE lcData AS LONGCHAR NO-UNDO.

lcData = '~{"test": ~{

 "parent2": [

   ~{

     "id": "2",

     "name": "parent2",

     "child": [

       ~{

         "value": "test2"

       ~}

     ]

   ~}

 ]

~}~}'.

DATASET dsTest:READ-JSON("longchar", lcData).

FOR EACH parent1:

   DISPLAY parent1. /* displays nothing, this is correct */

END.

FOR EACH child1:

   DISPLAY child1. /* displays test2 with unknown id, this is wrong */

END.

FOR EACH parent2:

   DISPLAY parent2. /* displays parent2, this is correct */

END.

FOR EACH child2:

   DISPLAY child2. /* displays nothing, this is wrong */

END.

Posted by mircea.alexandru on 03-Jul-2019 09:15

Just noticed now that you are actually getting something on child1.

Darn...this is a bug.

I assume changing the serialize-name to 'child1' and 'child2' works even with the field rID set to serialize-hidden.

As a workaround, you could parse the json manually using Progress.Json.ObjectModel.* and create the needed records.

Posted by jbijker on 04-Jul-2019 07:55

I've logged this with Progress Suppport: Case - 00499274

This thread is closed