Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
Andre_Fischer
Product and Topic Expert
Product and Topic Expert
75,169

Introduction


In a recent partner workshop I was asked how one can add annotations to an OData service when your system runs on top of SAP NetWeaver 740.

While with SAP NetWeaver 750 and higher you can add annotations within the CDS DDL source code there is no such support available for SAP NetWeaver 740.

Nevertheless customers and partners can leverage CDS views as a datasource for OData services already in SAP NetWeaver 740 if they are using service implementation using CDS views as mapped datasources.

So you can start building CDS views for your OData services in 740. To add support for annotaions in 740 backends you can used code based implementation.

I found however that there is not much information available around this topic ... so I decided to write this blog.

The use case as mentioned above for this scenario are customers and partners that want to build  OData services based on SAP NetWeaver 740 where no support for annotations in CDS views is available.

When upgrading to SAP NetWeaver 750 or higher you can move your implementation into CDS as well.

The following screen shot shows the first screen of the resulting SAP Fiori application which is based on the List Report Page and Object Page from Fiori elements (aka Smart Templates).

This app uses the OData service that I have described in my blog

https://blogs.sap.com/2016/05/31/odata-service-development-with-sap-gateway-code-based-service-devel...

 

 

From the entity set SalesOrderSet we show the columns Salesorder, Customer and Gross amount together with the Currency by default. The header of this list is named SalesOrders.



 

When clicking on on list entry we are using the navigation property ToItems and the details of the selected sales order is displayed on the object page.



Here some information from the sales order header such as Salesorder number, Customer number, lifecycle status and the last change date is shown in the header of the object page (red).

The gross amount is highlighted as a data point (green) whereas the title of the object page is titled as SalesOrder (blue).

 

Coding explained


In order to create these annoations we are going to implement the DEFINE method of the model provider extenstion class (MPC_EXT) of our OData service implementation. In the Service Builder we expand the folder Runtime Artifacts, select the class with the extension MPC_EXT class and select Go to ABAP Workbench from the context menue.



 

This opens the ABAP Development Tools in Eclipse



where we can start to redefine the DEFINE method.

After calling the DEFINE method of the superclass the code starts with some definitions.

 
 
DATA: lo_ann_target TYPE REF TO /iwbep/if_mgw_vocan_ann_target. " Vocabulary Annotation Target
DATA: lo_ann_target2 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_collection TYPE REF TO /iwbep/if_mgw_vocan_collection. " Vocabulary Annotation Collection
DATA: lo_function TYPE REF TO /iwbep/if_mgw_vocan_function. " Vocabulary Annotation Function
DATA: lo_fun_param TYPE REF TO /iwbep/if_mgw_vocan_fun_param. " Vocabulary Annotation Function Parameter
DATA: lo_property TYPE REF TO /iwbep/if_mgw_vocan_property. " Vocabulary Annotation Property
DATA: lo_record TYPE REF TO /iwbep/if_mgw_vocan_record. " Vocabulary Annotation Record
DATA: lo_simp_value TYPE REF TO /iwbep/if_mgw_vocan_simple_val. " Vocabulary Annotation Simple Value
DATA: lo_url TYPE REF TO /iwbep/if_mgw_vocan_url. " Vocabulary Annotation URL
DATA: lo_label_elem TYPE REF TO /iwbep/if_mgw_vocan_label_elem. " Vocabulary Annotation Labeled Element
DATA: lo_reference TYPE REF TO /iwbep/if_mgw_vocan_reference. " Vocabulary Annotation Reference

 

Next we add references. Please note the alias 'UI' which is later reused in the code.

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

 

We first specify the target entity type for our annations which is in this case the entity type "Salesorder". Important here is to set the correct namespace of our OData service.

Next we add the header information which is shown on the first page ('SalesOrders') to describe the entries of the list
and the details on the object page ('SalesOrder').

Then we are creating a collection of entries that specify the columns of the entity set that are shown in the list by default. These are the UI.LineItem annotations.
    "annotations for entity type Sales Order
lo_ann_target = vocab_anno_model->create_annotations_target( 'SalesOrder' ).
lo_ann_target->set_namespace_qualifier( 'ZE2E100_XX_3_SRV' ). "change the namespace to the SRV namespace

" Header Info
lo_annotation = lo_ann_target->create_annotation( iv_term = 'UI.HeaderInfo' ).
lo_record = lo_annotation->create_record( ).
lo_record->create_property( 'TypeName' )->create_simple_value( )->set_string('SalesOrder').
lo_record->create_property( 'TypeNamePlural' )->create_simple_value( )->set_string( 'SalesOrders').

" Columns to be displayed by default
lo_annotation = lo_ann_target->create_annotation( iv_term = 'UI.LineItem' ).
lo_collection = lo_annotation->create_collection( ).

lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField' ).
lo_property = lo_record->create_property( 'Label' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_string( 'Salesorder' ).
lo_property = lo_record->create_property( 'Value' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_path( 'Salesorder' ).

lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField' ).
lo_property = lo_record->create_property( 'Label' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_string( 'Customer' ).
lo_property = lo_record->create_property( 'Value' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_path( 'Customer' ).

lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField' ).
lo_property = lo_record->create_property( 'Label' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_string( 'Gross amount' ).
lo_property = lo_record->create_property( 'Value' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_path( 'Grossamountintransaccurrency' ).

lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField' ).
lo_property = lo_record->create_property( 'Label' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_string( 'Currency' ).
lo_property = lo_record->create_property( 'Value' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_path( 'Transactioncurrency' ).

 

The columns that are displayed in the header of the object page are annotated using the 'UI.Identification' annotation.

 
    " Columns to be displayed in the object page
lo_annotation = lo_ann_target->create_annotation(
EXPORTING
iv_term = 'UI.Identification' ).
lo_collection = lo_annotation->create_collection( ).

lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField' ).
lo_property = lo_record->create_property( 'Label' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_string( 'Salesorder' ).
lo_property = lo_record->create_property( 'Value' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_path( 'Salesorder' ).

lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField' ).
lo_property = lo_record->create_property( 'Label' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_string( 'Customer' ).
lo_property = lo_record->create_property( 'Value' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_path( 'Customer' ).

lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField' ).
lo_property = lo_record->create_property( 'Label' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_string( 'Lifecycle status' ).
lo_property = lo_record->create_property( 'Value' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_path( 'Salesorderlifecyclestatus' ).

lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField' ).
lo_property = lo_record->create_property( 'Label' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_string( 'Last changed at' ).
lo_property = lo_record->create_property( 'Value' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_path( 'Lastchangeddatetime' ).

 

The gross amount that shall be shown as a data point is annotated next.

 
    " Gross amount to be displayed as a data point
lo_annotation = lo_ann_target->create_annotation(
EXPORTING
iv_term = 'UI.DataPoint'
iv_qualifier = 'Grossamountintransaccurrency' ).
lo_record = lo_annotation->create_record( iv_record_type = 'UI.DataField' ).
lo_record->create_property( 'Value' )->create_simple_value( )->set_path('Grossamountintransaccurrency').
lo_record->create_property( 'Title' )->create_simple_value( )->set_string( 'Gross amount' ).

 

Then we specify the facets for the header and the details of the object page using the annoation path '@UI.Identification' .

To let the gross amount show up in the header as a data point we have to set the annotation pathe '@UI.DataPoint#Grossamountintransaccurrency'.

 
    "Header Facets
lo_collection = lo_ann_target->create_annotation( iv_term = 'UI.HeaderFacets' )->create_collection( ).

"Facet for Sales Order Header Details on object page
lo_record = lo_collection->create_record( iv_record_type = 'UI.ReferenceFacet' ).
lo_record->create_property( 'ID' )->create_simple_value( )->set_string( 'GeneralInformation' ).
lo_record->create_property( 'Label' )->create_simple_value( )->set_string( 'General Information' ).
lo_record->create_property( 'Target')->create_simple_value( )->set_annotation_path( '@UI.Identification' ).

"Facet for Gross amount
lo_record = lo_collection->create_record( iv_record_type = 'UI.ReferenceFacet' ).
lo_record->create_property( 'ID' )->create_simple_value( )->set_string( 'GrossAmount' ).
lo_record->create_property( 'Label' )->create_simple_value( )->set_string( 'Gross amount' ).
lo_record->create_property( 'Target')->create_simple_value( )->set_annotation_path( '@UI.DataPoint#Grossamountintransaccurrency' ).

"Facet for Sales Order Header Details on object page
lo_collection = lo_ann_target->create_annotation( iv_term = 'UI.Facets' )->create_collection( ).

lo_record = lo_collection->create_record( iv_record_type = 'UI.ReferenceFacet' ).
lo_record->create_property( 'ID' )->create_simple_value( )->set_string( 'ItemList' ).
lo_record->create_property( 'Label' )->create_simple_value( )->set_string( 'Item List' ).
lo_record->create_property( 'Target')->create_simple_value( )->set_annotation_path( 'ToItems/@UI.LineItem' ).

 

We can finally add the annoations that specify the columns of the sales order item list which is shown on the object page.
These are again 'UI.LineItem' annotations. But this time the target of our annotations is a new object that points to the 'SalesOrderItem' entity type.

 
    "add annotations for sales order line items
lo_ann_target2 = vocab_anno_model->create_annotations_target( 'SalesOrderItem' ).
lo_ann_target2->set_namespace_qualifier( 'ZE2E100_XX_3_SRV' ). "change the namespace to the SRV namespace

" Columns to be displayed by default
lo_annotation = lo_ann_target2->create_annotation( iv_term = 'UI.LineItem' ).
lo_collection = lo_annotation->create_collection( ).

lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField' ).
lo_property = lo_record->create_property( 'Label' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_string( 'Salesorder' ).
lo_property = lo_record->create_property( 'Value' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_path( 'Salesorder' ).

lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField' ).
lo_property = lo_record->create_property( 'Label' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_string( 'Item' ).
lo_property = lo_record->create_property( 'Value' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_path( 'Salesorderitem' ).

lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField' ).
lo_property = lo_record->create_property( 'Label' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_string( 'Gross amount' ).
lo_property = lo_record->create_property( 'Value' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_path( 'Grossamountintransaccurrency' ).

lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField' ).
lo_property = lo_record->create_property( 'Label' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_string( 'Currency' ).
lo_property = lo_record->create_property( 'Value' ).
lo_simp_value = lo_property->create_simple_value( ).
lo_simp_value->set_path( 'Transactioncurrency' ).

 

The  resulting  annotations can be found in the $metadata files:

 
 <Annotations Target="ZE2E100_XX_3_SRV.SalesOrder" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<Annotation Term="UI.HeaderInfo">
<Record>
<PropertyValue Property="TypeName" String="SalesOrder" />
<PropertyValue Property="TypeNamePlural" String="SalesOrders" />
</Record>
</Annotation>
<Annotation Term="UI.LineItem">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Label" String="Salesorder" />
<PropertyValue Property="Value" Path="Salesorder" />
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Label" String="Customer" />
<PropertyValue Property="Value" Path="Customer" />
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Label" String="Gross amount" />
<PropertyValue Property="Value" Path="Grossamountintransaccurrency" />
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Label" String="Currency" />
<PropertyValue Property="Value" Path="Transactioncurrency" />
</Record>
</Collection>
</Annotation>
<Annotation Term="UI.Identification">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Label" String="Salesorder" />
<PropertyValue Property="Value" Path="Salesorder" />
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Label" String="Customer" />
<PropertyValue Property="Value" Path="Customer" />
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Label" String="Lifecycle status" />
<PropertyValue Property="Value" Path="Salesorderlifecyclestatus" />
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Label" String="Last changed at" />
<PropertyValue Property="Value" Path="Lastchangeddatetime" />
</Record>
</Collection>
</Annotation>
<Annotation Term="UI.DataPoint" Qualifier="Grossamountintransaccurrency">
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="Grossamountintransaccurrency" />
<PropertyValue Property="Title" String="Gross amount" />
</Record>
</Annotation>
<Annotation Term="UI.HeaderFacets">
<Collection>
<Record Type="UI.ReferenceFacet">
<PropertyValue Property="ID" String="GeneralInformation" />
<PropertyValue Property="Label" String="General Information" />
<PropertyValue Property="Target" AnnotationPath="@UI.Identification" />
</Record>
<Record Type="UI.ReferenceFacet">
<PropertyValue Property="ID" String="GrossAmount" />
<PropertyValue Property="Label" String="Gross amount" />
<PropertyValue Property="Target" AnnotationPath="@UI.DataPoint#Grossamountintransaccurrency" />
</Record>
</Collection>
</Annotation>
<Annotation Term="UI.Facets">
<Collection>
<Record Type="UI.ReferenceFacet">
<PropertyValue Property="ID" String="ItemList" />
<PropertyValue Property="Label" String="Item List" />
<PropertyValue Property="Target" AnnotationPath="ToItems/@UI.LineItem" />
</Record>
</Collection>
</Annotation>
</Annotations>
<Annotations Target="ZE2E100_XX_3_SRV.SalesOrderItem" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<Annotation Term="UI.LineItem">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Label" String="Salesorder" />
<PropertyValue Property="Value" Path="Salesorder" />
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Label" String="Item" />
<PropertyValue Property="Value" Path="Salesorderitem" />
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Label" String="Gross amount" />
<PropertyValue Property="Value" Path="Grossamountintransaccurrency" />
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Label" String="Currency" />
<PropertyValue Property="Value" Path="Transactioncurrency" />
</Record>
</Collection>
</Annotation>
</Annotations>
29 Comments