Conversions in SAP Gateway Foundation – Part 1
Many of us remember the ABAP dynpro programming model as the methodology to create user interfaces on top of business applications in a lot of SAP products. Furthermore, SAP GUI is still a widely used technology.
ABAP dynpro is tightly integrated with the ABAP Dictionary: the definition of domains, data elements, structures, and database tables influences the appearance of, the behavior of, and the content representation in an ABAP dynpro user interface.
Take domains, for example. Domains may reference conversion exits. These exits define a transformation between the representation in the ABAP runtime environment and the representation on the UI.
Let us take a look at the so-called alpha conversion routine (not to be confused with alpha conversion in lambda calculus):
The five-character conversion exit identification ALPHA is added to a character-like domain,
VBELN in this case. As a result, for any purely numerical content of a corresponding field leading zeros are omitted during output on UI but added to numerical user input. Any non-numerical content stays as it is in both directions.
The left screenshot shows the representation of a sales document number (based on domain
VBELN) in the famous transaction VA03 while the right screenshot displays the same sales document in SE16, that is, the representation in database table
The transformation from the ABAP representation (with leading zeros in our example) to the representation on the UI is called outbound conversion while the other direction is called inbound conversion.
Please observe that these conversion exits have nothing to do with locale-dependent representations of dates, times, or amounts. Nevertheless, conversion exits may also take the logon language into account.
Technically, conversion exits are implemented as function modules that follow a certain naming convention:
CONVERSION_EXIT_<exitID>_OUTPUT. Their signature contains an importing parameter
INPUT and an exporting parameter
OUTPUT without type specification.
OData and SAP Gateway Foundation
Nowadays, SAP Fiori is the user experience paradigm. Its technological basis relies on SAPUI5 with OData as the protocol for data transfer between backend and UI client. SAP Gateway Foundation enables the usage of OData. In case of a typical ABAP backend SAP Gateway Foundation is the framework that allows you to develop, to expose, and to administer OData services.
When using SAP Gateway Foundation to create an OData service on top of an existing ABAP business application it can be assumed that conversion exits are taken into account as described above.
And yes, the framework provides features to automatically execute conversions such that the OData service exposes data in a way that is comparable to the former representation in SAP GUI.
But since OData defines a type system that is different from the type system in the ABAP runtime environment things get a little complicated. The conversion feature in SAP Gateway Foundation is very powerful and supports much more than just the conversion exits mentioned above.
In a small series of blog posts let us explore the secrets of conversions in SAP Gateway Foundation both for OData version 2.0 and OData version 4.0. We start with the above example of conversion exits in the context of OData version 2.0.
Starting Point – An Example
Let us stick to the sales document number. Suppose you want to create an OData service that provides sales document headers using a direct access to the database.
Your OData service will define an entity type,
SD_HEADER for example. And, there will be an entity set
SD_HEADER_SET. For the sake of simplicity we assume that the ABAP names are used in the OData metadata document.
The entity type
SD_HEADER will get a key property
VBELN to identify the sales document header through the sales document number.
If we would just expose the database content in the OData service a (JSON) response would look like this:
How do we achieve that the system automatically applies the ALPHA conversion as defined in the ABAP Dictionary such that the OData service returns the following result?
The answer is simple: we provide the dictionary information to SAP Gateway Foundation. The mechanism to do this is called binding.
Option 1 – Structure Binding
After having created the entity type (storing the object in
lo_entity_type) with its properties you implement the following call in the
DEFINE method of the model provider class:
lo_entity_type->bind_structure( iv_structure_name = 'VBAK' iv_bind_conversions = abap_true ).
Please observe the importing parameter
IV_BIND_CONVERSIONS. If it would not be set to
ABAP_TRUE then SAP Gateway Foundation would take over type information from the ABAP Dictionary but would not take the conversion information into account.
This code is also generated if you use transaction SEGW (SAP Gateway Service Builder) to build your service. In this design time tool you would just specify the name of the ABAP Dictionary structure when defining the entity type:
The generator will create the above method call with
IV_BIND_CONVERSIONS = ABAP_TRUE automatically.
Option 2 – Element Binding
Similarly, if you create your properties independent of a structure and you just want to use ABAP Dictionary information for a single property you can call method
BIND_DATA_ELEMENT at the respective property object (
lo_property, for example) providing the name of a data element. Again, do not forget to set
lo_property->bind_element( iv_element_name = 'DATA_ELEMENT_NAME' iv_bind_conversions = abap_true ).
IV_BIND_CONVERSIONS has been added to this method in SAP_GWFND 740 SP13 and higher. Hence, earlier releases do not support this function. You either need to use structure binding or the following feature.
Independent of any ABAP Dictionary reference you are able to specify a conversion exit at the property using method
SET_CONVERSION_EXIT. The method expects the 5-character identification of the conversion exit as it would have been entered in the domain.
lo_property->set_conversion_exit( 'ALPHA' ).
Be careful, the method does not check the existence of the conversion exit. It just adds the information to the property which implies that the method may also be used to override a conversion exit that has previously been determined using structure binding.
The last sentence may sound as if the method could also be used to remove a conversion exit. In principle, this is possible if an initial value is provided to the method.
A more appropriate way is the usage of method
/IWBEP/IF_MGW_ODATA_PROPERTY~DISABLE_CONVERSION at the property class. It does not remove the conversion information from the property object but switches off its usage.
lo_entity_type = model->get_entity_type( 'SD_HEADER' ). lo_entity_type->get_property( 'Vbeln' )->disable_conversion( ).
There is a corresponding method
ENABLE_CONVERSION. But this method cannot be used to derive conversion exit information from the ABAP Dictionary retroactively. It just resets the switch that has been set with
Another switch that allows to disable conversions is the method
/IWBEP/IF_MGW_ODATA_MODEL~SET_NO_CONVERSION at the model itself. It disables all conversions for the complete model – we will discuss in subsequent blog posts why this is not advisable at all. Consider that you cannot re-enable a conversion for a property using
ENABLE_CONVERSION if the conversion has been switched off for the complete model.
To summarize, the best way to work with the conversions is as follows: use structure binding with
IV_BIND_CONVERSIONS = ABAP_TRUE and disable conversions at the individual property if needed.
Now, if a (primitive) property of an OData service “knows” about an assigned conversion exit SAP Gateway Foundation may execute an inbound conversion for content of a request payload and filter expressions or key predicates in the request URI. Outbound conversions are processed for the response payload.
In the next blog post we are going to discuss a bit more theoretical and technical background about how SAP Gateway Foundation transfers and serializes data, and when and where conversions are executed.
Very informative and wellexplained!
Interesting blog, Thomas, thank you.
I think there is an interesting debate to be had about why it might be a good idea to do conversion in Gateway.
To take your example, if Gateway returns the sales order number without any conversion I can easily write a formatter so that my UI5 app displays it without the leading zeroes.
If instead we get Gateway to do the conversion then we must ensure that every time the app passes the sales order number back to the service the reverse conversion takes place.
Thanks for your comment. My answer would be twofold:
in addition to what Thomas said I would like to add that it is the goal of OData services provided by SAP Gateway to hide the SAP specifics on how we handle data ABAP internally from the UI5 developer so that live of UI developers gets easier.
For the same reason OData services provided by SAP Gateway can exernally use property names like "MaterialNumber" which are much easier to understand than "MATNR" or "SalesOrder" that you can use instead of "VBELN" (which stems from German "Verkaufsbeleg") while the ABAP developer that implements the service can happily use MATNR and VBELN. 😉
Good examples with SD tables VBAK and VBELN!
thanks a lot for share this information . very usefull
thanks a lot for these very useful information in Part 1 and 2 of your series. I am pretty sure, that my question does not really hit your main work area, nevertheless maybe you have an opinion about it 🙂 ?
I am wondering about the question "How can I steer the behaviour of the conversions, when I implement the Auto-Exposure scenario with @OData.publish: true, where I do not have a SEGW project or model provider class?"
Maybe I am wrong, but as far as I know, there is not really a CDS annotation, which I could use to steer this. Would you suggest to avoid the Auto-Exposure way and implement RDS (or the manual mapping)?
Thanks in advance and best regards,
Thanks for this question. Very good point. Difficult to answer in a short comment. Personally, I would prefer auto exposure. RDS or MDS might make sense if the additional flexibility outweighs the additional effort/complication.
The auto exposure uses generic data and model provider classes. Hence, no possibility to influence conversions as described above. The auto exposure uses the default conversion derivation mechanism of SAP Gateway. This derivation is executed in the options 1 and 2 as described in the dictionary binding section of the blog post.
Therefore, the only chance to influence the conversion behavior is to change the input. That is, the typing in the ABAP CDS View. You may use the cast( ) operator to manipulate the typing. For example, if the data source types field A with data element X that would lead to a certain conversion and you do not want to have it then try to cast to a data element Y with similar properties that does not lead to a conversion in the default derivation: cast(a as y)
thanks a lot for your quick reply - I think I got your point.
Just a sidenote considering auto exposure: Our experience showed that this kind of flexibility is really necessary in more or loss all of our scenarios. I think this at least applies generally for customer projects, where you have to implement something dependent on the needs of the users or the business team. At some point in time they always show up with some fancy ideas, is you know what I mean ;-).
Once again, thank you and best regards,
Thank you for the great post. I am having some trouble with conversion routines that cause short dumps. I explain it all in this question, and I was hoping you could take a look at it and give me your thoughts on it.
During processing of an OData request, I can see in the implementation of a GET_ENTITYSET method that /IWBEP/IF_MGW_REQ_ENTITYSET=>GET_OSQL_WHERE_CLAUSE_CONVERT takes conversion exits into account, by converting external (output) to internal (input) values in the resulting values.
However, in a GET_ENTITY method, /IWBEP/IF_MGW_REQ_ENTITY=>GET_CONVERTED_KEYS does not apply conversion exits. (You would think, because it has CONVERTED in the name, as opposed to GET_KEYS, that the system would apply conversion exits).
Am I doing something wrong? Or is it the system that is not behaving consistently?
Martin Ceronio - indeed, /IWBEP/IF_MGW_REQ_ENTITY=>GET_CONVERTED_KEYS is supposed to execute the (inbound) conversions. If it does not, a detailed analysis is required.
Thanks for the confirmation Thomas. It sounds like we should perhaps open an SAP incident for that.
Thomas Nitschke OK, never mind, I was being a doofus.
I didn't realize that /IWBEP/IF_MGW_REQ_ENTITY=>GET_CONVERTED_KEYS exports a data structure, not a table like GET_KEYS, so simply passing the entity structure does in fact obtain a converted value in the correct field.