Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
vwegert
Active Participant

Welcome to another ABAP Trapdoors article - the first one posted using my new SCN user. If you are intersted in the older articles, you can find a link list at the bottom of this post.

I've been using asXML for some years now as a convenient way to serialize and deserialize arbitrary ABAP data structures. Some time ago, I learned about IF_SERIALIZABLE_OBJECT and its use to include class instances (aka objects) in an asXML representation as well. A few days ago, I decided to use this technique in a current development project. At the same time, I was trying to use CL_DEMO_OUTPUT_STREAM instead of classic lists as suggested by the online documentation, and since I was supposedly familiar with the basics of using transformations, I focused rather on the usage of this new output technology. I hacked together a small demo programm like this one:


REPORT z_test_serialize.
CLASS lcl_serializable_thingy DEFINITION CREATE PUBLIC.
  PUBLIC SECTION.
    INTERFACES if_serializable_object.
    METHODS constructor
      IMPORTING
        i_foo TYPE string.
    METHODS get_foo
      RETURNING
        VALUE(r_foo) TYPE string.
  PRIVATE SECTION.
    DATA g_foo TYPE string.
ENDCLASS.
CLASS lcl_serializable_thingy IMPLEMENTATION.
  METHOD constructor.
    g_foo = i_foo.
  ENDMETHOD.
  METHOD get_foo.
    r_foo = g_foo.
  ENDMETHOD.
ENDCLASS.
CLASS lcl_main DEFINITION CREATE PRIVATE.
  PUBLIC SECTION.
    CLASS-METHODS run.
ENDCLASS.
CLASS lcl_main IMPLEMENTATION.
  METHOD run.
    DATA: lr_stream        TYPE REF TO cl_demo_output_stream,
          l_foo_in        TYPE string,
          lr_first_thingy  TYPE REF TO lcl_serializable_thingy,
          l_xml_data      TYPE string,
          lr_second_thingy TYPE REF TO lcl_serializable_thingy,
          l_foo_out        TYPE string.
    lr_stream = cl_demo_output_stream=>open( ).
    SET HANDLER cl_demo_output_html=>handle_output FOR lr_stream.
    lr_stream->write_text( iv_text = 'XML Serialization of ABAP Objects Instances'
                            iv_format = if_demo_output_formats=>heading
                            iv_level  = 1 ).
    l_foo_in = |Hello, this is Foo Bar calling from { sy-sysid } client { sy-mandt }.|.
    lr_stream->write_data( iv_name  = 'Input Data'
                          ia_value  = l_foo_in
                          iv_format = if_demo_output_formats=>nonprop ).
    CREATE OBJECT lr_first_thingy
      EXPORTING
        i_foo = l_foo_in.
    CALL TRANSFORMATION id
      SOURCE instance = lr_first_thingy
      RESULT xml      = l_xml_data.
    lr_stream->write_data( iv_name  = 'XML Serialization'
                          ia_value  = l_xml_data
                          iv_format = if_demo_output_formats=>nonprop ).
    CALL TRANSFORMATION id
      SOURCE xml      = l_xml_data
      RESULT instance = lr_second_thingy.
    l_foo_out = lr_second_thingy->get_foo( ).
    lr_stream->write_data( iv_name  = 'Output Data'
                          ia_value  = l_foo_out
                          iv_format = if_demo_output_formats=>nonprop ).
    lr_stream->close( ).
  ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
  lcl_main=>run( ).

Instead of the expected output (some text, an XML representation of the instance and the same text again), I got - a shortdump. The reference lr_second_thingy was not set after the second transformation - so the deserialization must somehow be broken, right? The debugger quickly revealed that the string variable that was supposed to contain the serialized instance was empty - so it's the serialization that must be broken, then, and not the deserialization? Well, they both are, in a way. To cut straight to the point, here is the faulty code:


    CALL TRANSFORMATION id
      SOURCE instance = lr_first_thingy
      RESULT xml      = l_xml_data.
    lr_stream->write_data( iv_name  = 'XML Serialization'
                          ia_value  = l_xml_data
                          iv_format = if_demo_output_formats=>nonprop ).
    CALL TRANSFORMATION id
      SOURCE xml      = l_xml_data
      RESULT instance = lr_second_thingy.

And here is the corrected version:


    CALL TRANSFORMATION id
      SOURCE instance = lr_first_thingy
      RESULT XML        l_xml_data.
    lr_stream->write_data( iv_name  = 'XML Serialization'
                          ia_value  = l_xml_data
                          iv_format = if_demo_output_formats=>nonprop ).
    CALL TRANSFORMATION id
      SOURCE XML        l_xml_data
      RESULT instance = lr_second_thingy.

Yup, the difference is a single character - or two characters in this case. Without the equals sign, XML is treated as a keyword to denote a variable containing the raw XML data. With the equals sign, something else happens that I have yet to find a sensible and practical use for - at least when used with the identity transformation. You can spot this issue if you use the pretty printer to convert the keywords to upper case - and if you notice the tiny difference between xml and XML.

Older ABAP Trapdoors articles