Skip to Content

Updates

24.07.2018 – new coding with vocabulary based annotations based on text elements

26.07.2018 – added description how to work with CDS based OData services

26.07.2018 – added code that retrieves texts from data elements

14.10.2018 – added an additional solution (works solely for sap:label)

Introduction

A customer asked me today how to change the the properties sap:label, sap:heading and sap:quickinfo in an OData service that has been developed using ABAP code based implementation.

Instead of the data which is retrieved by the SAP Gateway framework by default from the underlying data element they wanted to use custom annotations and retrieve the same from other data elements.

Then I got the question how to change these annotations for CDS based OData Services.

In this blog I will actually not show how to change the sap annotations but how to publish vocabulary based annotations instead on the Common Vocabulary.

<Annotations xmlns="http://docs.oasis-open.org/odata/ns/edm" Target="ZGW_PRODUCT_SRV.Product/Category">

<Annotation String="Label for category" Term="Common.Label"/>

<Annotation String="Heading for category" Term="Common.Heading"/>

<Annotation String="Quickinfo for category" Term="Common.QuickInfo"/>

</Annotations>

These annotations can be interpreted in SAPUI5 as well and if SAP Fiori Elements applications are used these vocabulary based annotions will be used instead of the default values that are set via sap:label, sap:heading and sap:quickinfo.

OData services based on ABAP Code based implementation

Suppose the original OData service would have an entity set ProductSet whose entity type Product is bound to the DDIC structure BAPI_EPM_PRODUCT_HEADER.

The three sandard  sap annotations mentioned above would look like as follows for the property Category.

<Property Name="Category" 
...
sap:quickinfo="EPM: Product Category" 
sap:label="Category" 
sap:heading="Product Category"
...
/>

This is because the property Category is based on the data element SNWD_PRODUCT_CATEGORY.

Solution 1: Use of text elements

A flexible approach is to use text elements as the source for our vocabulary based annotations based on the Common Vocabulary.

The target of the following Annotation is the property Category of the entity type Product.

The above mentioned  annotations are generated if we add the following coding to our DEFINE method of the MPC_EXT class.

  METHOD define.
    DATA: lo_ann_target  TYPE REF TO /iwbep/if_mgw_vocan_ann_target.   " Vocabulary Annotation Target
    DATA: lo_annotation  TYPE REF TO /iwbep/if_mgw_vocan_annotation.   " Vocabulary Annotation
    DATA: lo_simp_value  TYPE REF TO /iwbep/if_mgw_vocan_simple_val.   " Vocabulary Annotation Simple Value
    DATA: lo_reference   TYPE REF TO /iwbep/if_mgw_vocan_reference.    " Vocabulary Annotation

    super->define( ).

    lo_reference = vocab_anno_model->create_vocabulary_reference( iv_vocab_id = '/IWBEP/VOC_COMMON' iv_vocab_version = '0001').
    lo_reference->create_include( iv_namespace = 'com.sap.vocabularies.Common.v1' iv_alias = 'Common' ).

    "annotations for entity type "Product" and property "Category"

    lo_ann_target = vocab_anno_model->create_annotations_target( 'Product/Category' ).
    lo_ann_target->set_namespace_qualifier( 'ZGW_PRODUCT_SRV' ).    "change the namespace to the SRV namespace

    "map text 001 to label
    lo_annotation = lo_ann_target->create_annotation( iv_term = 'Common.Label' ).
    lo_simp_value = lo_annotation->create_simple_value( ).
    lo_simp_value->set_string_from_text_element(
              iv_text_element_symbol = '001'
              io_text_element_container_ref = me ).

    "map text 002 to heading
    lo_annotation = lo_ann_target->create_annotation( iv_term = 'Common.Heading' ).
    lo_simp_value = lo_annotation->create_simple_value( ).
    lo_simp_value->set_string_from_text_element(
               iv_text_element_symbol = '002'
               io_text_element_container_ref = me ).

    "map text 003 to quickinfo
    lo_annotation = lo_ann_target->create_annotation( iv_term = 'Common.QuickInfo' ).
    lo_simp_value = lo_annotation->create_simple_value( ).
    lo_simp_value->set_string_from_text_element(
           iv_text_element_symbol = '003'
           io_text_element_container_ref = me ).

  ENDMETHOD.

Please note that we are using the method set_string_from_text_element.

Caution:

If you use the  method set_string the annotations will not offer support for multiple languages.

Text elements for a class can be maintained by using transaction SE24. In the edit mode choose the push button Text elements or press F5.

We create three text elements and translate the same to German. You have to make sure to activate your changes first.

After having translated the texts in German (or any other language) we can test the metadata document of our Service.

It turns out that when logging on in German the SAP Gateway client Shows the following response.

<Annotations xmlns="http://docs.oasis-open.org/odata/ns/edm" Target="ZGW_PRODUCT_SRV.Product/Category">

<Annotation String="Label für Kategorie" Term="Common.Label"/>

<Annotation String="Heading für Kategorie" Term="Common.Heading"/>

<Annotation String="Quickinfo für Kategorie" Term="Common.QuickInfo"/>

</Annotations>

 

Solution 2: Use of data elements

The texts that can be assigned to vocabulary based annotations can also be retrieved from existing data elements.

These might have the Advantage that the field descriptions are already maintained and translated.

In our DEFINE method of the MPC_EXT class we map four field descriptions to the vocabulary based annotations Common.Label, Common.Heading, Commona.QuickInfo and Common.Text.

  METHOD define.
    DATA: lo_ann_target  TYPE REF TO /iwbep/if_mgw_vocan_ann_target.   " Vocabulary Annotation Target
    DATA: lo_annotation  TYPE REF TO /iwbep/if_mgw_vocan_annotation.   " Vocabulary Annotation
    DATA: lo_simp_value  TYPE REF TO /iwbep/if_mgw_vocan_simple_val.   " Vocabulary Annotation Simple Value
    DATA: lo_reference   TYPE REF TO /iwbep/if_mgw_vocan_reference.    " Vocabulary Annotation

    super->define( ).

    lo_reference = vocab_anno_model->create_vocabulary_reference( iv_vocab_id = '/IWBEP/VOC_COMMON' iv_vocab_version = '0001').
    lo_reference->create_include( iv_namespace = 'com.sap.vocabularies.Common.v1' iv_alias = 'Common' ).

    "annotations for entity type "Product" and property "Category"

    lo_ann_target = vocab_anno_model->create_annotations_target( 'Product/Category' ).
    lo_ann_target->set_namespace_qualifier( 'ZGW_PRODUCT_SRV' ).    "change the namespace to the SRV namespace

    "map medium description to label
    lo_annotation = lo_ann_target->create_annotation( iv_term = 'Common.Label' ).
    lo_simp_value = lo_annotation->create_simple_value( ).
    lo_simp_value->set_string_from_data_element(
      EXPORTING
        iv_text_type = /iwbep/if_mgw_med_odata_types=>gcs_vocan_text_types-data_element_medium " Vocabulary Annotation text type
        iv_text_id   =   'S_SEATSMAX'                                                               " Vocabulary Annotation text ID
    ).

    "map heading to heading
    lo_annotation = lo_ann_target->create_annotation( iv_term = 'Common.Heading' ).
    lo_simp_value = lo_annotation->create_simple_value( ).
    lo_simp_value->set_string_from_data_element(
        EXPORTING
          iv_text_type = /iwbep/if_mgw_med_odata_types=>gcs_vocan_text_types-data_element_heading " Vocabulary Annotation text type
          iv_text_id   =   'S_SEATSMAX'                                                               " Vocabulary Annotation text ID
      ).

    "map quickinfo to quickinfo
    lo_annotation = lo_ann_target->create_annotation( iv_term = 'Common.QuickInfo' ).
    lo_simp_value = lo_annotation->create_simple_value( ).
    lo_simp_value->set_string_from_data_element(
        EXPORTING
          iv_text_type = /iwbep/if_mgw_med_odata_types=>gcs_vocan_text_types-data_element_quickinfo" Vocabulary Annotation text type
          iv_text_id   =   'S_SEATSMAX'                                                               " Vocabulary Annotation text ID
      ).

    "map long description to Text
    lo_annotation = lo_ann_target->create_annotation( iv_term = 'Common.Text' ).
    lo_simp_value = lo_annotation->create_simple_value( ).
    lo_simp_value->set_string_from_data_element(
        EXPORTING
          iv_text_type = /iwbep/if_mgw_med_odata_types=>gcs_vocan_text_types-data_element_long " Vocabulary Annotation text type
          iv_text_id   =   'S_SEATSMAX'                                                               " Vocabulary Annotation text ID
      ).

*    CATCH /iwbep/cx_mgw_med_exception.

  ENDMETHOD.

The result in the $metadata document looks like:

<Annotations xmlns="http://docs.oasis-open.org/odata/ns/edm" Target="ZGW_PRODUCT_SRV.Product/Category">

<Annotation String="Max. capacity econ." Term="Common.Label"/>

<Annotation String="Capacity in economy class" Term="Common.Heading"/>

<Annotation String="Maximum capacity in economy class" Term="Common.QuickInfo"/>

<Annotation String="Maximum capacity economy class" Term="Common.Text"/>

</Annotations>

Solution 3 (works only for sap:label)

If just sap:label should be updated this can also be achieved by using the following code snippet:

  METHOD define.
    super->define( ).

    DATA: 
      lo_entity_type TYPE REF TO /iwbep/if_mgw_odata_entity_typ,
      lo_property    TYPE REF TO /iwbep/if_mgw_odata_property.

    super->define( ).
    lo_entity_type = model->get_entity_type( iv_entity_name = 'Product').
    lo_property = lo_entity_type->get_property( iv_property_name = 'Category').
    lo_property->set_label_from_text_element(
      EXPORTING
                iv_text_element_symbol = '002'
               io_text_element_container_ref = me
    ).
*    CATCH /iwbep/cx_mgw_med_exception.

  ENDMETHOD.

This works however only for sap:label since there are no specific methods to update sap:heading and sap:quickinfo.

Text elements can be created the same way as shown in

 

Show the result (of Solution 1) in a SAP Fiori Elements App

If we generate a list reporting app to consume our service we will see that column for the product category now uses the value Label for category stored in our text element rather than using the value Category which is stored in sap:label.

<EntityType sap:content-version="1" Name="Product">
<Key>
<PropertyRef Name="ProductId"/>
</Key>
<Property Name="ProductId" sap:label="Product ID" MaxLength="10" Nullable="false" Type="Edm.String"/>
...
<Property Name="Category"  sap:label="Category" MaxLength="40" Nullable="false" Type="Edm.String"/>
<Property Name="Price"     sap:label="Price" Type="Edm.Decimal" Scale="4" Precision="23"/>
...
</EntityType>

The heading of the other columns (here: Price and Product ID) are using the text provided by the annotation sap:label instead.

 

Show the result in a SAP Fiori Master Detail App

As an example how to consume vocabulary based annotations in a SAPUI5 app I have generated a SAP Fiori application based on the Master Detail template.

When you add the following code in your Detail.view.xml of your Master Detail App.

<ObjectHeader
	id="objectHeader"
	title="{Name}"
	number="{
		path: 'Price',
		formatter: '.formatter.currencyValue'
		}"
	numberUnit="{CurrencyCode}">
	
        <attributes>	
	    	<ObjectAttribute text="{Category}" />
	    	<ObjectAttribute text="{Category/##com.sap.vocabularies.Common.v1.Label/String}" />
	    	<ObjectAttribute text="{Category/##com.sap.vocabularies.Common.v1.Heading/String}" />
		<ObjectAttribute text="{Category/##com.sap.vocabularies.Common.v1.QuickInfo/String}" />
	</attributes>
	<!-- 	<ObjectAttribute text="{Category/#@sap:label}" /> -->			
</ObjectHeader>

The resulting Screen looks like follows:

This means that you are able to change the default values for sap:label, sap:heading and sap:quickinfo if needed.

 

OData services based on CDS views

If an OData Service is based on CDS views the recommended way to pubish it as an OData Service is to use the Service Builder and the Reference Data Source Approach if there is the need to add functionality which is not supported by CDS views yet. (See Online Help – Exposing CDS Entities as OData Service).

Also for CDS view based OData services the annotations sap:label, sap:heading and sap:quickinfo are taken from the data elements of the underlying data base tables.  Reason is that only this way it is ensured that classic UI’s based used via SAPGUI show the same descriptions.

Since you cannot change the texts of data elements delivered by SAP you have to use the annoations @EndUserText as describe in the SAP Online Help Adding Field Labels and Descriptions

@EndUserText.label: '<text>'
@EndUserText.quickInfo: '<text>'

This way it is however only possible to set Customer specific values for sap:label and sap:quickinfo. 

Suppose we have an CDS view that uses the following annotations.

define view Z_C_Product
  as select from snwd_pd as Product
{
      //Product
  key client,
  key product_id,
      category,

…
      
      @EndUserText: {
        label: 'MyLabel' ,
        quickInfo: 'MyQuickInfo'
      }
      Product.product_id as ProductId
}

If you have maintained the DDL source Code using English as your logon language the annoations for the property ProductId would look like follows:

<Property sap:label="MyLabel" Name="ProductId" 
sap:quickinfo="MyQuickInfo" sap:display-format="UpperCase" 
MaxLength="10" Type="Edm.String"/>

But if you would log on in a different language such as German you would only get an empty string for the annotation sap:label.

<Property Name="ProductId" sap:label="" 
sap:display-format="UpperCase" 
MaxLength="10" Type="Edm.String"/>

In order to achieve multi language support you have to use transaction SE63.

 

  1. Start transaction SE63
  2. From the menu choose Translation –> ABAP Objects –> Short Texts or choose Ctrl+F2

  3. In the Object Type Selection (Object Groups) dialogue expand the entry A5 User Interface Texts and choose the entry DDLS CDS Views.
  4. Enter the name of your CDS view in the field Object Name.
  5. Choose the language in which you have maintained your CDS DDL source as the Source Language.
  6. Choose your desired Target Language.
  7. Press Edit and translate your Texts.

 

Now the property would show the following metadata when logging on in German

<Property Name="ProductId" sap:quickinfo="MeinQuicInfoGerman" 
sap:label="MeinLabel (German)" sap:display-format="UpperCase" 
MaxLength="10" Type="Edm.String"/>
To report this post you need to login first.

4 Comments

You must be Logged on to comment or reply to a post.

  1. Andre Adam

    Hello,

    Thanks for the blog and imformation shared in it.

    One question: will this also work with an CDS based OData Service?

    Best Regards

    André

    (0) 
  2. Geoffrey Mendoza

    Hello Ander,

     

    Thanks for this information.

     

    I also have a question: Is it possible to modify sap:label not by text elements but just by assigning any string into it?

     

    Thanks,

    Geoffrey

    (0) 
    1. Andre Fischer
      Post author

      Hi Geoffrey,

      no, but you can do so when using vocabulary based annotations though I wouldn’t recommend this as I wrote above.

      Using text elements or referring to DDIC elements allows you to leverage existing translations or to use the Translation capabilities of SAP AS ABAP.

      Best Regards,

      Andre

       

      (0) 

Leave a Reply