Os endpoints do projeto que estão retornando instâncias da classe Page do Spring Data estão disparando a seguinte mensagem de warning:
Serializing PageImpl instances as-is is not supported, meaning that there is no guarantee about the stability of the resulting JSON structure!
For a stable JSON structure, please use Spring Data's PagedModel (globally via @EnableSpringDataWebSupport(pageSerializationMode = VIA_DTO)) or Spring HATEOAS and Spring Data's PagedResourcesAssembler as documented in https://docs.spring.io/spring-data/commons/reference/repositories/core-extensions.html#core.web.pageables.
A partir do Spring Data 3.1 essa mensagem foi inserida para alertar e desencoragajar os desenvolvedores de continuarem renderizando, com a biblioteca Jackson, diretamente o Page com sua implementação PageImpl pois é um tipo de domínio da API e pode ser alterado por qualquer razão afetando sua representação em JSON e consequentemente quebrar aplicações clientes em uma atualização de versão do framework.
A atual versão possui a seguinte complexa estrutura:
{
"content": [
{
"id": 4,
"nome": "xpto",
"email": "xpto@xpto.com",
"cpf": "56778124040",
"telefone": "22222"
}
],
"pageable": {
"pageNumber": 0,
"pageSize": 1,
"sort": {
"empty": false,0
"sorted": true,
"unsorted": false
},
"offset": 0,
"paged": true,
"unpaged": false
},
"last": true,
"totalPages": 1,
"totalElements": 1,
"size": 1,
"number": 0,
"sort": {
"empty": false,
"sorted": true,
"unsorted": false
},
"numberOfElements": 1,
"first": true,
"empty": false
}
Essa estrutura já foi alterada em diversas ocasiões.
A documentação do Spring sugere a utilização do Spring HATEOAS, porém aponta duas soluções convenientes empregando somente o Spring Data para esse aviso:
I) Utilizar o org.springframework.data.web.PagedModel do Spring Data que encapsula o as instâncias de Page em uma representação simplificada da Spring HATEOAS, mas omitindo links de navegação.
Ex:
@GetMapping
public ResponseEntity<PagedModel<PacienteListagemDTO>> listar(@PageableDefault(sort = {"nome"}) Pageable pageable) {
PagedModel<PacienteListagemDTO> pacientesPage = new PagedModel<>((pacienteRepository.findAll(pageable)).map(PacienteListagemDTO::new));
return ResponseEntity.ok(pacientesPage);
}
Dessa forma a instância Page é embutida em uma PagedModel, e a estrutura do JSON possui um campo page expondo apenas os metadados essenciais para a paginação:
{
"content": [
{
"id": 4,
"nome": "xpto",
"email": "xpto@xpto.com",
"cpf": "56778124040",
"telefone": "22222"
}
],
"page": {
"size": 1,
"number": 0,
"totalElements": 1,
"totalPages": 1
}
}
II) Criar uma classe de configuração global que traduz PageImpl em PagedModel simplesmente habilitando o @EnableSpringDataWebSupport.
Ex:
package med.voll.api.webinfra;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.web.config.EnableSpringDataWebSupport;
@Configuration
@EnableSpringDataWebSupport(pageSerializationMode = EnableSpringDataWebSupport.PageSerializationMode.VIA_DTO)
public class JacksonConfiguration {
}
Dessa forma não é necessário qualquer intervenção sobre os controllers ficando o processo de tradução totalmente automático e transparente ao desenvolvedor.