Some ABAP values have curious in-memory (and in-database) representations which are meant to be hidden from the user. The standard SAP user interface does this automatically, but the behavior of these values in external interfaces varies.

For example, address numbers, ie. the keys of address entries, use conversion exit ALPHA. This means that address number 1 would be represented as 0000000001 in-memory and in-database.

Address number domain

RFC Function Modules / Web Services

RFC function modules, and therefore also web services, do not convert values automatically. This makes sense, since an RFC call coming from another ABAP system expects all values to already be in the correct in-memory form, ie. the RFC call looks pretty much like normal function module call.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
FUNCTION zweb_service.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     VALUE(IM_NAME1) TYPE  AD_NAME1
*"  EXPORTING
*"     VALUE(EX_ADDRESS_NUMBER) TYPE  AD_ADDRNUM
*"     VALUE(EX_NAME1) TYPE  AD_NAME1
*"----------------------------------------------------------------------

  SELECT SINGLE addrnumber
    FROM adrc
    INTO @ex_address_number
   WHERE name1 = @im_name1.

  IF sy-subrc = 0.
    ex_name1 = im_name1.
  ENDIF.

ENDFUNCTION.

Address number includes prefixing zeroes

While understandable, this behavior is a poor fit in a world where integration to ABAP systems are increasingly implemented using different flavors of HTTP, rather than the proprietary ABAP RFC protocol. It forces actual RFC functions and RFC functions used for defining web services to be implemented separately: the web service functions need to manually convert values for output in order to not expose the in-memory representation to the caller. This means that the only guard against exposing ABAP’s internal weirdness is the programmer.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
FUNCTION zweb_service.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     VALUE(IM_NAME1) TYPE  AD_NAME1
*"  EXPORTING
*"     VALUE(EX_ADDRESS_NUMBER) TYPE  AD_ADDRNUM
*"     VALUE(EX_NAME1) TYPE  AD_NAME1
*"----------------------------------------------------------------------

  SELECT SINGLE addrnumber
    FROM adrc
    INTO @ex_address_number
   WHERE name1 = @im_name1.

  IF sy-subrc = 0.
    ex_name1 = im_name1.

    CALL FUNCTION 'CONVERSION_EXIT_ALPHA_OUTPUT'
      EXPORTING
        input  = ex_address_number
      IMPORTING
        output = ex_address_number.
  ENDIF.

ENDFUNCTION.

Address number is returned without the prefixing zeroes

OData

The more modern OData protocol improves the situation considerably: when an OData entity is defined by referring to data elements, the OData framework performs input and output conversions automatically.

OData entity structure

OData entity in SEGW transaction

Any values returned by the OData framework are automatically converted for output, which means that address numbers will not contain the extra prefixing zeroes:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
METHOD addresses_get_entityset.

  DATA(lt_select_option) = io_tech_request_context->get_filter( )->get_filter_select_options( ).

  DATA lr_address_number TYPE RANGE OF ad_addrnum.
  io_tech_request_context->get_filter( )->convert_select_option(
    EXPORTING
      is_select_option = VALUE #( lt_select_option[ property = 'ADDRESS_NUMBER' ] OPTIONAL )
    IMPORTING
      et_select_option = lr_address_number
  ).

  DATA lr_name1 TYPE RANGE OF ad_name1.
  io_tech_request_context->get_filter( )->convert_select_option(
    EXPORTING
      is_select_option = VALUE #( lt_select_option[ property = 'NAME1' ] OPTIONAL )
    IMPORTING
      et_select_option = lr_name1
  ).


  SELECT addrnumber AS address_number,
         name1
    FROM adrc
    INTO CORRESPONDING FIELDS OF TABLE @et_entityset
   WHERE addrnumber IN @lr_address_number
     AND name1      IN @lr_name1.

ENDMETHOD.

OData converts address numbers automatically

Conversions are likewise automatically handled in entity keys (since a direct SELECT could not work if ls_key-address_number was not in the same format as the values in the database):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
METHOD addresses_get_entity.

  DATA ls_keys TYPE zcl_zodata_service_mpc_ext=>ts_address.
  io_tech_request_context->get_converted_keys( IMPORTING es_key_values = ls_keys ).

  SELECT SINGLE addrnumber AS address_number,
         name1
    FROM adrc
    INTO CORRESPONDING FIELDS OF @er_entity
   WHERE addrnumber = @ls_keys-address_number.

ENDMETHOD.

Entity keys are converted automatically

OData Functions

However, for some reason conversions are not automatically defined for OData function parameters:

OData function parameter

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
METHOD /iwbep/if_mgw_appl_srv_runtime~execute_action.

  CASE iv_action_name.

    WHEN 'GetName1'.
      DATA ls_parameters TYPE zcl_zodata_service_mpc_ext=>ts_getname1.
      io_tech_request_context->get_converted_parameters( IMPORTING es_parameter_values = ls_parameters ).

      DATA ls_entity TYPE zcl_zodata_service_mpc_ext=>ts_address.
      SELECT SINGLE addrnumber AS address_number,
                    name1
        FROM adrc
        INTO CORRESPONDING FIELDS OF @ls_entity
       WHERE addrnumber = @ls_parameters-addressnumber.

      copy_data_to_ref(
        EXPORTING
          is_data = ls_entity
        CHANGING
          cr_data = er_data
      ).

  ENDCASE.

ENDMETHOD.

No data returned

You have to manually add the conversion exit to the parameter definition by redefining the define method in the model provider extension (*_MPC_EXT) class:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
METHOD define.

  super->define( ).


  DATA(lo_function) = model->get_action( iv_action_name = 'GetName1' ).

  DATA(lo_parameter) = lo_function->get_input_parameter( iv_name = 'AddressNumber' ).

  lo_parameter->set_conversion_exit( iv_conv_exit = 'ALPHA' ).

ENDMETHOD.

After this addition the function parameters will also be converted, and our function will actually return data:

Data returned as expected