Auxiliary Class no RAP
O problema: lógica repetida entre behavior pools
Seu BO cresceu. A entidade raiz tem um behavior pool, as filhas têm os seus, e espalhados por eles há uma validation que checa consistência de crédito, um determination que recalcula o mesmo total e uma action que precisa da mesmíssima verificação. Três lugares, uma regra — o instinto de qualquer desenvolvedor é fatorar isso numa classe comum e chamar de todos os pontos.
Aí você cria a ZCL_CREDIT_HELPER, um método estático, e tenta ler o buffer do BO lá de dentro:
METHOD check_credit.
" dentro de uma classe ABAP comum:
READ ENTITIES OF ZI_SalesOrder IN LOCAL MODE
ENTITY SalesOrder FIELDS ( CreditProfile ) WITH CORRESPONDING #( keys )
RESULT DATA(orders).
ENDMETHOD.E toma o erro: IN LOCAL MODE não é permitido fora de uma classe habilitada para o RAP BO. A adição IN LOCAL MODE — que pula verificações de feature/autorização ao acessar o próprio BO — é um direito privilegiado, e uma classe ABAP qualquer não o tem. A lógica pode até ser movida para lá se você passar tudo por parâmetro, mas no instante em que ela precisa tocar o buffer do BO, a classe comum trava.
É exatamente esse buraco que a ABP auxiliary class preenche.
O que é uma auxiliary class
Uma auxiliary class é uma classe global que você declara na BDEF e que passa a ter direitos de acesso privilegiados ao RAP BO — os mesmos direitos de um behavior pool. A definição da documentação é enxuta: são classes que fornecem métodos reutilizáveis para implementar comportamentos, permitindo terceirizar funcionalidade e simplificar o trabalho concorrente (times mexendo no mesmo BO sem colidir num único pool gigante). E o ponto central: elas oferecem direitos de acesso ampliados ao BO referenciado, o que significa que você pode usar IN LOCAL MODE e PRIVILEGED nas EML lá dentro.
Duas características técnicas que a doc crava:
São implicitamente
FINALe globais — e referenciam um RAP business object viaFOR BEHAVIOR OF.Só podem ser instanciadas ou invocadas pelo ambiente de runtime ABAP (a VM) — como os behavior pools, você não faz
NEWnelas a partir de código arbitrário.
Auxiliary class × behavior pool, em uma linha: o behavior pool é onde os métodos handler/saver vivem (é lá que FOR MODIFY, FOR VALIDATE, save etc. são implementados — e só lá). A auxiliary class é onde a lógica reutilizável mora, para os pools delegarem tarefas a ela. Handler e saver não podem ser implementados numa auxiliary class; mas podem chamá-la à vontade.
Como declarar e implementar
1. Registrar na BDEF
No header da behavior definition, após a implementação, você lista a(s) auxiliary class(es) com auxiliary class ... unique. Pode declarar uma ou várias, em lista separada por vírgula:
managed implementation in class zbp_i_salesorder unique;
auxiliary class zcl_salesorder_aux unique; // <- a auxiliary class
strict ( 2 );
define behavior for ZI_SalesOrder alias SalesOrder
persistent table zsalesorder
lock master
authorization master ( instance )
{
create;
update;
delete;
validation validateCredit on save { create; field CreditProfile; }
determination calcTotals on modify { create; }
action reevaluate result [1] $self;
}2. A classe global
A classe usa a adição FOR BEHAVIOR OF <bdef> — a mesma família do FOR BEHAVIOR OF do behavior pool. Ela nasce praticamente vazia; os métodos reutilizáveis são seus, com a assinatura que você quiser:
CLASS zcl_salesorder_aux DEFINITION
PUBLIC ABSTRACT FINAL
FOR BEHAVIOR OF ZI_SalesOrder.
PUBLIC SECTION.
" método reutilizável: recebe chaves, devolve os inválidos
CLASS-METHODS get_invalid_credit
IMPORTING keys TYPE TABLE FOR VALIDATION ZI_SalesOrder~validateCredit
RETURNING VALUE(result) TYPE tt_invalid_keys.
ENDCLASS.
CLASS zcl_salesorder_aux IMPLEMENTATION.
METHOD get_invalid_credit.
" IN LOCAL MODE funciona aqui
READ ENTITIES OF ZI_SalesOrder IN LOCAL MODE
ENTITY SalesOrder FIELDS ( CreditProfile SoldToParty )
WITH CORRESPONDING #( keys )
RESULT DATA(orders).
result = VALUE #( FOR o IN orders
WHERE ( CreditProfile IS INITIAL )
( %tky = o-%tky ) ).
ENDMETHOD.
ENDCLASS.3. Delegar do behavior pool
Agora os métodos handler — em qualquer pool do BO — chamam a auxiliary class em vez de repetir a lógica:
METHOD validateCredit. " no behavior pool
DATA(invalid) = zcl_salesorder_aux=>get_invalid_credit( keys ).
LOOP AT invalid INTO DATA(bad).
APPEND VALUE #( %tky = bad-%tky ) TO failed-salesorder.
APPEND VALUE #( %tky = bad-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'Perfil de crédito inválido' ) )
TO reported-salesorder.
ENDLOOP.
ENDMETHOD.
METHOD reevaluate. " outra operação, possivelmente outro pool
DATA(invalid) = zcl_salesorder_aux=>get_invalid_credit( CORRESPONDING #( keys ) ).
" ... reusa a MESMA lógica, sem duplicar uma linha
ENDMETHOD.Uma regra de verdade, um ponto de manutenção, chamada de quantos pools o BO tiver.
O superpoder e por que ele existe
O que separa a auxiliary class de um helper comum é a enhanced access rights. Dentro dela você pode:
IN LOCAL MODE— ler e modificar o BO pulando feature control e autorização, porque você é o provider chamando a si mesmo (e não um consumidor externo que precisa ser barrado).PRIVILEGED— acesso em modo privilegiado ao BO, útil em cenários de processamento interno onde os checks de instância atrapalhariam.
Esses dois são exatamente os direitos que um behavior pool tem e uma classe ABAP comum não tem. A auxiliary class é, no fundo, "um pedaço de behavior pool que pode ser reusado" — herda os privilégios do provider sem ser o lugar onde os handlers moram.
A recomendação explícita da SAP: não terceirize completamente as implementações de handler e saver para auxiliary classes — isso gera overhead desnecessário. A auxiliary class é para lógica reutilizável compartilhada, não para virar o "verdadeiro" pool com um pool-casca vazio na frente. Os handlers ficam no behavior pool; o que é comum a vários deles desce para a auxiliary class.
Um tipo que só existe aqui dentro
Vale conhecer um detalhe que reforça o parentesco com o behavior pool: certos BDEF derived types só podem ser usados dentro de classes de implementação e auxiliary classes — não fora delas. A lista inclui FOR CHANGE, FOR DETERMINATION, FOR VALIDATION, FOR ... FEATURES e FOR ... AUTHORIZATION. Foi por isso que, no exemplo acima, o parâmetro keys pôde ser tipado com TABLE FOR VALIDATION ZI_SalesOrder~validateCredit: esse tipo compila na auxiliary class. Numa classe comum, nem isso seria possível — mais uma confirmação de que a auxiliary class está "do lado de dentro" do BO.
Quando usar — e quando não
Situação | Auxiliary class? | Por quê |
|---|---|---|
Lógica que toca o buffer do BO e é usada em ≥2 operações/pools | Sim | Precisa dos direitos privilegiados + reuso — o caso canônico |
BO grande com vários devs trabalhando em paralelo | Sim | Fatiar o comportamento em pools + auxiliary reduz conflito de merge |
Lógica reutilizada, mas tudo cabe num único pool | Talvez | Um método privado no próprio pool já resolve — auxiliary só quando cruza pools |
Reuso dentro do mesmo BO, invisível para fora, sem tocar buffer | Considere internal action/function | Se a reutilização é uma operação do BO, o artefato pode ser uma internal action |
Lógica pura (cálculo, formatação) sem acessar o BO | Não | Classe utilitária comum basta — não desperdice o mecanismo |
Compartilhar lógica entre BOs diferentes | Não diretamente | Auxiliary é ligada a UM bdef; para cross-BO, veja cross-BO handling / classe comum com dados passados por parâmetro |
A régua: auxiliary class é para lógica que precisa dos privilégios do provider E é compartilhada entre pontos do mesmo BO. Faltou o "toca o buffer/privilégios"? Classe comum. Faltou o "compartilhada entre pools"? Método privado no pool. É uma ferramenta específica para uma dor específica.
Auxiliary class vs. as alternativas
Mecanismo | Direitos do BO? | Reuso | Onde brilha |
|---|---|---|---|
Auxiliary class | Sim (LOCAL MODE, PRIVILEGED) | Entre pools do mesmo BO | Helper privilegiado compartilhado |
Internal action/function | Sim (é operação do BO) | Via EML, dentro do BO | Quando o reuso É uma operação (passo do processo) |
Método privado no pool | Sim (está no pool) | Só dentro daquele pool | Reuso local, um pool só |
Classe utilitária comum | Não | Qualquer lugar | Lógica pura, sem tocar o BO |
Boas práticas consolidadas
Auxiliary para o compartilhado, pool para o handler. A divisão da própria doc: métodos handler/saver no pool; lógica comum a vários deles na auxiliary. Não inverta.
Não esvazie o pool. Pool-casca vazio + auxiliary fazendo tudo é o anti-pattern que a SAP alerta — overhead sem ganho.
Tipagem forte com os derived types. Aproveite que
TABLE FOR VALIDATION/DETERMINATION/CHANGEcompila aqui — assinaturas tipadas evitam conversões e erros.Métodos coesos, nome de negócio.
get_invalid_credit, nãohelper1. A auxiliary é biblioteca do BO; trate como API interna.PRIVILEGEDcom parcimônia. Pular checks é poder — use quando o cenário interno realmente exige, não por preguiça de tratar autorização.Uma auxiliary por preocupação, se fizer sentido. A BDEF aceita várias; um BO grande pode ter
..._aux_credit,..._aux_pricing— coesão acima de um baldão único.
Perguntas frequentes
Posso implementar uma validation ou action direto na auxiliary class?
Não. Métodos handler e saver (FOR VALIDATE, FOR MODIFY, save etc.) só podem ser implementados no behavior pool. A auxiliary class recebe a delegação desses métodos — o handler continua no pool e chama a auxiliary.
Preciso instanciar a auxiliary class com NEW?
Não — como os behavior pools, ela só é instanciada/invocada pelo runtime ABAP. Na prática, você chama métodos estáticos (ou o padrão que o time adotar), sem gerenciar o ciclo de vida do objeto.
Uma auxiliary class serve para vários BOs?
Ela é declarada com FOR BEHAVIOR OF apontando para um BDEF, então os direitos privilegiados valem para aquele BO. Para lógica genuinamente cross-BO, o caminho é uma classe comum recebendo os dados por parâmetro, ou os mecanismos de cross-BO transactional handling do RAP.
Qual a diferença para uma internal action?
Ambas reusam lógica com direitos do BO. A internal action é uma operação do BO (chamada via EML, aparece na BDEF como ação interna) — ideal quando o reuso é um passo do processo. A auxiliary class é um método de classe (chamada ABAP normal) — ideal quando o reuso é uma função utilitária privilegiada. Se você pensa "isto é uma etapa do meu BO", internal action; se pensa "isto é um helper que vários pontos usam", auxiliary class.
Auxiliary class tem a ver com o with friends das extensões?
São coisas diferentes com um tema comum (direitos de acesso). with friends dá a uma BDEF extension acesso irrestrito ao BO original que ela estende. A auxiliary class dá a uma classe sua os direitos do provider do seu próprio BO. Uma é sobre extensão de BO alheio; a outra, sobre organização do seu.
Isso funciona em managed e unmanaged?
Sim — o mecanismo é do BDEF, independente do tipo de implementação. Tanto o managed quanto o unmanaged podem declarar auxiliary classes e delegar a elas.
Conclusão
A auxiliary class resolve uma dor precisa: reusar, entre os vários behavior pools de um BO, lógica que precisa dos direitos privilegiados do provider — os mesmos IN LOCAL MODE e PRIVILEGED que uma classe comum não alcança. Declarada na BDEF com auxiliary class, definida com FOR BEHAVIOR OF, ela é o "pedaço reutilizável de behavior pool": não é onde os handlers moram, é onde o que eles compartilham descansa. Use quando a lógica cruza pools e toca o BO; para o resto, um método privado, uma internal action ou uma classe utilitária comum fazem o serviço. É organização de código com os privilégios certos — nada mais, e nada menos.
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.