Blog SAPienteSAPiente
ABAP Cloud

Biblioteca XCO no ABAP Cloud: o que ela faz e como facilita o dia a dia

SAPiente25 de jun. de 2026· 8 min read

O Clean Core cortou metade das classes que você usava — a XCO devolve quase todas

Quem migra pra ABAP Cloud toma o mesmo susto que eu tomei: você abre uma classe que usou a vida inteira, o ATC pinta de vermelho e avisa que ela "não é liberada para uso em ABAP Cloud". sy-uname, cl_gui_frontend_services, abap2xlsx, meia dúzia de CALL FUNCTION — tudo fora. Aí começa a parte chata: caçar qual é a classe liberada que faz a mesma coisa.

A XCO existe pra encurtar essa caça. É a biblioteca da SAP que junta as funções do dia a dia atrás de uma porta só — a classe xco_cp. Em vez de decorar dez nomes, você digita xco_cp=> e o autocomplete do ADT te leva ao resto.

Não vou despejar a biblioteca inteira aqui. Vou mostrar o que eu de fato uso nos meus projetos e o que cada módulo substitui — todos com APIs released, que passam no ATC de Cloud Readiness sem gambiarra.

O essencial da XCO em 7 linhas

  • XCO = eXtension Components. Uma porta de entrada (xco_cp) para dezenas de funções utilitárias liberadas para ABAP Cloud.

  • Interface fluente: você encadeia as chamadas e lê o resultado no fim com ->value.

  • Campos de sistema: xco_cp=>sy->user( ), ->date( ), ->time( ), ->moment( ) no lugar dos sy-.

  • Chaves: xco_cp=>uuid( )->value gera UUID e converte entre os quatro formatos (x16, C22, C32, C36).

  • Texto e regex: xco_cp=>string( ) faz split/join/upper/match; xco_cp=>regular_expression( ) valida com PCRE.

  • Integração: xco_cp_json monta/lê JSON e xco_cp=>string( )->as_xstring( ... ) gera hash SHA.

  • Arquivos e log: xco_cp_xlsx lê/gera Excel; xco_cp_bal escreve no Application Log.

Os dois que mais me salvam: o bloco de campos de sistema (acabou a pergunta "como pego o usuário no cloud?") e o XCO Excel, que resolveu o upload de planilha de vez. Se você for testar só dois, comece por esses.

O que é a biblioteca XCO, afinal?

XCO é sigla de eXtension Components. Na prática, é um monte de classe utilitária com o prefixo xco_cp (de Cloud Platform) que a SAP liberou pro ABAP Cloud. A ideia toda é você não ter que caçar: parte de xco_cp e segue o autocomplete.

O estilo é fluent — cada método devolve um objeto, então você emenda as operações numa linha e pega o dado "cru" no fim, com ->value:

DATA(resultado) = xco_cp=>string( `abap cloud` )->to_upper_case( )->split( ` ` )->value.
" resultado = tabela com 'ABAP' e 'CLOUD'

Repare: to_upper_case( ) devolve um objeto string, split( ) devolve um objeto de tabela, e o ->value só aparece quando você quer o conteúdo. Estranha nas primeiras vezes — depois vira natural, e o código fica curto.

Como descobrir o que existe: digite xco_cp=> no ADT e abra o autocomplete (Ctrl+Espaço). Cada método é um ramo da biblioteca. Combinado com o filtro api:released do Open Object (Ctrl+Shift+A), você só esbarra em coisa que dá pra usar no cloud.

Como pegar usuário, data e hora sem os campos sy-?

Esse é o primeiro tranco da migração. Ler sy-uname ou sy-datum direto não passa no ATC de Cloud Readiness. Tudo foi pra xco_cp=>sy — e, de quebra, você ganha fuso e formato, que antes ficavam por sua conta e rendiam bug.

" Usuário atual (no lugar de sy-uname)
DATA(usuario) = xco_cp=>sy->user( )->name.

" Data atual no fuso do usuário, em formato ABAP (YYYYMMDD)
DATA(hoje) = xco_cp=>sy->date( xco_cp_time=>time_zone->user
                       )->as( xco_cp_time=>format->abap )->value.

" Mesma data, agora em ISO 8601 estendido (2026-06-24)
DATA(hoje_iso) = xco_cp=>sy->date( xco_cp_time=>time_zone->user
                           )->as( xco_cp_time=>format->iso_8601_extended )->value.

" Hora atual e idioma de logon
DATA(agora)  = xco_cp=>sy->time( xco_cp_time=>time_zone->user )->as( xco_cp_time=>format->abap )->value.
DATA(idioma) = xco_cp=>sy->language( )->value.

O parâmetro de fuso é o pulo do gato: time_zone->user dá a data/hora do usuário; ->utc dá em UTC. No mundo sy-, escolher entre sy-datum e sy-datlo era erro silencioso esperando acontecer — aqui a intenção fica escrita no código. E o idioma vem com extras: language( )->get_name( ) traz o texto curto e language( )->as( xco_cp_language=>format->iso_639 ) devolve o código ISO, coisa que o sy-langu nunca deu.

Como fazer conta com datas e comparar dois instantes?

Somar dia a uma data sempre rendeu aquele código feio com aritmética na unha. A XCO trata data como objeto: soma, subtrai e lê o componente sem você cuidar de virada de mês.

" Amanhã: soma 1 dia e devolve em formato ABAP
DATA(amanha) = xco_cp=>sy->date( )->add( iv_day = 1 )->as( xco_cp_time=>format->abap )->value.

" Há 30 dias
DATA(ha_30_dias) = xco_cp=>sy->date( )->subtract( iv_day = 30 )->as( xco_cp_time=>format->abap )->value.

" Ler componentes da data
DATA(data)  = xco_cp=>sy->date( ).
DATA(ano)   = data->year.
DATA(mes)   = data->month.
DATA(dia)   = data->day.

Pra comparar tempo existe o moment — data e hora num ponto só. Ele responde "antes/depois" e até "esse instante cai dentro do intervalo?" sem você converter nada pra timestamp na mão:

DATA(agora)  = xco_cp=>sy->moment( xco_cp_time=>time_zone->user ).
DATA(limite) = xco_cp=>sy->moment( xco_cp_time=>time_zone->user )->add( iv_hour = 2 ).

IF agora->is_before( limite ).
  " ainda dentro da janela de 2 horas
ENDIF.

" Unix timestamp, quando uma API externa pede epoch
DATA(epoch) = xco_cp=>sy->unix_timestamp( )->value.

Cuidado com a data serial do Excel. Esse add/subtract da XCO é pra datas ABAP. A coluna de data que vem de uma planilha é outra história: o Excel conta dias a partir de 30/12/1899, então o valor chega como número serial e você soma à base, não usa o pipeline de data da XCO. Mostro isso no post do upload de Excel.

Como gerar UUID e converter entre formatos?

UUID aparece o tempo todo: chave técnica de tabela RAP, ID de correlação, external_id de log. A XCO gera e — o que me salva mais — converte entre os quatro formatos sem eu ter que lembrar qual classe fazia x16 pra C36.

" UUID binário de 16 bytes (sysuuid_x16) — o típico de chave de tabela
DATA(uuid_x16) = xco_cp=>uuid( )->value.

" Mesmo UUID em representações textuais
DATA(uuid_c22) = xco_cp=>uuid( )->as( xco_cp_uuid=>format->c22 )->value.
DATA(uuid_c32) = xco_cp=>uuid( )->as( xco_cp_uuid=>format->c32 )->value.
DATA(uuid_c36) = xco_cp=>uuid( )->as( xco_cp_uuid=>format->c36 )->value. " 36 chars com hífens

" Converter um C36 recebido de fora para x16
DATA(de_volta) = xco_cp_uuid=>format->c36->to_uuid( uuid_c36 )->value.

Na prática: o x16 é o que você grava na tabela; o C36 (BAF0A1E7-5FB0-...) é o que uma API REST espera receber. Ter os dois caminhos numa classe só evita o vai e volta com cl_system_uuid e conversão de codepage.

Como tratar texto sem encher o código de SPLIT e CONCATENATE?

Tem um cenário onde isso brilha de verdade: leitura de planilha. No meu app de upload de roteiros, cada célula do Excel chega como string e precisa virar campo tipado. É aí que o xco_cp=>string( ) ganha — split, trim, maiúscula, tudo emendado numa expressão em vez de três comandos soltos. O xco_cp=>strings( ) (no plural) trata uma tabela de textos.

" Recortar a partir da 2ª posição
DATA(sub) = xco_cp=>string( `XABAP` )->from( 2 )->value.            " 'ABAP'

" Split e join
DATA(partes) = xco_cp=>string( `Hello.World.ABAP` )->split( `.` )->value.   " tabela
DATA(junto)  = xco_cp=>strings( partes )->join( `, ` )->value.              " 'Hello, World, ABAP'

" Maiúsculas / minúsculas
DATA(maiusc) = xco_cp=>string( `abap` )->to_upper_case( )->value.           " 'ABAP'
DATA(minusc) = xco_cp=>string( `HALLO WORLD` )->to_lower_case( )->value.

" Teste rápido de padrão direto no objeto string
IF xco_cp=>string( ` 1` )->matches( `\s\d` ).
  " começa com espaço seguido de dígito
ENDIF.

O SPLIT ... AT continua valendo, ninguém é obrigado a trocar tudo. Mas quando a transformação tem três ou quatro passos, a versão encadeada lê de cima pra baixo e dá menos brecha pra erro.

Como validar entrada com expressão regular?

Conferir um código de cliente, validar formato de e-mail, extrair um trecho: regex resolve, e a XCO entrega um motor PCRE (Perl Compatible) liberado — o mesmo dialeto que você já usa em JavaScript ou Python, sem a surpresa do POSIX antigo.

" Padrão: só maiúsculas, dígitos e underscore
DATA(regex) = xco_cp=>regular_expression(
                iv_value  = `^[A-Z0-9_]+$`
                io_engine = xco_cp_regular_expression=>engine->pcre( ) ).

IF regex->matches( `MEU_CONTEUDO` ).
  " válido
ENDIF.

" Extrair ocorrências direto de um texto (grep devolve uma tabela)
DATA(achados) = xco_cp=>string( `this is a list of words` )->grep(
                  iv_regular_expression = `\w*is\w*`
                  io_engine             = xco_cp_regular_expression=>engine->pcre( ) )->value.

Como montar e ler JSON pra falar com uma API?

No mesmo app de roteiros eu chamo a API do Business Partner pra gravar latitude e longitude do cliente. Pra montar o corpo da requisição, o data builder da XCO resolve sem eu precisar criar uma estrutura ABAP só pra serializar — útil quando o JSON não bate exatamente com nenhum tipo que você tem:

DATA(json) = xco_cp_json=>data->builder( )->begin_object( )
               ->add_member( `CarrierId` )->add_string( `DL` )
               ->add_member( `ConnectionId` )->add_string( `0017` )
               ->add_member( `Active` )->add_boolean( abap_true )
             ->end_object( )->get_data( )->to_string( ).
" json = {"CarrierId":"DL","ConnectionId":"0017","Active":true}

O caminho inverso é o xco_cp_json=>data->from_string( json ), que devolve um objeto navegável pra você ler membro a membro. Quando o payload mapeia 1:1 com um tipo, dá pra serializar a estrutura inteira de uma vez; o builder é pro resto.

Como gerar um hash SHA-256?

Esse é mais de nicho — uso quando preciso de checksum pra detectar mudança de conteúdo ou de uma assinatura. A XCO calcula a partir do objeto string, com o algoritmo escolhido na classe xco_cp_hash:

DATA(hash) = xco_cp=>string( `conteudo-a-assinar` )->as_xstring(
               xco_cp_hash=>algorithm->for( `SHA256` ) )->value.

Detalhe que confunde: a XCO tem objeto dedicado só pro SHA1; pra SHA256 e os outros, você passa o nome do algoritmo como texto em xco_cp_hash=>algorithm->for( 'SHA256' ). Se preferir a via clássica, cl_abap_message_digest (com calculate_hash_for_char) também é liberada e resolve igual.

Como ler e gerar Excel (.xlsx) no cloud?

Esse módulo sozinho já justifica conhecer a XCO. Sem cl_gui_frontend_services, sem OPEN DATASET e sem abap2xlsx, ler planilha no Public Cloud parecia beco sem saída. A classe xco_cp_xlsx lê o .xlsx direto do xstring pra uma tabela interna — e também gera um Excel pra download.

" Ler: do conteúdo do arquivo para acesso de leitura
DATA(lo_document)  = xco_cp_xlsx=>document->for_file_content( iv_file_content = lv_xstring ).
DATA(lo_xlsx)      = lo_document->read_access( ).
DATA(lo_worksheet) = lo_xlsx->get_workbook( )->worksheet->at_position( 1 ).

" Gerar: um documento vazio para escrita -> vira xstring para download
DATA(lo_write) = xco_cp_xlsx=>document->empty( )->write_access( ).

Tem o tutorial completo disso aqui. Montei o app do zero — RAP com draft, @Semantics.largeObject pro controle de upload, leitura do Excel com a XCO, validação de template e geração da planilha-modelo. Está em Upload de Excel (.xlsx) no RAP em S/4HANA Cloud com a XCO.

Excel sim, CSV não. A XCO tem módulo próprio só pra Excel (xco_cp_xlsx) — não existe um xco_cp_csv. CSV no cloud você resolve na mão: converte o xstring em texto com cl_abap_conv_codepage=>create_in( )->convert( ) (com fallback pra cl_abap_conv_in_ce + codepage 1160 quando o arquivo não vem em UTF-8), faz SPLIT AT cl_abap_char_utilities=>cr_lf pra separar as linhas e SPLIT no delimitador (;) pra separar os campos. É exatamente a abordagem que sigo no upload de CT-e on-stack (CSV). O acceptableMimeTypes do largeObject aceita text/csv no controle de upload, mas quem interpreta o conteúdo é o seu código, não a XCO.

Como gravar no Application Log direto pela XCO?

Dá pra escrever no Application Log (a SLG1 do mundo cloud) sem instanciar a cadeia cl_bali_* na mão. O xco_cp_bal embrulha tudo numa fábrica fluente: você cria o log apontando objeto/sub-objeto e vai anexando mensagem.

" Criar o log na persistência de banco
DATA(lo_log) = xco_cp_bal=>for->database( )->log->create(
                 iv_object      = `ZMEU_OBJETO`
                 iv_subobject   = `ZMEU_SUBOBJETO`
                 iv_external_id = `CARGA-2026-06-24` ).

" Anexar uma mensagem (a partir de um SYMSG)
lo_log->add_message( VALUE symsg( msgty = `W`
                                 msgid = `ZMINHA_CLASSE_MSG`
                                 msgno = `001`
                                 msgv1 = `Item 1` ) ).

Três coisas que evitam dor de cabeça: o objeto e o sub-objeto do log nascem no ADT (a SLG0 não é liberada no cloud); você precisa de uma classe de mensagens com as mensagens que vai usar; e a autorização S_APPL_LOG tem que liberar o objeto. Na variante for->database( ), a XCO persiste por uma segunda conexão de banco — então não tem save obrigatório, e o log sobrevive mesmo se o processo principal cair.

Conecta com o fluxo de jobs. No post de Application Jobs eu montei o log com as classes cl_bali_*, que dão mais controle sobre cabeçalho e severidade. O xco_cp_bal é o atalho fluente pro mesmo Application Log — escolha conforme o quanto você precisa mexer nesses detalhes.

E os módulos mais avançados: gerar objeto e ler o repositório

Os dois módulos que miram automação são os menos conhecidos. O de Generation cria objeto de repositório por código — scaffolding de classe, domínio, data element a partir de um template, dentro de um transporte. O de Info System faz o contrário: lê metadado de objeto existente — fonte de um método, checagem de sintaxe, atributos.

" Gerar: criar uma classe num transporte (esqueleto do fluxo)
DATA(lo_op) = xco_cp_generation=>environment->dev_system( lv_transport
                )->create_put_operation( ).

lo_op->for-clas->add_object( `ZCL_MINHA_CLASSE`
            )->set_package( `Z_MEU_PACOTE`
            )->create_form_specification( ).

lo_op->execute( ).

" Info System: ler a fonte de um método e checar sintaxe
DATA(lt_erros) = xco_cp_abap=>class( `ZCL_MINHA_CLASSE` )->check_syntax( ).
DATA(fonte)    = xco_cp_abap=>class( `ZCL_MINHA_CLASSE`
                   )->implementation->method( `IF_OO_ADT_CLASSRUN~MAIN`
                   )->content( )->get_source( ).

É a base de gerador caseiro (criar dezenas de objetos a partir de uma planilha de configuração) e de quality gate (rodar checagem de sintaxe por código antes de ativar) — coisa que antes pedia API interna não liberada. Vale só uma ressalva: a API de geração muda mais entre releases, então confira o que o seu sistema expõe antes de apostar nela.

Que outros módulos a XCO ainda traz?

A biblioteca é grande e cresce a cada release. Além do que já cobrimos, guarde estes no radar — pra você lembrar de procurar na XCO antes de sair instanciando classe avulsa:

Módulo

Classe de entrada

Para quê

Binário (xstring)

xco_cp=>xstring( )

Operar conteúdo binário — base64, conversão de/para string, concatenação.

Mensagens

xco_cp=>message( ) / messages( )

Montar mensagens (a leitura da atual já vem de xco_cp=>sy->message( )).

Contexto / Tenant

xco_cp=>current->tenant( )

System ID, GUID, global/subaccount e URLs do tenant — sem sy-sysid/sy-mandt.

Call stack

xco_cp=>current / xco_cp_call_stack

Inspecionar e formatar a pilha de chamadas de quem invocou a sua lógica.

Application Log

xco_cp_bal

Gravar no Application Log de forma fluente (visto acima).

O xco_cp=>current->tenant( ) é um exemplo prático do dia a dia: pegar o identificador do sistema sem tocar em campo restrito.

DATA(tenant)    = xco_cp=>current->tenant( ).
DATA(system_id) = tenant->get_id( ).
DATA(guid)      = tenant->get_guid( )->value.

XCO x clássico: o que muda no código?

Pra fixar, o "antes e depois". A coluna da esquerda é o que você fazia (e que muitas vezes não passa no ATC de Cloud Readiness); a da direita é o equivalente XCO liberado.

Tarefa

Clássico (restrito no cloud)

XCO (liberado)

Usuário atual

sy-uname

xco_cp=>sy->user( )->name

Data / hora

sy-datum / sy-uzeit

xco_cp=>sy->date( ) / ->time( )

Gerar UUID

cl_system_uuid

xco_cp=>uuid( )->value

Quebrar/juntar texto

SPLIT / CONCATENATE

xco_cp=>string( )->split( ) / strings( )->join( )

Regex

cl_abap_regex (POSIX)

xco_cp=>regular_expression( ) (PCRE)

Montar JSON

/ui2/cl_json (não liberado)

xco_cp_json=>data->builder( )

Ler/gerar Excel

abap2xlsx (não liberado)

xco_cp_xlsx

Hash SHA-256

cl_abap_message_digest

xco_cp=>string( )->as_xstring( xco_cp_hash=>... )

Application Log

cl_bali_* + SLG0

xco_cp_bal=>for->database( )

Sistema / tenant

sy-sysid / sy-mandt

xco_cp=>current->tenant( )

XCO não é um coringa para tudo. Pra hash, o cl_abap_message_digest também é liberado; pra alguns casos de string, a sintaxe nativa é mais direta. A regra que eu sigo: uso a XCO quando o equivalente clássico não é liberado no cloud, ou quando o encadeamento deixa o código mais limpo. Não troco a + 1 por uma cadeia XCO só por moda.

Perguntas frequentes

A XCO só funciona em ABAP Cloud?

Não. As classes xco_cp* nasceram pensando no cloud, mas a maioria também está no ABAP clássico (on-premise) em releases recentes. O ganho maior aparece no Clean Core, onde muita classe antiga deixou de ser liberada e a XCO vira o caminho oficial.

Preciso tratar exceção em toda chamada XCO?

Boa parte dos métodos é no_check (sem assinatura de exceção), então o compilador não obriga um TRY. Mas operação que depende de conteúdo externo — ler um Excel quebrado, por exemplo — pode disparar cx_xco_runtime_exception. Pra entrada não confiável, mantenha o TRY ... CATCH.

A XCO substitui de vez os campos sy-?

No dia a dia, sim: usuário, data, hora, fuso, idioma e mensagem têm equivalente em xco_cp=>sy, e sysid/mandt vêm de xco_cp=>current->tenant( ). Alguns campos bem específicos de runtime ainda saem de outras APIs liberadas, mas o que você lê com mais frequência está coberto — e com fuso e formato explícitos.

Onde vejo a lista completa de módulos?

Na SAP Help, em "Overview of XCO Modules", no repositório SAP-samples/abap-cheat-sheets e na página-índice da série XCO da Software Heroes, que vai módulo por módulo. Como a biblioteca cresce a cada release, confira a versão do seu sistema: um módulo pode existir num S/4HANA Cloud atual e ainda não no seu on-premise.

XCO Excel aguenta planilha grande?

Ela lê via stream de linhas, o que ajuda, mas o arquivo inteiro chega como xstring em memória. Pra carga pesada, valide o tamanho antes de processar e jogue pro background com Application Jobs, pra não estourar o tempo de uma requisição online.

Conclusão

A XCO não inventa nada que o ABAP já não fizesse — ela organiza. Em vez de você lembrar dez nomes de classe e descobrir na ativação que metade não é liberada, parte de xco_cp=> e segue o autocomplete. Campo de sistema, data com fuso, UUID, texto, regex, JSON, hash, Excel, Application Log e contexto de tenant: o caminho oficial e legível está todo ali.

O conselho é o mesmo do post sobre o ADT: não tente decorar tudo. Da próxima vez que o ATC reclamar de uma classe não liberada, procure o equivalente na XCO antes de partir pra gambiarra. Em pouco tempo o xco_cp=> vira reflexo — e o código fica, de quebra, mais limpo e à prova de Clean Core.

Referências oficiais

TagsADTClean CoreDesenvolvedorPerformaceEclipse
Avalie este conteúdo
para avaliar
SAPiente
@sapiente

Blog sobre SAP, ABAP, BTP, Fiori e tudo que envolve o ecossistema SAP.

Ver perfil →
FacebookInstagramYouTubeTwitter

Comentários 0

Entre na conversa

Faça login para deixar seu comentário neste artigo.

Ainda sem comentários

Seja o primeiro a comentar este artigo.