Em alguns projetos eu tive a necessidade de salvar objetos preenchidos para usar em um momento posterior e tive uma grande dificuldade a primeira vista, pois não encontrei algo fácil de como fazer isso. Na época a primeira solução foi fazer uma tabela em que cada campo representava um atributo do meu objeto e salvar os atribuitos nessa tabela manualmente (não riam!).
Depois de um tempo descobri que isso não era uma boa solução e seria inviável quando aparecesse a necessidade de trabalhar com objetos complexos, que possuim atributos que também são objetos com mais atributos, e então saí em busca de outras soluções. Para resolver esse problema, descobri que existem 2 recursos bem legais:
Nesse documento iremos focar na primeira opção: a serialização. A serialização de objetos funciona basicamente assim:
Para exemplificar, vamos criar uma classe que serializa e deserializa objetos através de dois métodos estáticos.
*----------------------------------------------------------------------*
* CLASS ZCL_SERIALIZATION DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS zcl_serialization DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
*"* public components of class ZCL_SERIALIZATION
CLASS-METHODS transform_object_to_rawstring
IMPORTING
!io_object TYPE REF TO if_serializable_object
RETURNING
value(rv_xstring) TYPE xstring
EXCEPTIONS
transformation_failed .
CLASS-METHODS transform_rawstring_to_object
IMPORTING
!iv_xstring TYPE xstring
EXPORTING
!eo_object TYPE REF TO if_serializable_object
EXCEPTIONS
transformation_failed .
PROTECTED SECTION.
*"* protected components of class ZCL_SERIALIZATION
PRIVATE SECTION.
*"* private components of class ZCL_SERIALIZATION
ENDCLASS. "ZCL_SERIALIZATION DEFINITION
*----------------------------------------------------------------------*
* CLASS ZCL_SERIALIZATION IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS zcl_serialization IMPLEMENTATION.
* <SIGNATURE>---------------------------------------------------------------------------+
* | Static Public Method ZCL_SERIALIZATION =>TRANSFORM_OBJECT_TO_RAWSTRING
* +-------------------------------------------------------------------------------------+
* | [--->] IO_OBJECT TYPE REF TO IF_SERIALIZABLE_OBJECT
* | [<-()] RV_XSTRING TYPE XSTRING
* | [EXC!] TRANSFORMATION_FAILED
* +--------------------------------------------------------------------------</SIGNATURE>
METHOD transform_object_to_rawstring.
TYPES: line_t(4096)TYPE x .
TYPES: table_t TYPE STANDARD TABLE OF line_t .
DATA:lt_restab TYPE table_t.
FIELD-SYMBOLS: <lfs_restab> LIKE LINE OF lt_restab.
CALL TRANSFORMATION id_indent
SOURCE obj = io_object
RESULT XML lt_restab.
IF lt_restab IS NOT INITIAL.
LOOP AT lt_restab ASSIGNING <lfs_restab>.
CONCATENATE rv_xstring <lfs_restab>
INTO rv_xstring IN BYTE MODE.
ENDLOOP.
** compresss here
TRY.
CALL METHOD cl_abap_gzip=>compress_binary
EXPORTING
raw_in = rv_xstring
IMPORTING
gzip_out = rv_xstring.
CATCH cx_parameter_invalid_range .
CATCH cx_sy_buffer_overflow .
CATCH cx_sy_compression_error .
ENDTRY.
ELSE.
RAISE transformation_failed.
ENDIF.
ENDMETHOD. "transform_object_to_rawstring
* <SIGNATURE>---------------------------------------------------------------------------+
* | Static Public Method ZCL_SERIALIZATION =>TRANSFORM_RAWSTRING_TO_OBJECT
* +-------------------------------------------------------------------------------------+
* | [--->] IV_XSTRING TYPE XSTRING
* | [<---] EO_OBJECT TYPE REF TO IF_SERIALIZABLE_OBJECT
* | [EXC!] TRANSFORMATION_FAILED
* +--------------------------------------------------------------------------</SIGNATURE>
METHOD transform_rawstring_to_object.
DATA: lv_xstring_decompressed TYPE xstring,
lo_exception TYPE REF TO cx_root.
*** Restore the object here
*** 1) decompress the object
cl_abap_gzip=>decompress_binary(
EXPORTING
gzip_in = iv_xstring
IMPORTING
raw_out = lv_xstring_decompressed
).
*** 2) revert TRANSFORMATION
TRY .
CALL TRANSFORMATION id_indent
SOURCE XML lv_xstring_decompressed
RESULT obj = eo_object.
CATCH cx_root INTO lo_exception.
ENDTRY.
IF NOT eo_object IS BOUND.
RAISE transformation_failed.
ENDIF.
ENDMETHOD. "transform_rawstring_to_object
ENDCLASS. "ZCL_SERIALIZATION IMPLEMENTATION
O código é bem simples e auto-explicativo, resumindo tudo de forma breve os métodos funcionam assim:
Para exemplificar melhor, vamos pegar um objeto qualquer e serializar, salvar no banco e recuperar depois:
DATA: lo_my_instance TYPE REF TO lcl_my_class, "Esse objeto implementa a interface IF_SERIALIZABLE_OBJECT
lo_old_instance TYPE REF TO lcl_my_class,
lv_rawstring TYPE xstring,
lo_serialized TYPE REF TO if_serializable_object.
"Convertendo para binário - salvando a instância
CALL METHOD zcl_serialization=>transform_object_to_rawstring
EXPORTING
io_object = lo_my_instance
RECEIVING
rv_xstring = lv_rawstring
EXCEPTIONS
transformation_failed = 1
OTHERS = 2.
* Posso salvar minha variável LV_RAWSTRING em qualquer tabela que eu quiser,
* de acordo com a minha lógica de negócio
"Recuperando a instância - lendo do banco de dados
CALL METHOD zcl_serialization=>transform_rawstring_to_object
EXPORTING
iv_xstring = lv_rawstring
IMPORTING
eo_object = lo_serialized
EXCEPTIONS
transformation_failed = 1
others = 2.
IF sy-subrc IS INITIAL.
TRY .
lo_old_instance ?= lo_serialized. "Downcasting!
CATCH cx_root.
"Erro no casting (atributos mudaram?)
ENDTRY.
ENDIF.
Agora já conhecemos uma forma de salvar as instâncias dos nosso objetos no banco de dados e como recuperá-las. Claro que o exemplo é bem básico mas caso alguém tenha alguma dúvida, use a seção de comentários para continuarmos a discussão