
Hola, el lector!
Mientras desarrollaba un proyecto de capacitación en Spring Boot 2, decidí experimentar con @Param
en consultas de Spring Data JPA, o más bien, con su ausencia :
@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 magia, cómo funciona el segundo método está en la publicación anterior Siguiendo el rastro de la Clínica de mascotas de primavera ).
@Param
eliminar @Param
puedes asegurarte de que Spring funcione bien sin ellos . Escuché sobre un parámetro en la compilación que le permite no duplicar nombres en anotaciones, pero no hice nada especial, así que decidí cavar más profundo hacer un trato
Si todavía usa las anotaciones del título del artículo, Spring Boot y JDK 8, le pido gato:
ACTUALIZACIÓN: @PathVariable
@RequestParam
@PathVariable
y @RequestParam
todavía son necesarias para que la aplicación funcione correctamente. Pero sus atributos de value/name
ya no son necesarios: los nombres de las variables buscan la coincidencia.
Lo primero que intenté fue cambiar el nombre en el parámetro ( mail
lugar de email
):
@Query("SELECT u FROM User u WHERE LOWER(u.email) = LOWER(:email)") Optional<User> findByEmailIgnoreCase(String mail);
Recibo la recepción y el lugar para el punto de interrupción:
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]
A continuación, encontramos el lugar donde se determina el nombre del parámetro del método:

Se puede ver que se utilizan 2 estrategias: StandardReflectionParameterNameDiscoverer
y LocalVariableTableParameterNameDiscoverer
. El primero usa el JDK8 JEP 118: Acceso a los nombres de los parámetros en tiempo de ejecución . De acuerdo con SPR-9643 , si no es posible determinar los nombres de los parámetros de acuerdo con la primera estrategia, Spring intenta usar el "análisis de símbolos de depuración basado en ASM".
- Hay mucha información sobre los nombres de parámetros de Java 8 en Internet, se
-parameters
compilación con el indicador -parameters
. Voy a la configuración de Spring Boot del proyecto IDEA:

Sí, está realmente incluido ... ¿Pero qué pasa si construyo y ejecuto el proyecto a través de Maven?
¡El resultado es el mismo!
Enciendo la salida de depuración en la configuración de Maven, compilo el proyecto y veo:
[DEBUG] Goal: org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) ... <parameters default-value="false">true</parameters>
Parece que el maven-compiler-plugin
ya maven-compiler-plugin
configurado en spring-boot-starter-parent
, de donde spring-boot
proyectos spring-boot
se heredan por defecto cuando se generan a través de SPRING INITIALIZR . Vamos allí y ( solo para Spring Boot 2 ) seguro, el complemento está configurado allí:
<plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <parameters>true</parameters> </configuration> </plugin>
Finalmente, podemos redefinir la configuración del maven-compiler-plugin
en nuestro proyecto, donde establecemos este indicador en false
. Comprobar: el proyecto ha comenzado. Y cuando intentamos extraer el método obtenemos:
Unable to detect parameter names for query method ru.javaops.bootjava.restaurantvoting.repository.UserRepository.findByEmailIgnoreCase! Use @Param or compile with -parameters on JDK 8.
Esto significa que:
- nuestro razonamiento es cierto
- Basado en la segunda estrategia de ASM, no pude obtener la información (aunque comencé a través de Debug)
RESULTADO: el indicador de -parameters
en Spring Boot 2 está habilitado de manera predeterminada, por lo que si hereda de spring-boot-starter-parent
, los nombres de los parámetros se definen en @Param
de @Param
y @Param
, @RequestParam
, @PathVariable
no son necesarios. Menos código, menos errores.
Para Spring Boot 1.x, el indicador de compilación se puede habilitar por la fuerza, ver arriba.
PD: utilicé JDK 8, JDK 11 y Spring Boot 2.1.1 para la investigación
ACTUALIZACIÓN 2: es interesante que para @RequestParam
y @PathVariable
segundo funcione con la segunda estrategia LocalVariableTableParameterNameDiscoverer
basada en la información recibida por ASM del LocalVariableTableParameterNameDiscoverer
. Incluyendo para Spring regular (sin arranque) y sin una opción de compilación.
Gracias por su atencion!