Interface BaseCrudService<E,D,ID,FD extends GenericFilterDTO>
- Type Parameters:
E- tipo da entidadeD- tipo do DTOID- tipo do identificadorFD- tipo do DTO de filtro
- All Known Implementing Classes:
AbstractBaseCrudService,AbstractReadOnlyService
Esta interface define o boundary canônico entre controllers genericos e implementacoes de dominio.
Os controllers base assumem que conversoes entity -> DTO, resolucao de ordenacao padrao,
options e capacidades estatisticas sejam fornecidas neste nivel, e nao espalhadas em adapters
locais de frontend ou em controllers customizados.
Em projetos com JPA e associacoes LAZY, a forma suportada de manter esse boundary e herdar
de AbstractBaseCrudService, que aplica semantica transacional adequada aos fluxos usados
pelos controllers publicos da plataforma.
Capacidades cobertas
- CRUD e listagem com ordenacao padrao.
- Filtragem paginada e por cursor.
- Projecoes leves para
OptionDTO. - Option-sources e surfaces estatisticas canonicas.
-
Nested Class Summary
Nested ClassesModifier and TypeInterfaceDescriptionstatic final recordResultado de criacao que carrega simultaneamente o identificador persistido e o corpo projetado. -
Method Summary
Modifier and TypeMethodDescriptionbyIdsOptions(Collection<ID> ids) Busca entidades pelos IDs fornecidos e as projeta paraOptionDTO, preservando a ordem da coleção de entrada.byIdsOptionSourceOptions(String sourceKey, Collection<Object> ids) default StringcomputeOptionLabel(E entity) Tenta computar um label textual amigável para a entidade informada.default voiddeleteAllById(Iterable<ID> ids) Exclui todos os registros correspondentes aos IDs fornecidos.default voiddeleteById(ID id) Exclui uma entidade pelo identificador (ignora quando inexistente).default DistributionStatsResponsedistributionStats(DistributionStatsRequest<FD> request) Executes a canonical distribution aggregate over the filtered dataset.default IDdefault org.springframework.data.domain.Page<E> 🔍 Filtro Avançado com Ordenação Padrão Inteligentedefault CursorPage<E> filterByCursor(FD filter, org.springframework.data.domain.Sort sort, String after, String before, int size) Executa o filtro utilizando paginação por cursor.default <R> CursorPage<R> filterByCursorMapped(FD filter, org.springframework.data.domain.Sort sort, String after, String before, int size, Function<E, R> mapper) Executa o filtro por cursor e projeta o conteúdo dentro do contexto do service.default <R> org.springframework.data.domain.Page<R> filterMappedWithIncludeIds(FD filter, org.springframework.data.domain.Pageable pageable, Collection<ID> includeIds, Function<E, R> mapper) Executa filtro com inclusão opcional de IDs e projeta o conteúdo dentro do contexto do service.filterOptions(FD filter, org.springframework.data.domain.Pageable pageable) Executa o filtro padrão e projeta cada entidade paraOptionDTOusando oOptionMapperconfigurado.filterOptionSourceOptions(String sourceKey, FD filter, String search, org.springframework.data.domain.Pageable pageable, Collection<Object> includeIds) default org.springframework.data.domain.Page<E> filterWithIncludeIds(FD filter, org.springframework.data.domain.Pageable pageable, Collection<ID> includeIds) Aplica o filtro informado e injeta entidades adicionais no topo da primeira página.findAll()📋 Lista Todas as Entidades com Ordenação Padrãodefault org.springframework.data.domain.Page<E> findAll(org.springframework.data.domain.Pageable pageable) 📄 Paginação com Ordenação Padrão InteligentefindAllById(Collection<ID> ids) Recupera múltiplas entidades pelos seus identificadores.default <R> List<R> findAllByIdMapped(Collection<ID> ids, Function<E, R> mapper) Recupera múltiplas entidades pelos seus identificadores e projeta o resultado dentro do contexto do service.default <R> List<R> findAllMapped(Function<E, R> mapper) Lista todas as entidades e projeta o resultado dentro do contexto do service.default ERecupera uma entidade pelo identificador.default <R> RfindByIdMapped(ID id, Function<E, R> mapper) Recupera uma entidade pelo identificador e projeta o resultado dentro do contexto do service.Retorna uma string representando a versão atual do dataset.default org.springframework.data.domain.Sort📊 Constrói Ordenação Padrão Baseada em Anotações @DefaultSortColumndefault StatsSupportModeInforma se o recurso suporta a superficie canonica dedistribution stats.default StatsSupportModeInforma se o recurso suporta a superficie canonica degroup-by stats.default jakarta.persistence.EntityNotFoundExceptiondefault OptionMapper<E, ID> Retorna umOptionMapperpadrão que projeta entidades paraOptionDTO.default OptionSourceRegistryRetorna o registro de option-sources disponiveis para a entidade do recurso.default StatsFieldRegistryRetorna o registro canonico de campos elegiveis para stats.default StatsSupportModeInforma se o recurso suporta a superficie canonica detime-series stats.default GroupByStatsResponsegroupByStats(GroupByStatsRequest<FD> request) Executes a canonical group-by aggregate over the filtered dataset.default booleanhasOptionSource(String sourceKey) Verifica se existe uma option-source registrada para a entidade do recurso.default OptionalLongLocaliza a posição absoluta de um registro considerando um filtro e ordenação.default EmergeUpdate(E existing, E update) Permite combinar o estado atual com o payload de atualizacao antes da persistencia.default OptionSourceDescriptorresolveOptionSource(String sourceKey) Resolve o descritor de uma option-source registrada para a entidade do recurso.default EPersiste uma nova entidade.default <R> RsaveMapped(E entity, Function<E, R> mapper) Persiste uma entidade e projeta o resultado dentro do contexto do service.default <R> BaseCrudService.SavedResult<ID, R> saveResultMapped(E entity, Function<E, R> mapper) Persiste uma entidade e retorna, no mesmo boundary do service, o ID persistido e a projeção correspondente.default TimeSeriesStatsResponsetimeSeriesStats(TimeSeriesStatsRequest<FD> request) Executes a canonical time-series aggregate over the filtered dataset.default EAtualiza uma entidade existente.default <R> RupdateMapped(ID id, E entity, Function<E, R> mapper) Atualiza uma entidade e projeta o resultado dentro do contexto do service.
-
Method Details
-
getRepository
BaseCrudRepository<E,ID> getRepository() -
getSpecificationsBuilder
GenericSpecificationsBuilder<E> getSpecificationsBuilder() -
getEntityClass
-
getOptionMapper
Retorna umOptionMapperpadrão que projeta entidades paraOptionDTO.Implementações podem sobrescrever para customizar o mapeamento. Quando não sobrescrito, o mapper padrão usa
extractId(Object)para o id ecomputeOptionLabel(Object)para o label. O campoextrapermanecenullpara manter o payload leve.Observação de performance: a computação do label utiliza reflexão apenas durante a projeção de opções (endpoints de options). Anotar a propriedade com
@OptionLabelevita a varredura por heurísticas. -
getDatasetVersion
Retorna uma string representando a versão atual do dataset.Implementações podem sobrescrever este método para expor um valor que permita ao cliente invalidar caches quando os dados mudarem. Em cenários corporativos, uma implementação típica calcula um hash ou timestamp a partir da coluna
updatedAtpara que o frontend possa detectar mudanças sem precisar refazer consultas pesadas.// Exemplo de implementação @Override public Optional<String> getDatasetVersion() { return repository.maxUpdatedAt().map(Instant::toString); }- Returns:
- versão do dataset, quando disponível
-
getGroupByStatsSupportMode
Informa se o recurso suporta a superficie canonica degroup-by stats.- Returns:
- modo de suporte; por padrao
StatsSupportMode.DISABLED
-
getTimeSeriesStatsSupportMode
Informa se o recurso suporta a superficie canonica detime-series stats.- Returns:
- modo de suporte; por padrao
StatsSupportMode.DISABLED
-
getDistributionStatsSupportMode
Informa se o recurso suporta a superficie canonica dedistribution stats.- Returns:
- modo de suporte; por padrao
StatsSupportMode.DISABLED
-
getStatsFieldRegistry
Retorna o registro canonico de campos elegiveis para stats.- Returns:
- registro de campos suportados pelo recurso
-
getOptionSourceRegistry
Retorna o registro de option-sources disponiveis para a entidade do recurso.- Returns:
- registro de fontes derivadas; por padrao vazio
-
hasOptionSource
Verifica se existe uma option-source registrada para a entidade do recurso.- Parameters:
sourceKey- chave da fonte derivada- Returns:
truequando a fonte existe para a entidade atual
-
resolveOptionSource
Resolve o descritor de uma option-source registrada para a entidade do recurso.- Parameters:
sourceKey- chave da fonte derivada- Returns:
- descritor canonico da fonte
- Throws:
UnknownOptionSourceException- quando a chave nao estiver registrada
-
findByIdMapped
Recupera uma entidade pelo identificador e projeta o resultado dentro do contexto do service.- Type Parameters:
R- tipo projetado- Parameters:
id- identificador da entidademapper- função de projeção- Returns:
- resultado projetado
-
findAll
📋 Lista Todas as Entidades com Ordenação Padrão
Retorna todos os registros da entidade aplicando automaticamente a ordenação definida via anotações
DefaultSortColumn.🔄 Comportamento:
- Aplica
getDefaultSort()automaticamente - Se nenhum @DefaultSortColumn definido, retorna sem ordenação específica
- Ideal para listagens completas onde ordem consistente é importante
📋 Exemplo de Uso:
// No Service: List<Funcionario> funcionarios = findAll(); // SQL gerado (se @DefaultSortColumn(priority=1) em 'nome'): SELECT * FROM funcionarios ORDER BY nome ASC- Returns:
- Lista de todas as entidades ordenadas conforme @DefaultSortColumn
- See Also:
- Aplica
-
findAllMapped
Lista todas as entidades e projeta o resultado dentro do contexto do service.- Type Parameters:
R- tipo projetado- Parameters:
mapper- função de projeção- Returns:
- lista projetada
-
findById
Recupera uma entidade pelo identificador.- Parameters:
id- identificador da entidade- Returns:
- entidade encontrada
- Throws:
jakarta.persistence.EntityNotFoundException- quando não encontrada
-
findAllById
Recupera múltiplas entidades pelos seus identificadores.Retorna uma lista vazia quando a coleção de IDs é
nullou vazia, evitando consultas desnecessárias ao banco de dados.- Parameters:
ids- coleção de identificadores a serem buscados- Returns:
- lista de entidades correspondentes aos IDs fornecidos
-
findAllByIdMapped
Recupera múltiplas entidades pelos seus identificadores e projeta o resultado dentro do contexto do service.- Type Parameters:
R- tipo projetado- Parameters:
ids- coleção de identificadoresmapper- função de projeção- Returns:
- lista projetada
-
extractId
-
save
Persiste uma nova entidade.- Parameters:
entity- instância a ser salva- Returns:
- entidade salva (com ID)
-
saveMapped
Persiste uma entidade e projeta o resultado dentro do contexto do service.- Type Parameters:
R- tipo projetado- Parameters:
entity- instância a ser salvamapper- função de projeção- Returns:
- resultado projetado
-
saveResultMapped
Persiste uma entidade e retorna, no mesmo boundary do service, o ID persistido e a projeção correspondente.- Type Parameters:
R- tipo projetado- Parameters:
entity- instância a ser salvamapper- função de projeção- Returns:
- resultado contendo o ID persistido e o corpo projetado
-
mergeUpdate
Permite combinar o estado atual com o payload de atualizacao antes da persistencia.O comportamento padrao devolve
existing, mas implementacoes podem sobrescrever para copiar campos mutaveis, preservar relacionamentos ou aplicar regras de merge de dominio.- Parameters:
existing- entidade atual carregada do repositórioupdate- entidade derivada do DTO de entrada- Returns:
- entidade efetivamente usada no fluxo de update
-
computeOptionLabel
Tenta computar um label textual amigável para a entidade informada.Estratégia de resolução:
- Se existir método ou campo anotado com uma anotação chamada
OptionLabel(qualquer pacote), usa seu valor convertido para String. Métodos são verificados antes de campos. Suporta herança. - Caso contrário, tenta invocar (case-insensitive, na ordem) os getters
getLabel,getNomeCompleto,getNome,getDescricao,getTitle. - Se nada encontrado ou valor nulo/vazio, faz fallback para
String.valueOf(id).
- Se existir método ou campo anotado com uma anotação chamada
-
update
Atualiza uma entidade existente.- Parameters:
id- identificador da entidade a atualizarentity- dados a serem mesclados e persistidos- Returns:
- entidade atualizada
- Throws:
jakarta.persistence.EntityNotFoundException- quando a entidade não existe
-
updateMapped
Atualiza uma entidade e projeta o resultado dentro do contexto do service.- Type Parameters:
R- tipo projetado- Parameters:
id- identificador da entidade a atualizarentity- dados a serem mesclados e persistidosmapper- função de projeção- Returns:
- resultado projetado
-
deleteById
Exclui uma entidade pelo identificador (ignora quando inexistente).- Parameters:
id- identificador da entidade a excluir
-
deleteAllById
Exclui todos os registros correspondentes aos IDs fornecidos.- Parameters:
ids- Coleção de identificadores a serem removidos
-
findAll
default org.springframework.data.domain.Page<E> findAll(org.springframework.data.domain.Pageable pageable) 📄 Paginação com Ordenação Padrão Inteligente
Retorna uma página de entidades aplicando ordenação padrão automaticamente quando nenhuma ordenação é especificada no
Pageable.🧠 Lógica Inteligente:
- Se Pageable tem ordenação: Usa a ordenação especificada
- Se Pageable sem ordenação: Aplica
getDefaultSort()automaticamente - Se sem @DefaultSortColumn: Usa ordenação do banco (pode ser imprevisível)
📋 Exemplos de Comportamento:
// Caso 1: Com ordenação especificada Pageable pageable = PageRequest.of(0, 10, Sort.by("salario").descending()); Page<Funcionario> page = findAll(pageable); // → SQL: ... ORDER BY salario DESC LIMIT 10 // Caso 2: Sem ordenação (aplica @DefaultSortColumn automaticamente) Pageable pageable = PageRequest.of(0, 10); Page<Funcionario> page = findAll(pageable); // → SQL: ... ORDER BY nome ASC LIMIT 10 (se @DefaultSortColumn no campo nome)🔗 Uso em Controllers:
// O controller genérico delega a projeção ao service: @GetMapping("/all") public ResponseEntity<List<FuncionarioDTO>> getAll() { return ResponseEntity.ok(service.findAllMapped(this::toDto)); } // URLs suportadas: GET /api/funcionarios/all?page=0&size=10 // Usa @DefaultSortColumn GET /api/funcionarios/all?page=0&size=10&sort=nome,asc // Usa ordenação específica GET /api/funcionarios/all?page=0&size=10&sort=salario,desc // Usa ordenação específica- Parameters:
pageable- Parâmetros de paginação e ordenação opcional- Returns:
- Página de entidades com ordenação aplicada
- See Also:
-
filter
default org.springframework.data.domain.Page<E> filter(FD filterDTO, org.springframework.data.domain.Pageable pageable) 🔍 Filtro Avançado com Ordenação Padrão Inteligente
Aplica filtros dinâmicos baseados em DTO de filtro e paginação, com ordenação padrão aplicada automaticamente quando não especificada.
🔄 Fluxo de Processamento:
- Ordenação: Aplica
getDefaultSort()se Pageable sem ordenação - Filtros: Constrói JPA Specification baseada no FilterDTO
- Consulta: Executa query otimizada com filtros + paginação + ordenação
📋 Exemplo de Uso Completo:
// Entidade com ordenação padrão: @Entity public class Funcionario { @DefaultSortColumn(priority = 1) private String departamento; @DefaultSortColumn(priority = 2) private String nome; } // DTO de filtro: public class FuncionarioFilterDTO extends GenericFilterDTO { @Filterable(operation = CONTAINS) private String nome; @Filterable(operation = EQUALS) private String departamento; } // No Controller: @PostMapping("/filter") public Page<FuncionarioDTO> filter(@RequestBody FuncionarioFilterDTO filterDTO, Pageable pageable) { return service.filterMappedWithIncludeIds(filterDTO, pageable, null, this::toDto); }🌐 Exemplos de Requisições:
POST /api/funcionarios/filter?page=0&size=10 Body: {"nome": "João", "departamento": "TI"} → SQL: SELECT * FROM funcionarios WHERE nome LIKE '%João%' AND departamento = 'TI' ORDER BY departamento ASC, nome ASC -- @DefaultSortColumn aplicada LIMIT 10 POST /api/funcionarios/filter?page=0&size=10&sort=salario,desc Body: {"nome": "Maria"} → SQL: SELECT * FROM funcionarios WHERE nome LIKE '%Maria%' ORDER BY salario DESC -- ordenação específica sobrescreve @DefaultSortColumn LIMIT 10🎯 Benefícios:
- Flexibilidade: Combina filtros dinâmicos com ordenação inteligente
- Performance: Queries otimizadas com índices corretos
- UX Consistente: Resultados sempre organizados de forma lógica
- Zero Config: Funciona automaticamente sem código extra
- Parameters:
filterDTO- DTO com critérios de filtro anotados com @Filterablepageable- Parâmetros de paginação e ordenação opcional- Returns:
- Página filtrada de entidades com ordenação aplicada
- See Also:
- Ordenação: Aplica
-
filterWithIncludeIds
default org.springframework.data.domain.Page<E> filterWithIncludeIds(FD filter, org.springframework.data.domain.Pageable pageable, Collection<ID> includeIds) Aplica o filtro informado e injeta entidades adicionais no topo da primeira página.Os IDs fornecidos em
includeIdssão removidos da página retornada para evitar duplicação. Quando a página solicitada for a primeira (page = 0), entidades ausentes são buscadas viafindAllById(Collection)e inseridas no topo na mesma ordem dos IDs fornecidos. Nas páginas subsequentes apenas a remoção de duplicados é realizada, evitando que itens sejam reexibidos em múltiplas páginas.- Parameters:
filter- critérios de filtropageable- informações de paginaçãoincludeIds- IDs que devem aparecer no topo da primeira página- Returns:
- página resultante com injeção opcional de entidades
-
filterMappedWithIncludeIds
default <R> org.springframework.data.domain.Page<R> filterMappedWithIncludeIds(FD filter, org.springframework.data.domain.Pageable pageable, Collection<ID> includeIds, Function<E, R> mapper) Executa filtro com inclusão opcional de IDs e projeta o conteúdo dentro do contexto do service.- Type Parameters:
R- tipo projetado- Parameters:
filter- critérios de filtropageable- informações de paginaçãoincludeIds- IDs que devem aparecer no topo da primeira páginamapper- função de projeção- Returns:
- página resultante projetada
-
filterByCursor
default CursorPage<E> filterByCursor(FD filter, org.springframework.data.domain.Sort sort, String after, String before, int size) Executa o filtro utilizando paginação por cursor.Implementações devem aplicar uma ordenação estável e retornar os cursores codificados para navegação. O método padrão lança
UnsupportedOperationExceptionindicando que a entidade ainda não suporta paginação por cursor.- Parameters:
filter- critérios de filtrosort- ordenação estável a ser aplicadaafter- cursor para avançar na listabefore- cursor para retroceder na listasize- quantidade de registros a recuperar- Returns:
- página baseada em cursor
- Throws:
UnsupportedOperationException- caso não seja implementado
-
filterByCursorMapped
default <R> CursorPage<R> filterByCursorMapped(FD filter, org.springframework.data.domain.Sort sort, String after, String before, int size, Function<E, R> mapper) Executa o filtro por cursor e projeta o conteúdo dentro do contexto do service.- Type Parameters:
R- tipo projetado- Parameters:
filter- critérios de filtrosort- ordenação aplicadaafter- cursor para avançarbefore- cursor para retrocedersize- tamanho da páginamapper- função de projeção- Returns:
- página por cursor projetada
-
groupByStats
Executes a canonical group-by aggregate over the filtered dataset.- Parameters:
request- stats request- Returns:
- group-by stats response
- Throws:
UnsupportedOperationException- when the resource does not support stats
-
timeSeriesStats
Executes a canonical time-series aggregate over the filtered dataset.- Parameters:
request- stats request- Returns:
- time-series stats response
- Throws:
UnsupportedOperationException- when the resource does not support stats
-
distributionStats
Executes a canonical distribution aggregate over the filtered dataset.- Parameters:
request- stats request- Returns:
- distribution stats response
- Throws:
UnsupportedOperationException- when the resource does not support stats
-
locate
Localiza a posição absoluta de um registro considerando um filtro e ordenação.Implementações devem retornar o índice zero-based do registro dentro do conjunto filtrado. O método padrão retorna
OptionalLong.empty(), indicando que a entidade não suporta a operação.- Parameters:
filter- critérios de filtrosort- ordenação aplicadaid- identificador do registro- Returns:
- posição absoluta quando suportado
-
filterOptions
default org.springframework.data.domain.Page<OptionDTO<ID>> filterOptions(FD filter, org.springframework.data.domain.Pageable pageable) Executa o filtro padrão e projeta cada entidade paraOptionDTOusando oOptionMapperconfigurado.Em cenários com JPA e carregamento lazy, a expectativa é que a implementação concreta seja provida por
AbstractBaseCrudService, para que a resolução do label ocorra dentro de transação.- Parameters:
filter- critérios de filtropageable- informações de paginação- Returns:
- página de opções reduzidas
-
byIdsOptions
Busca entidades pelos IDs fornecidos e as projeta paraOptionDTO, preservando a ordem da coleção de entrada.Em cenários com JPA e carregamento lazy, a expectativa é que a implementação concreta seja provida por
AbstractBaseCrudService, para que a resolução do label ocorra dentro de transação.- Parameters:
ids- identificadores a serem buscados- Returns:
- lista de opções na ordem solicitada
-
filterOptionSourceOptions
-
byIdsOptionSourceOptions
-
getDefaultSort
default org.springframework.data.domain.Sort getDefaultSort()📊 Constrói Ordenação Padrão Baseada em Anotações @DefaultSortColumn
Escaneia a classe da entidade em busca de campos anotados com
DefaultSortColumne constrói automaticamente um objetoSortpara uso em consultas JPA.🔄 Algoritmo de Processamento:
- Escaneamento: Percorre todos os campos da entidade (incluindo herança)
- Filtragem: Identifica campos com @DefaultSortColumn
- Ordenação: Ordena por prioridade (menor valor = maior prioridade)
- Construção: Monta Sort.Order para cada campo
📋 Exemplo de Uso:
// Na entidade: @Entity public class Produto { @DefaultSortColumn(priority = 1, ascending = false) private LocalDateTime dataLancamento; @DefaultSortColumn(priority = 2, ascending = true) private String nome; } // Resultado deste método: Sort.by( Sort.Order.desc("dataLancamento"), // prioridade 1 Sort.Order.asc("nome") // prioridade 2 ) // SQL gerado: ORDER BY dataLancamento DESC, nome ASC⚡ Performance:
- Reflection Cache: Fields são cached pelo JVM
- Lazy Execution: Só executa quando ordenação não especificada
- Single Scan: Uma única varredura por classe
🔗 Aplicação Automática:
Este método é chamado automaticamente por:
findAll()- Lista simplesfindAll(Pageable)- Quando Pageable.sort não está definidofilter(GenericFilterDTO, Pageable)- Quando Pageable.sort não está definido
- Returns:
Sortbaseado nos campos @DefaultSortColumn ouSort.unsorted()se nenhum campo anotado- See Also:
-
getNotFoundException
default jakarta.persistence.EntityNotFoundException getNotFoundException()
-