JSON to ABAP data structure program

On my current project, I had to write some ABAP code to convert a (deep) ABAP structure to JSON. I have seen at least two projects out there that do the same thing, but nothing that converts JSON to ABAP. So I set out to produce an ABAP program to do this.

[UPDATE – I just saw this: http://ruediger-plantiko.blogspot.com/2010/12/ein-json-parser-in-abap.html (post in German), it is also an effort to do JSON -> ABAP, but I have not been able to check it out in more detail].

What I present here is a working solution in the form of an ABAP subroutine (which could easily just be put into a class method) that takes a JSON string and any ABAP data structure as a changing parameter, then changes the ABAP data structure so that it is filled with the data from the JSON string.

The subroutine represents a very basic and trusting JSON parser, in that it believes the caller will not pass in any garbage. As such, there is no real JSON syntax checking, and passing rubbish will result in an incorrectly-filled data structure or, at worst, a short dump. In fact, it is very liberal in the sense that keys can be surrounded with double quotes or not, and so can string values, for that matter. Therefore, there is no strict application of JSON rules, though it should work with any JSON-compliant string.

The code represents a little machine that tries to track the state of a cursor as it moves through the given JSON with a number of switches. It is of course recursive, so that it caters for nested objects and arrays as values inside the JSON string, where arrays are treated as ABAP table entries.

The whole thing consists of 105 lines (excluding blanks and comments) which I think is not bad considering it’s ABAP, though I suspect there is probably room for improvement.

You can find the code for the subroutine here: https://gist.github.com/2282070

Here is a little sample ABAP to test the code, that should work on any Basis system: https://gist.github.com/2282244

Hint: If you run into any difficulty, run your JSON string through JSONLint to make sure it is correct!

 

You may also be interested in:

Tags: ,

  • rplantiko

    Hi,

    I appreciate your approach, using type sniffing of the result parameter for assigning the components. My approach (http://bsp.mits.ch/code/clas/zcl_json_parser) was to use a universal intermediate object (type ZUT_DATA) instead.

    This requires some postprocessing code to map the parsed data into the target structures. If certain tasks occur frequently, I would add public methods to the parser class performing this step. Till now, I didn’t find it necessary.

    Anyway, I made a branch of your gist adding some module tests (the failing tests to be interpreted as suggestions for further improvement).

    https://gist.github.com/2282935

    Kind regards,
    Rüdiger

  • Martin

    Hi Rüdiger,
    Thank you very much for taking the time to look at my code, and for writing the test class.
    The boolean issue is of course a very subjective issue, because what rule do you use to decide whether to treat a CHAR 1 as a boolean? You could look at the domain, if it is a dictionary field, to see whether it is FLAG or BOOLE, for instance, but you could potentially end up with problems if it is not supposed to be a boolean field. My feeling is that if a system talks to an ABAP system, it should rather translate the field when it knows it is supposed to be boolean, otherwise you lose some of the dynamicity of the ABAP.
    Secondly, it seems to me in your test class in TEST_DEEP, you are changing LT_DEEP but testing against LS_DEEP, which probably explains the failure.
    Thanks and Regards,
    Martin

  • Martin

    Me again. I have made a correction for the deep structure unit test in this gist: https://gist.github.com/2297987

  • Martin

    I should also add that my views on the treatment of Boolean values stem from the fact that I first did the ABAP to JSON portion, where translation is a problem because there is no hard rule for treatment of a CHAR 1 with ‘X’ or SPACE. Strictly speaking, ABAP does not have a Boolean elementary data type, and the use of a CHAR 1 with ‘X’ or SPACE is merely a workaround, so my conclusion is that when dealing with an ABAP system, one must interpret such fields on a case-by-case basis.

  • rplantiko

    Hi Martin (fka unknown :-) )

    thanks for your replies. Indeed, the assertion of my test_deep() method was erroneous itself. Changing to assert_equals( act = lt_deep act = lt_exp) makes the test work. So I understand your interface correctly.

    As for the Boolean part. As specified in http://www.json.org, a JSON value can be a string, number, object, array, or one of the literals true, false and null. So if an input value true or false (without enclosing double quotes) is scanned, it is clear that it must be a boolean.

    So the JSON source is clear about when it sends a boolean.

    What about the target.

    Indeed, ABAP doesn’t know the elementary data type boolean. Indeed, the data type FLAG and the ABAP constants ABAP_TRUE and ABAP_FALSE from type pool ABAP, are just workarounds for this.

    However, 99% of all ABAP programmers use a CHAR 1 with the values ‘ ‘ and ‘X’ as data type for a boolean. The 1% is a mix of other fashions, like NUMC 1 with ’0′ and ’1′.

    So, if you are type sniffing anyway, you could provide the target field with ‘ ‘ or ‘X’, if it is a length 1 character field.

    But I agree that you can argue about this, it is not a strict must for a JSON parser to do it like this.

    Kind regards,
    Rüdiger

  • rplantiko

    Addendum:

    Easiest way to detect whether a field lv_field is character length 1.

    describe field lv_field type lv_type length lv_length in character mode.
    if lv_type eq ‘C’ and lv_length eq 1.

    endif.