Spring dan JDK 8: Apakah Anda masih menggunakan @Param dan nama / nilai dalam anotasi Spring MVC? Maka artikel itu untuk Anda


Halo Pembaca!


Saat mengembangkan proyek pelatihan tentang Spring Boot 2, saya memutuskan untuk bereksperimen dengan @Param dalam pertanyaan Spring Data JPA, atau lebih tepatnya, dengan ketidakhadiran mereka :


 @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); } 

(tentang sihir, cara kerja metode kedua adalah di publikasi lama Mengikuti Jejak Klinik Spring Pet ).


@Param menghapus @Param Anda dapat memastikan bahwa Spring berfungsi dengan baik tanpa mereka . Saya mendengar tentang parameter dalam kompilasi yang memungkinkan Anda untuk tidak menduplikasi nama dalam anotasi, tetapi saya tidak melakukan sesuatu yang istimewa, jadi saya memutuskan menggali lebih dalam membuat kesepakatan


Jika Anda masih menggunakan anotasi dari judul artikel, Spring Boot dan JDK 8, saya minta cat:


UPDATE: @RequestParam dan @RequestParam masih sering dibutuhkan agar aplikasi berfungsi dengan benar. Tetapi atribut value/name mereka tidak lagi diperlukan: pencocokan dicari oleh nama variabel.


  • Hal pertama yang saya coba adalah mengubah nama dalam parameter ( mail bukan email ):


     @Query("SELECT u FROM User u WHERE LOWER(u.email) = LOWER(:email)") Optional<User> findByEmailIgnoreCase(String mail); 

    Saya mendapatkan resepsi dan tempat untuk breakpoint:


     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] 

  • Selanjutnya, kami menemukan tempat di mana nama parameter metode ditentukan:




Dapat dilihat bahwa 2 strategi digunakan: StandardReflectionParameterNameDiscoverer dan LocalVariableTableParameterNameDiscoverer . Yang pertama menggunakan JDK8 JEP 118: Akses ke Nama Parameter di Runtime . Menurut SPR-9643 , jika tidak mungkin untuk menentukan nama parameter sesuai dengan strategi pertama, Spring mencoba menggunakan "analisis simbol debug berbasis ASM".


  • Ada banyak informasi tentang Nama Parameter Java 8 di Internet, kompilasi dengan flag -parameters . Saya pergi ke pengaturan Boot Musim Semi dari proyek IDEA:


Ya, itu benar-benar termasuk ... Tetapi bagaimana jika saya membangun dan menjalankan proyek melalui Maven?
Hasilnya sama!


  • Saya mengaktifkan debug output dalam pengaturan Maven, kompilasi proyek dan lihat:


     [DEBUG] Goal: org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) ... <parameters default-value="false">true</parameters> 

    Sepertinya maven-compiler-plugin sudah dikonfigurasikan di spring-boot-starter-parent , dari mana proyek spring-boot diwarisi secara default ketika dihasilkan melalui SPRING INITIALIZR . Kami pergi ke sana dan ( hanya untuk Boot Spring 2 ) pasti, plugin dikonfigurasi di sana:


      <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <parameters>true</parameters> </configuration> </plugin> 

  • Terakhir, kita dapat mendefinisikan kembali konfigurasi maven-compiler-plugin di proyek kita, di mana kita menetapkan flag ini menjadi false . Periksa - proyek telah dimulai. Dan ketika mencoba menarik metode yang kita dapatkan:


     Unable to detect parameter names for query method ru.javaops.bootjava.restaurantvoting.repository.UserRepository.findByEmailIgnoreCase! Use @Param or compile with -parameters on JDK 8. 


Ini berarti:


  1. alasan kami benar
  2. Berdasarkan strategi ASM kedua, saya tidak bisa mendapatkan informasi (meskipun saya mulai melalui Debug)

HASIL: flag -parameters di Spring Boot 2 diaktifkan secara default, jadi jika Anda mewarisi dari spring-boot-starter-parent , maka nama parameter didefinisikan dalam @Param dan @Param , @RequestParam , @PathVariable tidak lagi diperlukan. Lebih sedikit kode, lebih sedikit kesalahan.


Untuk Spring Boot 1.x, flag kompilasi dapat diaktifkan secara paksa, lihat di atas.


PS: Saya menggunakan JDK 8, JDK 11, dan Spring Boot 2.1.1 untuk penelitian


UPDATE 2: menarik bahwa untuk @RequestParam dan @PathVariable kedua bekerja, strategi LocalVariableTableParameterNameDiscoverer kedua berdasarkan pada informasi yang diterima oleh ASM dari bytecode. Termasuk untuk Spring reguler (tanpa Boot) dan tanpa opsi kompilasi.


Terima kasih atas perhatian anda!

Source: https://habr.com/ru/post/id440214/


All Articles