Cria, revisa e padroniza interceptadores de busca Sankhya com `@BeforeLoadListener` (interface `FinderListener` + método `beforeExecute`) — injeta filtros/critérios dinâmicos no Finder JAPE antes da query chegar ao banco. Use ao criar, alterar, revisar, auditar ou padronizar interceptação de buscas/carregamento de entidades, ao implementar `beforeExecute`, ao aplicar filtro de segurança/multi-tenant transversal a uma entidade, ao trabalhar com classes `*FinderListener`, ou ao tocar em código com `@BeforeLoadListener`/`FinderListener`. NÃO usar para reagir a gravação/exclusão (eventos CRUD insert/update/delete, `PersistenceEventAdapter`) — isso é `@Listener`, skill `listener`.
Installation
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Cria, revisa e padroniza interceptadores de busca Sankhya com `@BeforeLoadListener` (interface `FinderListener` + método `beforeExecute`) — injeta filtros/critérios dinâmicos no Finder JAPE antes da query chegar ao banco. Use ao criar, alterar, revisar, auditar ou padronizar interceptação de buscas/carregamento de entidades, ao implementar `beforeExecute`, ao aplicar filtro de segurança/multi-tenant transversal a uma entidade, ao trabalhar com classes `*FinderListener`, ou ao tocar em código com `@BeforeLoadListener`/`FinderListener`. NÃO usar para reagir a gravação/exclusão (eventos CRUD insert/update/delete, `PersistenceEventAdapter`) — isso é `@Listener`, skill `listener`.
Interceptador de Buscas (@BeforeLoadListener) — Addon Studio 2.0
@BeforeLoadListener executa lógica personalizada sempre que uma entidade é carregada ou pesquisada via JAPE. Intercepta a execução do Finder — permite adicionar filtros, ordenações ou validar parâmetros de busca antes da query chegar ao banco. A anotação automatiza o atributo finder-listener no XML da entidade — sem edição manual de XML.
⚠️ @BeforeLoadListener ≠ @Listener. São mecanismos distintos: @BeforeLoadListener intercepta leitura (busca/carregamento, via FinderListener) e só funciona em instâncias do próprio add-on; @Listener reage a escrita (insert/update/delete, via PersistenceEventAdapter) e aceita também instâncias nativas. Tarefa de gravação/exclusão → skill listener.
1. Quando usar — @BeforeLoadListener vs @Criteria vs @Listener vs @BusinessRule
Mecanismo
Escopo
Quando usar
@BeforeLoadListener
Toda busca/carregamento de UMA entidade (transversal)
Filtro transversal aplicado a toda leitura da entidade, independente de quem consulta (segurança, multi-tenant, soft-delete).
@Criteria (repository)
Uma query específica
Filtro pontual em um método de busca declarado no repository.
@Listener
CRUD (insert/update/delete) de qualquer entidade
Validar/modificar campos ao gravar/excluir.
@BusinessRule
Confirmação/faturamento de notas (saída, mov. interna)
Regras transacionais comerciais com barramento de regras.
Regra rápida: filtro que precisa valer em todas as buscas da entidade (sem depender de quem chamou)? @BeforeLoadListener. Filtro de uma consulta só? @Criteria no repository.
2. Pré-requisito fundamental
A entidade precisa estar declarada no Dicionário de Dados — de uma das duas formas:
Arquivo XML de entidade (ex.: Produto.xml em datadictionary/) — skill data-dictionary.
Anotação @JapeEntity na classe de modelo — skill entity.
Sem declaração por nenhum desses meios, o SDK não tem onde injetar a configuração do listener.
Restrição de instâncias — só as do próprio add-on
@BeforeLoadListener só pode interceptar instâncias criadas pelo próprio add-on. NÃO é permitido em instâncias nativas do sistema (ex.: Parceiro, Produto nativo, CabecalhoNota, etc.).
3. Anatomia
import br.com.sankhya.jape.core.FinderListener;
import br.com.sankhya.jape.metadata.EntityMetaData;
import br.com.sankhya.jape.util.FinderWrapper;
import br.com.sankhya.studio.persistence.BeforeLoadListener;
import lombok.extern.java.Log;
@Log@BeforeLoadListener(instance = "MinhaInstancia")publicclassMinhaInstanciaFinderListenerimplementsFinderListener {
@OverridepublicvoidbeforeExecute(EntityMetaData entity, FinderWrapper finder)throws Exception {
// Adiciona um criterio de busca — setWhere SUBSTITUI a clausula inteira,// por isso compomos com o filtro ja existente via getWhere()Stringwhere= finder.getWhere();
finder.setWhere(where == null || where.isEmpty()
? "this.ATIVO = 'S'"
: where + " AND this.ATIVO = 'S'");
log.info("Filtro de seguranca aplicado para a entidade: " + entity.getName());
}
}
Atenção:setWhere(String)substitui a cláusula WHERE por completo. Para adicionar um critério sem descartar o filtro que já veio na consulta, sempre componha com getWhere() + " AND ...", como acima.
4. Atributo da anotação @BeforeLoadListener
Atributo
Obrigatório
Descrição
instance
Sim
Nome da instância (entidade) a interceptar — o mesmo valor de @JapeEntity(entity = "...") ou de <instance name="..."> no XML do dicionário. Não é o nome da tabela.
Gotcha:instance é o nome lógico da entidade, não a tabela. Para @JapeEntity(entity = "CabecalhoNota", table = "TGFCAB"), usa-se @BeforeLoadListener(instance = "CabecalhoNota").
Metadados da entidade interceptada (entity.getName(), etc.).
finder
br.com.sankhya.jape.util.FinderWrapper
Builder da consulta — compor critérios via finder.getWhere()/finder.setWhere(...).
Método declara throws Exception — exceção lançada bloqueia a busca e propaga ao chamador.
finder.setWhere(String clause)substitui a cláusula WHERE inteira — para adicionar critério, componha com finder.getWhere() + " AND ...". Prefixo this. obrigatório em todo campo da clause (mesma convenção do @Criteria — ver repository).
6. Filtros dinâmicos por contexto do usuário
Use o finder para critérios baseados no usuário logado:
Para SQL portável (Oracle/MSSQL) na clause — datas, nullValue, ignorecase, etc. — use macros Sankhya em vez de sintaxe específica de banco (SYSDATE, NVL, ||). Ver skill macros.
7. Injeção de dependência
Assim como o @Listener de persistência, @BeforeLoadListenersuporta @Inject (Guice). Delegue lógica de leitura de contexto/config a um service ou repository injetado via construtor:
Entidade-alvo declarada no dicionário (XML ou @JapeEntity) e é instância do próprio add-on.
Classe implementa br.com.sankhya.jape.core.FinderListener.
Anotada com @BeforeLoadListener(instance = "<NomeDaInstancia>") — nome = @JapeEntity(entity = "...") (ou <instance name="..."> no XML), não a tabela.
Apenas um@BeforeLoadListener para a instância em todo o projeto.
beforeExecute compõe critérios via getWhere() + " AND " + setWhere(...) (nunca setWhere seco — substitui o filtro existente), com prefixo this. nos campos.
Macros portáveis no lugar de SQL específico de banco.
Método leve — sem consultas pesadas (roda em toda busca).
Dependências (service/repository) via @Inject construtor (Guice), se necessárias.
@Log Lombok para logging (java.util.logging).
Filtros dinâmicos por usuário via JapeSession.getContext().getUserID().
Skills relacionadas
entity — entidade-alvo precisa estar declarada via @JapeEntity
data-dictionary — declaração XML; atributo finder-listener automatizado pela anotação
repository — sintaxe this.CAMPO da clause (igual ao @Criteria); alternativa por-query ao filtro transversal
macros — SQL portável Oracle/MSSQL na clause do finder.setWhere(...)
listener — @Listener (eventos CRUD de persistência — escopo distinto: gravação, não busca)