Biblioteca XCO no ABAP Cloud: o que ela faz e como facilita o dia a dia
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 dossy-.Chaves:
xco_cp=>uuid( )->valuegera 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_jsonmonta/lê JSON exco_cp=>string( )->as_xstring( ... )gera hash SHA.Arquivos e log:
xco_cp_xlsxlê/gera Excel;xco_cp_balescreve 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) |
| Operar conteúdo binário — base64, conversão de/para string, concatenação. |
Mensagens |
| Montar mensagens (a leitura da atual já vem de |
Contexto / Tenant |
| System ID, GUID, global/subaccount e URLs do tenant — sem |
Call stack |
| Inspecionar e formatar a pilha de chamadas de quem invocou a sua lógica. |
Application Log |
| 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 |
|
|
Data / hora |
|
|
Gerar UUID |
|
|
Quebrar/juntar texto |
|
|
Regex |
|
|
Montar JSON |
|
|
Ler/gerar Excel |
|
|
Hash SHA-256 |
|
|
Application Log |
|
|
Sistema / 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
Comentários 0
Ainda sem comentários
Seja o primeiro a comentar este artigo.
Entre na conversa
Faça login para deixar seu comentário neste artigo.