
مرحبا ، القارئ!
أثناء تطوير مشروع تدريبي على برنامج Spring Boot 2 ، قررت تجربة @Param
في استعلامات Spring Data JPA ، أو بالأحرى مع غيابها :
@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); }
(عن السحر ، كيف تعمل الطريقة الثانية في المنشور القديم التالي لـ Trail of Spring Pet Clinic ).
@Param
إزالة @Param
يمكنك التأكد من أن Spring يعمل بشكل جيد بدونها . سمعت بمعلمة في التجميع تتيح لك عدم تكرار الأسماء في التعليقات التوضيحية ، لكنني لم أفعل أي شيء خاص ، لذلك قررت حفر أعمق عقد صفقة.
إذا كنت لا تزال تستخدم التعليقات التوضيحية من عنوان المقال ، Spring Boot و JDK 8 ، فأنا أطلب cat:
استكمال: لا تزال هناك حاجة إلى @RequestParam
و @RequestParam
حتى يعمل التطبيق بشكل صحيح. لكن سمات value/name
لم تعد مطلوبة: يتم البحث عن مطابقة بواسطة أسماء المتغيرات.
أول شيء حاولت تغيير الاسم في المعلمة ( mail
بدلاً من email
):
@Query("SELECT u FROM User u WHERE LOWER(u.email) = LOWER(:email)") Optional<User> findByEmailIgnoreCase(String mail);
أحصل على مكان الاستقبال ونقطة التوقف:
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]
بعد ذلك ، نجد المكان الذي يتم فيه تحديد اسم معلمة الطريقة:

يمكن ملاحظة أنه يتم استخدام استراتيجيات 2: StandardReflectionParameterNameDiscoverer
و LocalVariableTableParameterNameDiscoverer
. الأول يستخدم JDK8 JEP 118: الوصول إلى أسماء المعلمات في وقت التشغيل . وفقًا لـ SPR-9643 ، إذا لم يكن من الممكن تحديد أسماء المعلمات عن طريق الاستراتيجية الأولى ، يحاول Spring استخدام "تحليل رمز تصحيح الأخطاء المستند إلى ASM".
- هناك الكثير من المعلومات حول Java 8 Parameter Names على الإنترنت ،
-parameters
التجميع باستخدام علامة -parameters
. أذهب إلى إعدادات Spring Boot في مشروع IDEA:

نعم ، لقد تم تضمينه بالفعل ... ولكن ماذا لو قمت ببناء وتشغيل المشروع من خلال Maven؟
والنتيجة هي نفسها!
أقوم بتشغيل إخراج تصحيح في إعدادات Maven ، ترجمة المشروع ونرى:
[DEBUG] Goal: org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) ... <parameters default-value="false">true</parameters>
يبدو أن maven-compiler-plugin
تم تهيئته بالفعل في spring-boot-starter-parent
spring-boot
، حيث يتم توريث مشاريع spring-boot
افتراضيًا عند إنشائها عبر SPRING INITIALIZR . نذهب إلى هناك و ( فقط من أجل Spring Boot 2 ) بالتأكيد ، تم تكوين المكون الإضافي هناك:
<plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <parameters>true</parameters> </configuration> </plugin>
أخيرًا ، يمكننا إعادة تعريف تكوين maven-compiler-plugin
في مشروعنا ، حيث نضع هذه العلامة على false
. تحقق - بدأ المشروع. وعند محاولة سحب الطريقة نحصل على:
Unable to detect parameter names for query method ru.javaops.bootjava.restaurantvoting.repository.UserRepository.findByEmailIgnoreCase! Use @Param or compile with -parameters on JDK 8.
هذا يعني أن:
- منطقنا صحيح
- استنادًا إلى استراتيجية ASM الثانية ، لم أستطع الحصول على المعلومات (على الرغم من أنني بدأت من خلال Debug)
RESULT: يتم -parameters
علامة -parameters
في Spring Boot 2 افتراضيًا ، لذلك إذا كنت ترث من spring-boot-starter-parent
، فسيتم تحديد أسماء المعلمات في @Param
و @Param
، @RequestParam
، @PathVariable
لم تعد مطلوبة. رمز أقل ، أخطاء أقل.
بالنسبة لـ Spring Boot 1.x ، يمكن تمكين علامة الترجمة بالقوة ، انظر أعلاه.
ملاحظة: استخدمت JDK 8 ، JDK 11 ، و Spring Boot 2.1.1 للبحث
UPDATE 2: من المثير أنه بالنسبة إلى @RequestParam
و @PathVariable
تعمل الثانية الثانية لاستراتيجية LocalVariableTableParameterNameDiscoverer
الثانية بناءً على المعلومات التي تلقاها ASM من LocalVariableTableParameterNameDiscoverer
البريدي. بما في ذلك الربيع العادية (بدون التمهيد) وبدون خيار التحويل البرمجي.
شكرا لاهتمامكم!