Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
Ryan-Crosby
Active Contributor


Background: You have a requirement to expose some type of BAPI for A2A integration and you don't want to use RFC but are aiming to keep it as simple as possible.

Disclaimer: In a lot of organizations the integration expert and the ABAP developers may be segregated, but it is not the case where I am so my apologies if I end up over-simplifying this as a result.  Also, the implementation for 'ZCL_ABAP_PROXY_MAPPER' is complete for my requirements but may not work fully should you choose to try it so pay close attention to the typekind logic for your situation.  ** Obsolete as of NW 7.5 ** - SAP has provided MOVE-CORRESPONDING xx TO yy EXPANDING NESTED TABLES.

How it first started: Below I've included a fake example (for simplicity reasons) that illustrates a common occurrence for passing data to the output after executing some BAPI, but it started because I got tired of always writing these static code sections for custom implementations.  I want to pass the data back and I end up writing a bunch of static code with LOOP, APPEND, etc. to fill the output.  Sometimes, I can use MOVE-CORRESPONDING as highlighted with the comment at line 42 but only if I don't have mismatches like lines 50-51 and that still doesn't help avoid a mountain of static code for deeply nested structures.



Direct Assignment is Not Possible: Foiled by the darn CONTROLLER (and even then I would have to declare ALL fields of the BAPI table structure to even try that)-



RTTS to the Rescue: A custom Z class that uses RTTS to handle both inward/outward conversion dynamically.

1. Public Section
class ZCL_ABAP_PROXY_MAPPER definition
public
final
create public .

*"* public components of class ZCL_ABAP_PROXY_MAPPER
*"* do not include other source files here!!!
public section.

class-data PROXY_TO_OTHER type ZCONV_MODE value 2. "#EC NOTEXT .
class-data OTHER_TO_PROXY type ZCONV_MODE value 1. "#EC NOTEXT .

class-methods MAP_STRUCTURE
importing
!DIRECTION type ZCONV_MODE
!INPUT type ANY
changing
!OUTPUT type ANY .
class-methods MAP_TABLE
importing
!DIRECTION type ZCONV_MODE
!INPUT type STANDARD TABLE
changing
!OUTPUT type STANDARD TABLE

2. Private Section
*"* private components of class ZCL_ABAP_PROXY_MAPPER
*"* do not include other source files here!!!
private section.

class-methods READ_COMPONENTS
importing
!INDEX type ZCONV_MODE
!INPUT type ANY
changing
!OUTPUT type ANY

3. MAP_TABLE Method
METHOD MAP_TABLE.

DATA: wa_to TYPE REF TO data.

FIELD-SYMBOLS: <wa_from> TYPE ANY,
<wa_to> TYPE ANY.

* add each entry of table to output
CREATE DATA wa_to LIKE LINE OF output.
ASSIGN wa_to->* TO <wa_to>.
LOOP AT input ASSIGNING <wa_from>.
CLEAR <wa_to>.
zcl_abap_proxy_mapper=>read_components( EXPORTING
index = direction
input = <wa_from>
CHANGING
output = <wa_to> ).
APPEND <wa_to> TO output.
ENDLOOP.

ENDMETHOD.

4. MAP_STRUCTURE Method
METHOD MAP_STRUCTURE.

* Read components of structure for mapping
zcl_abap_proxy_mapper=>read_components( EXPORTING
index = direction
input = input
CHANGING
output = output ).

ENDMETHOD.

5. READ_COMPONENTS Method
METHOD READ_COMPONENTS.

DATA: type_ref TYPE REF TO cl_abap_typedescr,
stru_ref_from TYPE REF TO cl_abap_structdescr,
lt_comp_from TYPE abap_compdescr_tab,
wa_comp_from TYPE abap_compdescr,
stru_ref_to TYPE REF TO cl_abap_structdescr,
lt_comp_to TYPE abap_compdescr_tab,
wa_comp_to TYPE abap_compdescr.

FIELD-SYMBOLS: <from> TYPE ANY,
<to> TYPE ANY.

* Get structure reference from RTTS
stru_ref_from ?= cl_abap_typedescr=>describe_by_data( input ).
lt_comp_from = stru_ref_from->components.
stru_ref_to ?= cl_abap_typedescr=>describe_by_data( output ).
lt_comp_to = stru_ref_to->components.
SORT lt_comp_to BY name.
type_ref ?= stru_ref_from.

* Always skip controller as first value
LOOP AT lt_comp_from INTO wa_comp_from FROM index.
* Only perform match if names with same type kind exist in both from and to
READ TABLE lt_comp_to INTO wa_comp_to WITH KEY name = wa_comp_from-name
BINARY SEARCH.
IF sy-subrc = 0 AND
* Types must match exactly or both be structures
( ( wa_comp_to-type_kind = wa_comp_from-type_kind ) OR
( wa_comp_to-type_kind = type_ref->typekind_struct1 AND
wa_comp_from-type_kind = type_ref->typekind_struct2 ) OR
( wa_comp_to-type_kind = type_ref->typekind_struct2 AND
wa_comp_from-type_kind = type_ref->typekind_struct1 ) ).
* Peform assignment and mapping
ASSIGN COMPONENT wa_comp_from-name OF STRUCTURE input TO <from>.
ASSIGN COMPONENT wa_comp_from-name OF STRUCTURE output TO <to>.
IF <from> IS ASSIGNED AND
<to> IS ASSIGNED.
IF wa_comp_from-type_kind = type_ref->typekind_table. "Table type
zcl_abap_proxy_mapper=>map_table( EXPORTING
direction = index
input = <from>
CHANGING
output = <to> ).
ELSEIF wa_comp_from-type_kind = type_ref->typekind_struct1 OR "Either flat or nested structures
wa_comp_from-type_kind = type_ref->typekind_struct2.
zcl_abap_proxy_mapper=>map_structure( EXPORTING
direction = index
input = <from>
CHANGING
output = <to> ).
ELSE. "Anything else - direct assignment
<to> = <from>.
ENDIF.
ENDIF.
ENDIF.
ENDLOOP.

ENDMETHOD.

The Result (with Earlier Sample): See the difference in the required ABAP effort.
1. Local Types
TYPES: BEGIN OF ty_request,
customer_number TYPE kunnr,
sales_organization TYPE vkorg,
material TYPE matnr,
document_date TYPE datum,
document_date_to TYPE datum,
transaction_group TYPE char01,
purchase_order_number TYPE bstkd,
END OF ty_request,

BEGIN OF ty_response,
return TYPE bapireturn,
sales_orders TYPE sra_bapiorders_t,
END OF ty_response.

2. Proxy Method

METHOD zii_sales_processing_in1~sales_order_dynamic_query.

DATA: ls_request TYPE ty_request,
ls_response TYPE ty_response.

* Initialize
CLEAR: ls_request, ls_response.

* Convert external request format to internal request format dynamically
zcl_abap_proxy_mapper=>map_structure(
EXPORTING
direction = zcl_abap_proxy_mapper=>proxy_to_other
input = input-sales_order_query_dynamic_requ
CHANGING
output = ls_request ).

* Conversion exit for customer
CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'
EXPORTING
input = ls_request-customer_number
IMPORTING
output = ls_request-customer_number.

* Execute BAPI search
CALL FUNCTION 'BAPI_SALESORDER_GETLIST'
EXPORTING
customer_number = ls_request-customer_number
sales_organization = ls_request-sales_organization
material = ls_request-material
document_date = ls_request-document_date
document_date_to = ls_request-document_date_to
transaction_group = ls_request-transaction_group
purchase_order_number = ls_request-purchase_order_number
IMPORTING
return = ls_response-return
TABLES
sales_orders = ls_response-sales_orders.

* Convert internal response format to external response format dynamically
zcl_abap_proxy_mapper=>map_structure(
EXPORTING
direction = zcl_abap_proxy_mapper=>other_to_proxy
input = ls_response
CHANGING
output = output-sales_order_query_dynamic_resp ).

ENDMETHOD

But Wait - What about Performance?: I tested this rigorously over the period of several days and across multiple projects for each time I had a chance to use it and I did not observe any noticeable performance differences, and in some cases even found that the dynamic examples ran faster than the static counterparts.  However, that said, I would not recommend such an approach for deeply nested structures with many levels and structures that are many, many columns wide because of the recursive algorithm.

Benefits:

1. Simplify and shorten ABAP coding effort.

2. If I start by plugging in types for all the BAPI parameters internally then new fields/structures can be made available for input or output by changing the corresponding request/response data type and merely executing a proxy regeneration.

3. If I want to expose friendlier business object names for non-SAP counterparts then I can use the mapping runtime in PI to handle such cases so I can still use dynamic RTTS internally.  I could also choose to abstract a more complicated piece of a BAPI interface such as the EXTENSIONIN table in 'BAPI_SALESORDER_SIMULATE' for example.

Hope some users might find this approach helpful in some way and I would always welcome feedback.

Regards,

Ryan Crosby

1 Comment
Labels in this area