Guia de Atualização para o Spring Boot 3.0 com Spring Data JPA e Querydsl

No ano passado, escrevi dois artigos sobre JPA Criteria e Querydsl (veja os artigos Introdução e Metamodel). Desde o final do ano passado, houve um novo lançamento principal do Spring Boot 3. Este lançamento é baseado no Spring Framework 6 com várias mudanças significativas e questões que devemos considerar ao atualizar.

O objetivo deste artigo é destacar essas mudanças ao atualizar o projeto sat-jpa (Projeto SAT). As tecnologias utilizadas aqui são:

  1. Spring Boot 3.0.2,
  2. Hibernate 6.1.6.Final
  3. Spring Data JPA 3.0.1 e
  4. Querydsl 5.0.0.

Spring Framework 6.0.4

O Spring Framework 6 tem muitas mudanças (veja O que há de novo no Spring Framework 6.x), as principais mudanças são:

  1. Mudar a base do Java para o Java 17 (ainda a última versão LTS do Java no momento de escrever este artigo) — ou seja, é a versão mínima do Java que temos que usar.
  2. Mudar a base do Jakarta para Jakarta EE 9+.

Além disso, há apenas uma pequena mudança no Spring MVC usado no projeto SAT.

Spring MVC 6.0.4

Todos os métodos na classe ResponseEntityExceptionHandler mudaram suas assinaturas. O argumento status foi alterado do tipo HttpStatus para o tipo HttpStatusCode (veja a mudança na classe CityExceptionHandler).

HttpStatus no Spring MVC 5

Java

 

@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException exception,
		HttpHeaders headers, HttpStatus status, WebRequest request) {
	return buildResponse(BAD_REQUEST, exception);
}

HttpStatusCode no Spring MVC 6

Java

 

@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException exception, 
        HttpHeaders headers, HttpStatusCode status, WebRequest request) {
	return buildResponse(BAD_REQUEST, exception);
}

Spring Boot 3.0.2

O Spring Boot 3 apresenta muitas mudanças (veja Notas de Lançamento do Spring Boot 3.0); as mais importantes são estas:

  • Java 17 (definido pelo Spring Framework).
  • Atualização para o Spring Framework 6 (veja acima).
  • Atualize para Hibernate 6 (veja abaixo).
  • Migração das dependências JavaEE para Jakarta EE — não é importante em nosso caso, pois não dependemos do Java enterprise aqui, mas pode afetar muitas dependências (por exemplo, API de servlet, validação, persistência, JMS, etc.).
  • Pequena mudança no Spring MVC 6 na classe ResponseEntityExceptionHandler (veja a próxima parte).

Vamos começar com as mudanças simples do Jakarta EE. Assim, podemos nos concentrar na persistência depois disso.

Dependências do Jakarta EE

A mudança significativa é a migração das dependências Java EE para Jakarta EE. O Spring Framework 6 estabeleceu a base como Jakarta EE 9 (veja O que há de novo no Spring Framework 6.x), mas o Spring Boot 3 já usa Jakarta EE 10 (veja Notas de Lançamento do Spring Boot 3.0) para muitas APIs (por exemplo, Servlet ou JPA — para citar algumas tecnologias).

Como consequência, todas as classes que utilizam outra classe do pacote jakarta precisam trocar para a mesma classe do pacote javax (veja, por exemplo, as anotações PostConstruct ou Entity).

Importações Javax

Java

 

import javax.annotation.PostConstruct;
import javax.persistence.Entity;

Importações Jakarta

Java

 

import jakarta.annotation.PostConstruct;
import jakarta.persistence.Entity;

Hibernate 6.1.6

Outra mudança importante no Spring Boot 3 é a atualização de Hibernate 5.6 para Hibernate 6.1. Os detalhes sobre o Hibernate 6.1 podem ser encontrados aqui ou nos notas de lançamento.

Sinceramente, não prestei atenção a essa mudança até ter que corrigir um teste falhando devido a uma quantidade diferente de resultados (veja a correção no classe CountryRepositoryCustomTests). A implementação com o novo Hibernate 6 retorna menos entidades do que antes.

Vale a pena mencionar duas mudanças aqui baseadas nessa investigação. Vamos começar com o registro em log primeiro.

Registro

Os logger do Hibernate foram alterados de org.hibernate.type para org.hibernate.orm.jdbc (veja esta referência e esta referência).

Nota: todos os itens de configuração disponíveis podem ser encontrados no classe org.hibernate.cfg.AvailableSettings.

Hibernate 5

Havia um único logger para os valores ocultos e extraídos.

Properties files

 

logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

Hibernate 6

O Hibernate 6 alterou o pacote principal e dividiu-os em dois logger diferentes a fim de distinguir a operação -> que valor deve ser registrado.

Properties files

 

logging.level.org.hibernate.orm.jdbc.bind=trace
logging.level.org.hibernate.orm.jdbc.extract=trace

Modelo de Consulta Semântica

Com o registro corrigido, foi confirmado que o Hibernate realmente extrai duas registros do DB:

Plain Text

 

2023-01-25T08:40:18.819+01:00  INFO 6192 --- [           main] c.g.a.s.j.c.CountryRepositoryCustomTests : Started CountryRepositoryCustomTests in 4.678 seconds (process running for 5.745)
Hibernate: select c2_0.id,c2_0.name from city c1_0 join country c2_0 on c2_0.id=c1_0.country_id where c1_0.name like ? escape '!' and c1_0.state like ? escape '!'
2023-01-25T08:40:19.221+01:00 TRACE 6192 --- [           main] org.hibernate.orm.jdbc.extract           : extracted value ([1] : [BIGINT]) - [3]
2023-01-25T08:40:19.222+01:00 TRACE 6192 --- [           main] org.hibernate.orm.jdbc.extract           : extracted value ([2] : [VARCHAR]) - [USA]
2023-01-25T08:40:19.240+01:00 TRACE 6192 --- [           main] org.hibernate.orm.jdbc.extract           : extracted value ([1] : [BIGINT]) - [3]
2023-01-25T08:40:19.241+01:00 TRACE 6192 --- [           main] org.hibernate.orm.jdbc.extract           : extracted value ([2] : [VARCHAR]) - [USA]

No entanto, o teste recebe apenas uma entidade do Hibernate, como você pode ver nestas capturas de tela de depuração:

O comportamento alterado é causado pelo novo Modelo de Consulta Semântica com Deduplicação Automática (veja a parte Modelo de Consulta Semântica) introduzido com o Hibernate 6 (veja a linha 178 no classe org.hibernate.sql.results.spi.ListResultsConsumer). O Hibernate 6 agora retorna o resultado deduplicado.

Gerador JPA do Hibernate

A dependência Maven Hibernate Jpamodelgen gerenciada por Spring Boot Dependencies foi movida do pacote org.hibernate para org.hibernate.orm. Veja:

Spring Boot 2.7.5

XML

 

<dependency>
	<groupId>org.hibernate</groupId>
	<artifactId>hibernate-jpamodelgen</artifactId>
</dependency>

Spring Boot 3.0.2

XML

 

<dependency>
	<groupId>org.hibernate.orm</groupId>
	<artifactId>hibernate-jpamodelgen</artifactId>
</dependency>

Liquibase

Para concluir as dependências de persistência básica, o Liquibase foi atualizado da versão 4.9.1 para 4.17.2. Não há diferença significativa, exceto no uso da dependência JAX-B. A dependência deve usar JAX-B da Jakarta em vez de Javax (veja o seguinte referência).

Spring Boot 2.7.5

XML

 

<dependency>
	<groupId>org.liquibase</groupId>
	<artifactId>liquibase-core</artifactId>
</dependency>

Spring Boot 3.0.2

XML

 

<dependency>
	<groupId>org.liquibase</groupId>
	<artifactId>liquibase-core</artifactId>
	<exclusions>
		<exclusion> <!-- due to SB 3.0 switch to Jakarta -->
			<groupId>javax.xml.bind</groupId>
			<artifactId>jaxb-api</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<dependency>
	<groupId>jakarta.xml.bind</groupId>
	<artifactId>jakarta.xml.bind-api</artifactId>
</dependency>

Spring Data JPA 3.0.1

O Spring Boot 3.0.2 depende do Spring Data Release Train 2022.0.1 (veja Spring Data 2022.0 – Notas de Lançamento de Turing), onde o Spring Data JPA 3.0.1 é usado com essas mudanças chave (veja as notas de lançamento):

  1. Mudar a linha de base do Java para Java 17,
  2. Mudar a linha de base da Jakarta para Jakarta EE 10 e
  3. Aumentar para o Hibernate 6

Nota: a versão anteriormente utilizada (no nosso caso) era a 2.7.5.

Querydsl 5.0.0

A versão do Querydsl não foi alterada, mas foi afetada de maneira semelhante à do Liquibase. As dependências devem ser usadas da Jakarta em vez da Javax. Portanto, a dependência do Querydsl deve usar a classificação jakarta em vez da antiga classificação jpa (veja esta referência).

Spring Boot 2.7.5

XML

 

<dependency>
	<groupId>com.querydsl</groupId>
	<artifactId>querydsl-jpa</artifactId>
</dependency>
<dependency>
	<groupId>com.querydsl</groupId>
	<artifactId>querydsl-apt</artifactId>
	<version>${querydsl.version}</version>
	<classifier>jpa</classifier>
	<scope>provided</scope>
</dependency>

Spring Boot 3.0.2

XML

 

<dependency>
	<groupId>com.querydsl</groupId>
	<artifactId>querydsl-jpa</artifactId>
	<version>${querydsl.version}</version>
	<classifier>jakarta</classifier>
</dependency>
<dependency>
	<groupId>com.querydsl</groupId>
	<artifactId>querydsl-apt</artifactId>
	<scope>provided</scope>
	<version>${querydsl.version}</version>
	<classifier>jakarta</classifier>
</dependency>

Conclusão

Este artigo cobriu a atualização para o mais recente Spring Boot 3.0.2 para JPA e Querydsl (no momento de escrever este artigo). O artigo começou com as mudanças no Spring Framework e Spring Boot. Em seguida, todas as mudanças no Hibernate e tecnologias relacionadas foram abordadas. No final, mencionamos as pequenas mudanças relacionadas ao Spring Data 3.0.1 e Querydsl 5.0.0.

O código-fonte completo demonstrado acima está disponível no meu GitHub repositório.

Nota: também há um artigo anterior, Guia de Atualização para Spring Data Elasticsearch 5.0, dedicado a uma atualização semelhante do Elasticsearch com o Spring Boot 3.

Source:
https://dzone.com/articles/upgrade-guide-to-spring-boot-3-for-spring-data-jpa-3-and-querydsl-5