Wednesday, September 13, 2017

Using Serializable Objects in ABAP

For a project I was working on I had to build generic logging functionality in ABAP. There were two important requirements:
  • No noticeable effect on performance 
  • Re-usable in different scenarios.
With the first requirement in mind I decided to build an RFC enabled function module that I could approach via an asynchronous RFC call. That seemed a fine idea at the time, but not when you consider that no generic types are allowed in RFC modules and you can’t use object references in the interface parameters. These limitations seriously compromised my possibility to meet requirement number two as re-usability often goes hand in hand with the passing of generic data types.
I complained about these restrictions by one of my esteemed colleagues and he asked me, why don’t you use serialized objects to pass data to your function module. As I hardly knew what he was talking about I decided to dive deeper in to this subject, ultimately leading to a satisfactory solution and to this blog.

Serialization 


Before I continue I would like to explain how you can serialize (and de-serialize) objects in ABAP.
I will first hit you with the definition of serialization, which hopefully will make a bit of sense in combination with the requirements above.

“Serialization is the process of translating data structures or object states into a format that can be stored or transmitted and reconstructed later when the resulting series of bits is reread according to the serialization format, it can be used to create a semantically identical clone of the original object”.

That is interesting stuff and just what I needed, a way to transmit an object instance and once transmitted a way to reconstruct it again and by doing so overcoming the limitations of my RFC function module.


How does it work in ABAP 

Actually the possibility of object serialization has been available in ABAP for a long time but somehow it never crossed my path. Although there are already some blogs available on the subject I was missing an overview of all its possibilities (and limitations). So let’s start with the basics.

Object serialization can be accessed with the CALL TRANSFORMATION statement in roughly the same way as you do a transformation of an internal table. To be able to serialize an object using this statement, its class must implement the interface IF_SERIALIZABLE_OBJECT. The result of this transformation is an XML (but JSON is possible as well) string or xstring. In ABAP it will look something like this.
First we define a simple class which implements the interface IF_SERIALIZABLE_OBJECT and has one private attribute and a setter- and a getter-method.


We can serialize an instance of this class into an XML-(x)string in the following way:


The result (LV_SERIALIZED_OBJECT) is of type XSTRING and it describes the instance in an XML format. You can do everything with it what you also can do with any other variable. Like passing it as a parameter to a function module or for example store it in the database. ( If you plan to do the latter it might be a good idea to compress the data first before storing it, as more complex objects tend to take up a lot of storage.) If we check the LV_SERIALIZED_OBJECT in the debugger it looks like this:


If you want the serialized object in JSON format then some additional coding has to be done as shown here.


But let’s stick with the XML version for now. We have seen that serialization can be done, but it’s pretty useless if we cannot de-serialize it back to an object instance again. But have no fear this can be easily done by calling the transformation again in reversed order.


It should not come as a surprise that the our object instance is working again as it should. And our private attribute with value ‘Will_I_surivive_serialization’ was shown on screen. So that is pretty cool! But let’s dive a bit deeper into the subject.

A further look into serializable objects 

Object References 

In our simple example we have seen that our attribute ‘survives’ the serialization process. But what happens if our attribute is not a string variable but also an object instance. To test this I made a small adjustment to our class definition and defined ‘MYPRIVATEATTRIBUTE’ into TYPE REF TO Object.


In my test I set an instance of class CL_CRM_ORGMAN_SERVICE as my attribute value and execute the serialization and deserialization. When I check the value of ‘MYPRIVATEATTRIBUTE’ in the debugger after the deserialization step I see it has the value {O:INITIAL}.


So what’s happening here. This means that it didn’t survive serialization and the reason behind it is that class CL_CRM_ORGMAN_SERVICES self is not implementing the interface IF_SERIALIZABLE_OBJECT. So that is an important limitation you have to take into account when you decide to use serialization. If you have other reference variables inside your class make sure that they implement the interface IF_SERIALIZABLE_OBJECT as well because otherwise they will not be serialized.

Data References 

But what about data references? Are they serializable? Let’s find out and put it to the test. I changed the definition of ‘MYPRIVATEATTRIBUTE’ into TYPE REF TO DATA and ran a simple test. Unfortunately the ‘MYPRIVATEATTRIBUTE’ didn’t survive the serialization process and after de-serialization it has the value {O:INITIAL} again. How could this be as I was told, and had read online, that it was possible. After some further investigation I found out that you have to supply the specific option data_refs = ‘heap_or_create’ to your transformation so that it will support data references. If you are interested there are actually a lot of options you can use for your transformations and an overview can be found here. But for now it suffices to say that data reference can be serialized but you have to tell your transformation to take them into account. See the example below for a working example.


Clone vs. Clone? 

As stated above serialization can be used to create a semantically identical clone of the original object. But SAP also provides another method of object cloning you can use by calling the following statement SYSTEM-CALL OBJMGR CLONE <object> TO <cloned_object>. Let’s compare both and see what the difference is. To do so I made some changes to our class definition and it now implements the CLONE method from the interface IF_OS_CLONE.


In my next example program I pass an new instance of myself (as it implements the IF_SERIALIZABLE_OBJECT interface) to the MYOBJECT attribute and after that I go through the serialization process and subsequently also make a clone of object LO_SERIALIZABLE_OBJECT. See code below:


If we now compare all three objects we can see that cloning via the serialization is actually not delivering exactly the same result in relation to the cloning done via the system call. As can be seen in the diagram below.


The difference between the deserialized object and the cloned object is that the latter is also a new instance of the same class but the attribute MYOBJECT is still referring to the same instance as the original LO_SERIALIZABLE_OBJECT. The deserialized object generates a new instance for the attribute MYOBJECT which actually makes sense as it goes through the same serialization process. This same principle will also apply if you use data references.

Modified Serialization and Deserialization

All the instance attributes for an object part are serialized as standard regardless of their visibility. To change this behavior, you can declare and implement the instance methods SERIALIZE_HELPER and DESERIALIZE_HELPER in the relevant class for each object part. In SAP there is a demo program called DEMO_SERIALIZABLE_OBJECT where this principle is demonstrated. As this blog is already getting quite large I will not go into much detail here. But for those who are interested in the topic please check here

Conclusion

Serialization of object references and data references can be quite a useful tool in some specific cases. It has some limitations but I hope this blog made you aware of them. Serialization can for example be used for passing generic data to RFC function modules, but also for storing object states in the database. You will probably not use it every day but know that it is around and in some cases might help you out.

No comments:

Post a Comment