Additional Blogs by Members
cancel
Showing results for 
Search instead for 
Did you mean: 
Former Member

Sumário

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:

  1. Serialização de Objetos
  2. ABAP Shared Objects

Nesse documento iremos focar na primeira opção: a serialização. A serialização de objetos funciona basicamente assim:

  • Pré-requisito: implementar a interface IF_SERIALIZABLE_OBJECT na classe a ser salva
  • Seus atributos (tanto públicos como privados) serão transformados em XML
  • O XML é transformados em RAWSTRING
  • Salvamos o conteúdo RAWSTRING em apenas um campo em uma tabela.
  • Para recuperar o conteúdo, buscaremos o campo RAWSTRING na tabela
  • Converteremos o RAWSTRING para XML.
  • Recuperaremos a instância que tinhamos em um objeto.

Código-Fonte

Para exemplificar, vamos criar uma classe que serializa e deserializa objetos através de dois métodos estáticos.

Definição

*----------------------------------------------------------------------*

*       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

Implementação

*----------------------------------------------------------------------*

*       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


Comentários

O código é bem simples e auto-explicativo, resumindo tudo de forma breve os métodos funcionam assim:

  1. TRANSFORM_OBJECT_TO_RAWSTRING
    • Parâmetro de entrada: um objeto IF_SERIALIZABLE_OBJECT (pode ser qualquer objeto que implemente essa interface)
    • Parâmetro de saída: uma variável XSTRING (conteúdo do objeto de forma serializada e pronto para ser salvo no banco de dados)
    • Código-fonte:  Basicamente ele pega o objeto e transforma para XML usando a transformation ID_IDENT e depois transforma isso para binário e comprime, para otimizar.
  2. TRANSFORM_RAWSTRING_TO_OBJECT
    • Parâmetro de entrada: uma variável XSTRING (conteúdo do objeto de forma serializada, que veio do banco de dados)
    • Parâmetro de saída: um objeto IF_SERIALIZABLE_OBJECT (deve ser um objeto TYPE REF TO if_serializable_object)
    • Código-fonte:  Aqui ele pega o conteúdo em binário comprimido, descomprime e transforma o XML de volta para objeto usando a mesma transformation ID_IDENT e retorna um objeto que implementa a interface com a instância salva.

Uso dos métodos

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.

Conclusão

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