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.
Conversion Exits
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 VBAK
.
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>_INPUT
and 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?
Dictionary Binding
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 IV_BIND_CONVERSIONS
.
lo_property->bind_element(
iv_element_name = 'DATA_ELEMENT_NAME'
iv_bind_conversions = abap_true ).
The parameter 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.
Explicit Specifications
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.
Tricky Switches
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 DISABLE_CONVERSION
.
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.
Conversion Execution
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.
Hello Mike,
Thanks for your comment. My answer would be twofold:
Thomas
Hi Mike,
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. 😉
Andre
Good examples with SD tables VBAK and VBELN!
thanks a lot for share this information . very usefull
Hi Thomas,
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,
Sebastian
Hi Sebastian,
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)
Thomas
Hi Thomas,
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,
Sebastian
Hi Thomas,
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.
https://answers.sap.com/questions/13329761/gateway-conversions-cause-dumps.html
Kind regards,
Mark.
Hello Thomas,
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?
Kind Regards,
Martin
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.
Many thanks.