개요 및 이 글에서 다루는 것
ABAP 7.40 SP08 이후 도입된 CONV 연산자는 명시적 타입 변환을 한 줄로 처리하는 인라인 표현식입니다. 과거에는 임시 변수를 선언해 값을 옮기고, 그 변수를 메서드 인자로 전달하는 3단계가 필요했습니다. CONV는 이 모든 과정을 CONV target_type( expression ) 한 줄로 압축합니다. 이 글에서는 다음 항목을 다룹니다.
- CONV 연산자의 문법과 타입 추론 (
#) 메커니즘 - 기존 임시 변수 방식 대비 가독성/유지보수 차이
- 메서드 호출 시 인라인 변환 패턴
- NEW, REF, VALUE 연산자와의 조합
- NUMC/STRING/CHAR 간 변환 시 주의점
- CAST와의 본질적 차이 (값 변환 vs 참조 캐스팅)
사전에 알고 있으면 좋은 것
ABAP의 기본 데이터 타입(I, P, N, C, STRING) 차이와 DATA 선언 구문, 메서드 시그니처(IMPORTING/EXPORTING 파라미터 타입 지정) 정도를 알고 있다면 충분합니다. 7.40 이후 도입된 인라인 선언(DATA(...)), VALUE, NEW 같은 동반 연산자를 함께 알고 있으면 활용 폭이 넓어집니다. ABAP for Cloud Development(릴리스 비고 기준) 또는 NetWeaver AS ABAP 7.40 SP08 이상 환경을 가정합니다.
환경 및 버전 준비
이 글의 예제는 다음 환경 중 어느 것에서도 동작합니다.
- SAP NetWeaver AS ABAP 7.40 SP08 이상 (CONV 최초 도입 버전)
- SAP S/4HANA 1709 이상 — ABAP Development Tools(ADT) for Eclipse 권장
- SAP BTP, ABAP Environment (Steampunk) — 최신 ABAP for Cloud Development 릴리스
개발 도구는 SE80(클래식)보다 ADT for Eclipse가 권장됩니다. 인라인 변환 표현식은 디버거 변수 표시 방식이 다르므로, ADT의 Variables 뷰에서 FREE_SELECTIONS나 호출 스택 변수 검사를 적극 활용하면 좋습니다. 백엔드 시스템 권한으로는 ZNAMESPACE에 클래스를 생성할 수 있는 개발 키와 패키지 할당 권한이 필요합니다. 테스트 데이터는 별도 데이터베이스 테이블 없이 인메모리 내부 테이블로 구성합니다.
핵심 개념 및 동작 원리
CONV 연산자의 기본 문법은 다음과 같습니다.
CONV target_type( expression )
CONV #( expression ) " 타입 추론 형태
target_type 자리에는 데이터 요소, 빌트인 타입(string, i, p 등), 또는 사용자 정의 타입을 넣을 수 있습니다. # 기호를 쓰면 컴파일러가 표현식이 사용되는 문맥(예: 대입 좌변, 메서드 파라미터 타입)으로부터 타입을 추론합니다.
비유하자면 CONV는 "포장지 갈아끼우기"입니다. 우체국에서 박스를 다른 규격으로 옮겨 담는 과정에서, 예전에는 빈 박스(DATA lv_tmp TYPE ...)를 미리 준비하고 내용물을 옮긴 다음 그 박스를 보냈습니다. CONV는 컨베이어 위에서 바로 규격을 바꿔주는 자동화 장비에 해당합니다. 컴파일러는 다음 단계로 처리합니다.
- 괄호 안 표현식의 정적 타입(static type)을 결정
- 타겟 타입을 명시값 또는 추론으로 확정
- 두 타입 간 변환 규칙(MOVE 규칙)을 적용해 임시 데이터 객체 생성
- 그 데이터 객체의 참조를 호출 측에 전달
중요한 점은 CONV가 새로운 값을 만든다는 것입니다. 원본 변수의 메모리를 그대로 가리키는 것이 아니라, 변환된 값을 보관하는 익명 임시 객체를 생성합니다. 따라서 결과를 변경해도 원본은 영향받지 않습니다.
한편 CAST는 이름이 비슷하지만 전혀 다른 일을 합니다. CAST target_class( oref )는 참조 변수의 정적 타입을 좁히는(narrowing/downcasting) 연산이며, 값을 복사하거나 변환하지 않습니다. 호환되지 않으면 런타임에 CX_SY_MOVE_CAST_ERROR가 발생합니다. 정리하면 CONV는 값 변환, CAST는 참조 타입 변환입니다.
실전 예제 1단계 — 기본 사용법
먼저 가장 단순한 형태입니다. 문자열로 받은 주문 번호를 정수형 카운터에 더하는 상황을 가정합니다.
REPORT z_conv_basic_demo.
DATA: lv_order_count TYPE i VALUE 0.
" 과거 방식: 임시 변수 + MOVE
DATA(lv_input_legacy) = `42`.
DATA lv_tmp_int TYPE i.
lv_tmp_int = lv_input_legacy.
lv_order_count = lv_order_count + lv_tmp_int.
" CONV 사용: 한 줄로
DATA(lv_input_modern) = `58`.
lv_order_count = lv_order_count + CONV i( lv_input_modern ).
WRITE: / 'Total orders:', lv_order_count.
두 번째 블록에서는 lv_tmp_int 같은 중간 변수가 사라졌습니다. 코드 라인이 줄어드는 것보다 더 중요한 것은, 변환의 의도가 표현식 자리에 직접 드러난다는 점입니다. 리뷰어가 "왜 갑자기 int 변수가 등장하지?"라고 묻지 않아도 됩니다.
타입 추론 형태도 살펴봅니다.
DATA lv_total_amount TYPE p LENGTH 9 DECIMALS 2.
DATA(lv_text_amount) = `1250.75`.
" 좌변 타입(p LENGTH 9 DECIMALS 2)으로 추론
lv_total_amount = CONV #( lv_text_amount ).
#은 문맥에서 타입이 확정 가능할 때만 쓸 수 있습니다. DATA(x) = CONV #( ... )처럼 좌변도 인라인 선언이라면 컴파일러가 추론할 근거가 없어 오류가 납니다.
실전 예제 2단계 — 메서드 파라미터 인라인 변환과 에러 처리
실제 업무에서는 메서드 호출 시 파라미터 타입 불일치를 해소하기 위해 CONV를 가장 자주 씁니다. 영업 주문 항목을 다루는 클래스를 예로 들겠습니다.
CLASS zcl_sales_item_handler DEFINITION PUBLIC.
PUBLIC SECTION.
TYPES:
BEGIN OF ty_item_log,
item_no TYPE numc10,
material TYPE char18,
quantity TYPE p LENGTH 9 DECIMALS 3,
logged_at TYPE timestampl,
END OF ty_item_log.
METHODS register_item
IMPORTING
iv_item_no TYPE numc10
iv_material TYPE char18
iv_quantity TYPE p
RAISING
cx_sy_conversion_no_number.
ENDCLASS.
CLASS zcl_sales_item_handler IMPLEMENTATION.
METHOD register_item.
DATA(ls_log) = VALUE ty_item_log(
item_no = iv_item_no
material = iv_material
quantity = iv_quantity
logged_at = cl_abap_tstmp=>utclong2tstmp( utclong_current( ) ) ).
" 실제 환경에서는 로그 테이블 INSERT 또는 응용 로그 호출
ENDMETHOD.
ENDCLASS.
" 호출부: 외부 시스템에서 STRING 형태로 들어온 값들
DATA(lo_handler) = NEW zcl_sales_item_handler( ).
DATA(lv_raw_item) = `0000004711`.
DATA(lv_raw_mat) = `MAT-A-001`.
DATA(lv_raw_qty) = `12.500`.
TRY.
lo_handler->register_item(
iv_item_no = CONV numc10( lv_raw_item )
iv_material = CONV char18( lv_raw_mat )
iv_quantity = CONV p( lv_raw_qty ) ).
CATCH cx_sy_conversion_no_number INTO DATA(lx_conv).
MESSAGE lx_conv->get_text( ) TYPE 'E'.
ENDTRY.
여기서 주목할 점은 두 가지입니다. 첫째, 호출부 3개 파라미터가 모두 STRING인데 메서드 시그니처는 NUMC/CHAR/P입니다. CONV가 없다면 호출 직전에 임시 변수 3개를 선언하고 대입한 뒤 전달해야 합니다. 둘째, NUMC나 P로의 변환은 입력이 숫자 형식이 아닐 경우 CX_SY_CONVERSION_NO_NUMBER 예외를 던집니다. 따라서 CONV는 항상 안전한 변환이 아니며, 외부 입력을 다룰 때는 반드시 TRY/CATCH로 감싸는 것이 권장됩니다.
실전 예제 3단계 — 프로덕션 패턴과 다른 연산자 조합
대량 처리, 참조 객체 생성, 컬렉션 빌드와 결합한 패턴입니다. 다음은 입고 전표 다건을 한 번에 등록하는 시나리오입니다.
CLASS zcl_inbound_doc_builder DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
BEGIN OF ty_raw_line,
doc_id TYPE string,
plant TYPE string,
amount TYPE string,
END OF ty_raw_line,
tt_raw_line TYPE STANDARD TABLE OF ty_raw_line WITH EMPTY KEY.
TYPES:
BEGIN OF ty_doc_line,
doc_id TYPE numc10,
plant TYPE char4,
amount TYPE p LENGTH 13 DECIMALS 2,
END OF ty_doc_line,
tt_doc_line TYPE STANDARD TABLE OF ty_doc_line WITH EMPTY KEY.
CLASS-METHODS transform
IMPORTING it_raw TYPE tt_raw_line
RETURNING VALUE(rt_docs) TYPE tt_doc_line.
ENDCLASS.
CLASS zcl_inbound_doc_builder IMPLEMENTATION.
METHOD transform.
rt_docs = VALUE #(
FOR <ls_raw> IN it_raw
( doc_id = CONV numc10( <ls_raw>-doc_id )
plant = CONV char4( <ls_raw>-plant )
amount = CONV p( <ls_raw>-amount ) ) ).
ENDMETHOD.
ENDCLASS.
VALUE + FOR 루프 안에서 CONV를 사용하면 변환과 컬렉션 빌드가 한 표현식으로 묶입니다. 별도의 LOOP/APPEND 구문 없이 함수형 스타일로 작성되어, 의도가 데이터 흐름 자체로 드러납니다.
참조 객체와의 결합도 자주 쓰입니다. NEW로 인스턴스를 만들면서 생성자 인자를 변환해야 할 때입니다.
DATA(lo_amount) = NEW zcl_money(
iv_currency = CONV waers( `EUR` )
iv_value = CONV dmbtr( `9999.99` ) ).
DATA(lr_count) = REF #( CONV i( `100` ) ).
" lr_count 는 익명 임시 객체를 가리키는 데이터 참조
성능 관점에서는 CONV 자체의 비용이 임시 변수를 선언해 대입하는 것과 본질적으로 같습니다. 변환된 값을 담을 임시 데이터 객체가 어차피 필요하기 때문입니다. 따라서 핫 루프 안에서 동일한 표현식을 반복 변환하는 것은 피하고, 루프 외부에서 한 번 변환해 변수에 담아두는 것이 일반적으로 권장됩니다. 단위 테스트에서는 cl_abap_unit_assert=>assert_equals에 기대값을 넘길 때 CONV로 타입을 맞추면 시그니처 매칭 오류를 깔끔히 회피할 수 있습니다.
흔한 실수와 트러블슈팅
FAQ 1. CONV #( ... )가 컴파일 오류를 냅니다.
# 추론은 문맥이 명확할 때만 동작합니다. DATA(lv_x) = CONV #( lv_input ).처럼 좌변까지 추론하려 들면 두 추론이 충돌해 실패합니다. 좌변 타입을 명시하거나 CONV 자리에 타입을 직접 적어야 합니다.
FAQ 2. 숫자 문자열 변환에서 런타임 덤프가 납니다.
CONV i( `12abc` )처럼 형식이 어긋난 문자열을 정수/패킹 타입으로 바꾸면 CX_SY_CONVERSION_NO_NUMBER가 발생합니다. 외부 시스템 입력이라면 항상 TRY ... CATCH cx_sy_conversion_error 또는 더 좁은 서브 클래스로 감싸고, 사전에 검증 로직(예: 정규표현식, cl_abap_matcher)을 거치는 것이 안전합니다.
FAQ 3. CONV로 클래스 참조를 변환하려 했는데 안 됩니다.
CONV는 값 데이터 객체(elementary, structured, internal table) 변환을 위한 연산자입니다. 객체 참조 변수의 타입을 좁히는 것은 CAST sub_class( oref )의 역할입니다. 둘을 혼동하면 CONV가 컴파일 자체를 거부합니다.
FAQ 4. P 타입 변환 후 소수점이 잘립니다.
대상 타입의 DECIMALS가 원본보다 작으면 반올림/절사가 일어납니다. 이는 정밀도 손실이며 CONV의 잘못이 아니라 일반적인 MOVE 규칙입니다. 통화 금액처럼 정밀도가 중요한 데이터는 변환 대상 타입의 길이/소수 자릿수를 사전에 확인해야 합니다.
FAQ 5. 디버거에서 변환된 값이 안 보입니다.
인라인 표현식의 결과는 익명 임시 객체에 머물기 때문에 변수 이름이 없습니다. ADT 디버거에서는 호출 스택의 파라미터 노드를 펼쳐서 확인하거나, 디버깅 시점에 한정해 한 줄을 임시 변수 대입으로 풀어 쓰는 것이 권장됩니다.
이후에 살펴볼 만한 주제
CONV를 익혔다면 자연스럽게 이어지는 표현식 기반 ABAP 주제들이 있습니다. VALUE 연산자(구조체/내부 테이블 인라인 생성), REDUCE와 FOR를 활용한 함수형 컬렉션 처리, COND/SWITCH 조건 표현식, 그리고 CAST와 RTTI(cl_abap_typedescr) 기반 동적 타입 검사가 다음 단계로 권장됩니다. 또한 RAP(RESTful Application Programming Model)의 BDEF 핸들러 구현부에서 외부 페이로드를 내부 타입으로 옮길 때 CONV가 빈번히 등장하므로, RAP behavior implementation 패턴을 함께 보면 실무 감각을 빨리 쌓을 수 있습니다.
참고 링크
- SAP Help Portal — CONV, Constructor Expression for Type Conversion
- SAP Help Portal — CONV Operator Syntax Reference
- SAP Help Portal — Constructor Expressions Overview
- SAP Help Portal — CAST Operator (참조 캐스팅 비교)
- SAP Community — ABAP 7.40 Tag (인라인 선언/표현식 사례)
- SAP Help Portal — ABAP Environment on SAP BTP
댓글 0
아직 댓글이 없습니다.