본문 바로가기

ABAP 프로그래밍 개념/ABAP Dynamic Programming(동적 프로그래밍)

4. ABAP 동적 프로그래밍 : Runtime Type Services(런타임 유형 서비스)

ABAP Runtime Type services(RTTS)는 객체지향 프레임워크(Object-oriented Framework)로서 다음 두 가지 구성요소로 이루어져 있습니다.

1) Runtime Type Information(RTTI)
-> RTTI를 사용해서, 프로그램 실행 동안 data objects 또는 런 타임시의 클래스의 인스턴스의 유형 정보를 결정합니다.

2) Runtime Type Creation(RTTC)
-> RTTC은 프로그램 실행동안 새로운 데이터 유형을 정의하는 것을 허락해줍니다.

RTTS 프레임워크는 아래 그림과 같이 클래스의 위계 질서를 결정하는데, 런타임 시 Data Object의 유형 정보를 결정하고 새 데이터 유형을 정의할 수 있습니다.

이러한 유형 클래스(Type Classes)들의 인스턴스는 Type Objects라고 불리웁니다.

Type Class(유형클래스)은 Elementary Types, Reference Types, Complex Types과 같은 각각의 ABAP 유형(ABAP type) 을 위해 존재합니다. 각각의 Type Objects는 유형을 설명하는 속성을 포함하고 있습니다. 클래스 문서(Class Documentation)은 각 Type Class에 대한 정보를 제공합니다.


Runtime Type Information


종종, 동적으로 객체의 유형 정보(Type Information)를 결정해야하는 필요성이 있을 때가 있습니다. 예를 들어, Procedure의 일반적으로 유형화된 파라미터 혹은 숫자 계산에서 일반적으로 이름이 정해진 데이터 오브젝트를 사용하기 전에, 그 파라미터와 데이터 유형의 유형, 길이, 소숫점 자리수를 확인하고 싶을 수 있습니다. 이러한 경우, Data Object의 유형 정보를 확인할 수 있는 Type Object를 사용할 수 있습니다.

Type Object는 Type Class의 메소드들을 사용해서 만들어집니다. Type Object의 속성은 Type Information을 담고 있습니다. 아래 소스 코드의 예시는 Type Information을 확인하는 예시입니다.

TYPES: ty_type TYPE p DECIMALS 2.
DATA: v_data TYPE ty_type,
r_typedescr TYPE REF TO cl_abap_typedescr.

START-OF-SELECTION.

r_typedescr = cl_abap_typedescr=>describe_by_data( v_data ).

WRITE: / 'Kind:', r_typedescr->type_kind.
WRITE: / 'Length:', r_typedescr->length.
WRITE: / 'Decimals:', r_typedescr->decimals.

위 소스 코드를 보면, R_TYPEDESCR 이라는 Type Object를 Type Class인 CL_ABAP_TYPEDESCR의 인스턴스로 정의하였습니다. Type Object는 Type Class의 Static Method인 DESCRIBE_BY_DATA를 호출 했을 때 인스턴스화 됩니다. 이 Static Method를 위해서, Type Information이 필요한 Data Object를 전달합니다. 즉, 정보를 알고 싶은 Object를 Method로 전달하여 유형 정보를 전달 받습니다.

Type Information과 함께 Type Object가 인스턴스화되고 나면, 우리는 Data Object의 Type Information르 결정하는 Data Object의 속성에 접근할 수 있습니다. Type Object는 또한 TYPE_KIND 속성 비교하기 위하여 IF 또는 CASE 문에서 사용되는 Constants(상수)를 포함하고 있습니다.


Runtime Type Creation


앞선 글에서 논의했듯이, Type Object는 RTTS의 RTTI 메소드를 사용해서 만들어집니다. 이러한 Type Object는 RTTS의 RTTC 메소드들을 사용하여 새로운 유형들을 만듭니다. RTTC 메소드들은 동적으로 Data Object를 정의하는 데 사용하는 Data Types를 동적으로 만드는 것을 가능하게 해줍니다.

예를 들어, 동적으로 구조체(Structure)을 만들어서, 그것을 SELECT 구문에서 사용하고 싶다고 해봅니다. 이러한 구조체의 필드는 오직 런타임시에만 알 수 있을 거라고 한다면, RTTC 메소드를 사용하여 Data Type을 정의하고 이 Data Type를 사용하여 동적으로 Data Object를 만드는 데 사용합니다. CL_ABAP_STRUCTDESCR, CL_ABAP_TABLEDESCR, CL_ABAP_REFDESCR 클래스들의 GET이라는 factory method를 통해 Type Object를 만드는데 사용할 수 있습니다.

Type Object를 만드는데 필요한 정보는 위에 적은 CL_ABAP_~ 클래스들의 factory method에 전달됩니다. 예를 들어, 구성요소의 세부사항들은 CL_ABAP_STRUCTURE의 factory method에 구조체를 위한 Type Object를 만들기 위해 전달됩니다. 유사하게, Structure Type Object(구조체 형식의 Type Obejct)는 CL_ABAP_TABLEDESCR 클래스에 factory method에 전달되어 Table Type Object(테이블 형식의 Type Object)를 만들기 위해 전달됩니다. 아래 예시는, 어떻게 RTTC 메소드가 동적으로 Data Type을 정의하고 이 Data Type을 통해 Data Object를 만드는지를 보여줍니다.

PARAMETERS: p_table TYPE string,
	        p_where TYPE string.
DATA: r_typedescr TYPE REF TO cl_abap_typedescr,

r_structdescr TYPE REF TO cl_abap_structdescr,
r_tabledescr TYPE REF TO cl_abap_tabledescr,
r_table TYPE REF TO data,
components TYPE cl_abap_structdescr=>component_table,
component LIKE LINE OF components,
ro_alv TYPE REF TO cl_salv_table.

FIELD-SYMBOLS : <table> TYPE ANY TABLE.

START-OF-SELECTION.

PERFORM get_table.
PERFORM display_table.
*&------------------------------------------------------------*
*& Form GET_TABLE
*&------------------------------------------------------------*
* text
*-------------------------------------------------------------*
FORM get_table .
 r_typedescr = cl_abap_typedescr=>describe_by_name( p_table ).
  TRY.
   r_structdescr ?= r_typedescr.
   CATCH cx_sy_move_cast_error.
  ENDTRY.

 components = r_structdescr->get_components( ).
 
 TRY.
  r_structdescr = cl_abap_structdescr=>get( components ).
  r_tabledescr = cl_abap_tabledescr=>get( r_structdescr ).
  CATCH cx_sy_struct_creation.
  CATCH cx_sy_table_creation .
 ENDTRY.

 TRY.
  CREATE DATA r_table TYPE HANDLE r_tabledescr.
  ASSIGN r_table->* TO <table>.
  CATCH cx_sy_create_data_error.
 ENDTRY.

 TRY.
  SELECT *
  FROM (p_table)
  INTO CORRESPONDING FIELDS OF TABLE <table> WHERE (p_where).
  CATCH cx_sy_sql_error.
 ENDTRY.
ENDFORM.
*&------------------------------------------------------------*
*& Form DISPLAY_TABLE
*&------------------------------------------------------------*
* text
*-------------------------------------------------------------*
FORM display_table .
 TRY.
  CALL METHOD cl_salv_table=>factory
   IMPORTING
    r_salv_table = ro_alv
   CHANGING
    t_table = <table>.
  CATCH cx_salv_msg.
 ENDTRY.
 
 ro_alv->display( ).
ENDFORM.

위 예시를 보면, TABLE 이름과 SELECT 문의 Where 조건에 사용될 두 개의 Selection Screen Field를 정의하였습니다. 프로그램 로직은 화면에서 어떠한 테이블이 입력되더라도 그 테이블의 데이터를 보여주도록 구성하였습니다.

이 로직을 성공하기 위해서, GET_TABLE 서브루틴에서, 구성 요소를 가져오기 위해 주어진 구조의 Type Information를 동적으로 식별합니다. 이 구성 요소들을 통해 즉석에서 인터널 테이블을 만들 수 있고, 요청된 테이블으로부터 데이터를 가져올 동적인 SELECT 문을 진행할 수 있습니다. 최종적으로 DISPLAY_TABLE 서브루틴을 통해 데이터를 출력할 수 있습니다.

위 예시에서 GET_TABLE 서브루틴에서, 선택 화면에서 입력된 테이블 이름에 근거하여 R_TYPEDESCR이라는 Type Object를 만듭니다. 이후에 R_TYPEDESCR이라는 Type Object를 R_STRUCTDESCR에 다운캐스팅을 진행합니다. R_STRUCTDESCR이라는 Type Object는 CL_ABAP_STRUCTDESCR 클래스의 인스턴스로 새로운 Type Object를 만드는 RTTC 메소드를 포함하고 있습니다.

이후에, GET_COMPONENTS 메소드를 호출하여, 구조체의 구성요소를 얻습니다. 이 정보르 사용하여, CL_ABAP_STRUCTDESCR 클래스의 GET이라는 factory method를 호출하여 Structure type object(구조체 형식의 유형 오브젝트)를 만듭니다. 우리는 이 구조체 형식의 Type Object를 CL_ABAP_TABLEDESCR 클래스에 전달하여 Table 형식의 Type Object를 만듭니다.

Table 형식의 Type Object를 얻은 후에, CREATE 구문에 TYPE HANDLE 어디션을 사용하여 이 Table Object의 데이터 참조를 인스턴스화 시킵니다. 이 인스턴스화를 통해 R_TABLE이라는 데이터 참조 객체를 만들 수 있고, 이 R_TABLE의 유형은 R_TABLEDESCR이라는 Type Object에서 정의됩니다.

TYPE와 LIKE addition이 Data Type 또는 Data Object를 구체화하는 것과 마찬자기로, CREATE DATA구문의 TYPE HANDLE이라는 addition은 Type Object를 구체화하는 것에 도움을 줍니다.

동적으로 인터널 테이블이 만들어진 후에, 그것을 SELECT 구문에 사용하여 주어진 SELECT 문에 사용하여 연속적으로 결과를 출력하는데 사용됩니다. 볼 수 있다 싶이, 에러들을 각 단계마다 다룰 수 있고, 이러한 에러 확인하는 과정은 Dynameic Programming에 필수입니다.

만약, 아래 예시처럼 선택 화면에 데이터를 정확히 입력하여 실행했다면 정확한 결과를 얻을 수 있을 것입니다.

위 예시를 통해 ,RTTI와 RTTC에 대해서 확인하였습니다.

반응형