
Hallo, der Leser!
Während ich ein Schulungsprojekt für Spring Boot 2 entwickelte, entschied ich mich, mit @Param
in Spring Data JPA-Abfragen zu experimentieren, oder besser gesagt, mit deren Abwesenheit :
@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); }
(Über Magie, wie die zweite Methode funktioniert, steht in der alten Veröffentlichung " Following the Trail of Spring Pet Clinic" ).
@Param
Entfernen von @Param
Sie sicherstellen, dass Spring ohne sie @Param
funktioniert . Ich habe von einem Parameter in der Kompilierung gehört, mit dem Sie Namen in Anmerkungen nicht duplizieren können, aber ich habe nichts Besonderes getan, also habe ich mich entschieden tiefer graben einen Deal machen.
Wenn Sie immer noch die Anmerkungen aus dem Titel des Artikels, Spring Boot und JDK 8, verwenden, frage ich nach Katze:
UPDATE: @PathVariable
@RequestParam
@PathVariable
und @RequestParam
werden häufig noch benötigt, damit die Anwendung ordnungsgemäß funktioniert. Ihre value/name
Namensattribute sind jedoch nicht mehr erforderlich: Der Abgleich wird nach Variablennamen gesucht.
Als erstes habe ich versucht, den Namen im Parameter zu ändern ( mail
statt email
):
@Query("SELECT u FROM User u WHERE LOWER(u.email) = LOWER(:email)") Optional<User> findByEmailIgnoreCase(String mail);
Ich bekomme die Rezeption und den Platz für den Haltepunkt:
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]
Als nächstes finden wir die Stelle, an der der Name des Methodenparameters bestimmt wird:

Es ist ersichtlich, dass zwei Strategien verwendet werden: StandardReflectionParameterNameDiscoverer
und LocalVariableTableParameterNameDiscoverer
. Der erste verwendet den JDK8 JEP 118: Zugriff auf Parameternamen zur Laufzeit . Laut SPR-9643 versucht Spring, die "ASM-basierte Debug-Symbol-Analyse" zu verwenden, wenn es nicht möglich ist, die Parameternamen gemäß der ersten Strategie zu bestimmen.
- Es gibt viele Informationen zu den Java 8-Parameternamen im Internet. Eine Kompilierung mit dem Flag
-parameters
ist -parameters
. Ich gehe zu den Spring Boot-Einstellungen des IDEA-Projekts:

Ja, es ist wirklich enthalten ... Aber was ist, wenn ich das Projekt über Maven erstelle und ausführe?
Das Ergebnis ist das gleiche!
Ich aktiviere die Debug-Ausgabe in den Maven-Einstellungen, kompiliere das Projekt und sehe:
[DEBUG] Goal: org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) ... <parameters default-value="false">true</parameters>
Es sieht so aus, als ob das maven-compiler-plugin
bereits in spring-boot-starter-parent
konfiguriert ist, von wo spring-boot
Projekte standardmäßig geerbt werden, wenn sie über SPRING INITIALIZR generiert werden. Wir gehen dorthin und ( nur für Spring Boot 2 ) sicher, dass das Plugin dort konfiguriert ist:
<plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <parameters>true</parameters> </configuration> </plugin>
Schließlich können wir die Konfiguration des maven-compiler-plugin
in unserem Projekt neu definieren, wobei wir dieses Flag auf false
. Überprüfen Sie - das Projekt wurde gestartet. Und wenn wir versuchen, die Methode anzuwenden, erhalten wir:
Unable to detect parameter names for query method ru.javaops.bootjava.restaurantvoting.repository.UserRepository.findByEmailIgnoreCase! Use @Param or compile with -parameters on JDK 8.
Dies bedeutet, dass:
- Unsere Argumentation ist richtig
- Basierend auf der zweiten ASM-Strategie konnte ich die Informationen nicht erhalten (obwohl ich über Debug angefangen habe).
ERGEBNIS: Das Flag -parameters
in Spring Boot 2 ist standardmäßig aktiviert. Wenn Sie also von spring-boot-starter-parent
erben, werden die Parameternamen zur @Param
definiert und @Param
, @RequestParam
, @PathVariable
nicht mehr erforderlich. Weniger Code, weniger Fehler.
Für Spring Boot 1.x kann das Kompilierungsflag zwangsweise aktiviert werden (siehe oben).
PS: Ich habe JDK 8, JDK 11 und Spring Boot 2.1.1 für Forschungszwecke verwendet
UPDATE 2: Es ist interessant, dass für @RequestParam
und @PathVariable
zweite die zweite LocalVariableTableParameterNameDiscoverer
Strategie basierend auf den von ASM aus dem Bytecode empfangenen Informationen LocalVariableTableParameterNameDiscoverer
. Einschließlich für den regulären Frühling (ohne Boot) und ohne Kompilierungsoption.
Vielen Dank für Ihre Aufmerksamkeit!