
Olá, o leitor!
Enquanto desenvolvia um projeto de treinamento no Spring Boot 2, decidi experimentar o @Param
nas consultas JPA do Spring Data, ou melhor, com a ausência deles :
@Transactional(readOnly = true) public interface UserRepository extends JpaRepository<User, Integer> { @Query("SELECT u FROM User u WHERE LOWER(u.email) = LOWER(:email)") Optional<User> findByEmailIgnoreCase(@Param("email") String email); List<User> findByLastNameContainingIgnoreCase(@Param("lastname") String lastName); }
(sobre mágica, como o segundo método funciona está na publicação antiga Following the Trail of Spring Pet Clinic ).
@Param
remover o @Param
você pode garantir que o Spring funcione bem sem eles . Ouvi falar de um parâmetro na compilação que permite que você não duplique nomes nas anotações, mas como não fiz nada de especial, decidi cavar mais fundo fazer um acordo.
Se você ainda usa as anotações do título do artigo, Spring Boot e JDK 8, peço cat:
UPDATE: as @RequestParam
e @RequestParam
ainda são necessárias para que o aplicativo funcione corretamente. Mas seus atributos de value/name
não são mais necessários: a correspondência é pesquisada pelos nomes de variáveis.
A primeira coisa que tentei foi alterar o nome no parâmetro ( mail
vez de email
):
@Query("SELECT u FROM User u WHERE LOWER(u.email) = LOWER(:email)") Optional<User> findByEmailIgnoreCase(String mail);
Recebo a recepção e o local do ponto de interrupção:
Caused by: java.lang.IllegalStateException: Using named parameters for method public abstract java.util.Optional ru.javaops.bootjava.restaurantvoting.repository.UserRepository.findByEmailIgnoreCase(java.lang.String) but parameter 'Optional[mail]' not found in annotated query 'SELECT u FROM User u WHERE LOWER(u.email) = LOWER(:email)'! at org.springframework.data.jpa.repository.query.JpaQueryMethod.assertParameterNamesInAnnotatedQuery(JpaQueryMethod.java:125) ~[spring-data-jpa-2.1.3.RELEASE.jar:2.1.3.RELEASE]
Em seguida, encontramos o local em que o nome do parâmetro do método é determinado:

Pode-se observar que duas estratégias são usadas: StandardReflectionParameterNameDiscoverer
e LocalVariableTableParameterNameDiscoverer
. O primeiro usa o JDK8 JEP 118: acesso aos nomes de parâmetros em tempo de execução . De acordo com o SPR-9643 , se não for possível determinar os nomes dos parâmetros pela primeira estratégia, o Spring tenta usar a "análise de símbolo de depuração baseada em ASM".
- Há muitas informações sobre os nomes de parâmetros do Java 8 na Internet, é
-parameters
compilação com o sinalizador -parameters
. Eu vou para as configurações do Spring Boot do projeto IDEA:

Sim, está realmente incluído ... Mas e se eu criar e executar o projeto através do Maven?
O resultado é o mesmo!
Ative a saída de depuração nas configurações do Maven, compile o projeto e veja:
[DEBUG] Goal: org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) ... <parameters default-value="false">true</parameters>
Parece que o maven-compiler-plugin
já maven-compiler-plugin
configurado no spring-boot-starter-parent
, de onde spring-boot
projetos de spring-boot
são herdados por padrão quando gerados pelo SPRING INITIALIZR . Vamos lá e ( apenas para o Spring Boot 2 ), com certeza, o plugin está configurado lá:
<plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <parameters>true</parameters> </configuration> </plugin>
Finalmente, podemos redefinir a configuração do maven-compiler-plugin
em nosso projeto, onde definimos esse sinalizador como false
. Cheque - o projeto foi iniciado. E ao tentar puxar o método, obtemos:
Unable to detect parameter names for query method ru.javaops.bootjava.restaurantvoting.repository.UserRepository.findByEmailIgnoreCase! Use @Param or compile with -parameters on JDK 8.
Isso significa que:
- nosso raciocínio está correto
- Com base na segunda estratégia do ASM, não consegui obter as informações (embora tenha iniciado o Debug)
RESULTADO: o sinalizador -parameters
no Spring Boot 2 é ativado por padrão; portanto, se você herdar do spring-boot-starter-parent
, os nomes dos parâmetros serão definidos em @Param
e @Param
, @RequestParam
, @PathVariable
não @PathVariable
mais necessários. Menos código, menos erros.
Para o Spring Boot 1.x, o sinalizador de compilação pode ser ativado à força, veja acima.
PS: usei o JDK 8, JDK 11 e Spring Boot 2.1.1 para pesquisa
ATUALIZAÇÃO 2: é interessante que para @RequestParam
e @PathVariable
segundo funcione a segunda estratégia LocalVariableTableParameterNameDiscoverer
base nas informações recebidas pelo ASM do bytecode. Incluindo o Spring regular (sem inicialização) e sem uma opção de compilação.
Obrigado pela atenção!