Di JDK, ada satu set API kompilasi terkait yang dapat memulai proses kompilasi di java, parse file sumber java dan mendapatkan pohon sintaksnya. Set lengkap API ini termasuk dalam alat. Namun, banyak proyek telah menggunakan API ini untuk melakukan banyak hal. Misalnya, Lombok yang terkenal menggunakan API ini untuk memodifikasi pohon sintaks dalam kode sumber selama tahap pemrosesan anotasi. Hasil akhir setara dengan memasukkan kode baru langsung ke file sumber!
Karena set API ini saat ini tidak memiliki dokumen yang relevan, sulit digunakan. Misalnya, parse semua variabel dalam kode sumber dan cetaknya:
kelas publik javaparser {private static final string path = "user.java"; Private JavacfileManager FileManager; Private Javactool Javactool; javaparser publik () {konteks konteks = konteks baru (); filemanager = javacfileManager baru (konteks, true, charset.defaultcharset ()); javactool = javactool baru (); } public void parsejavafiles () {iterable <!-? Extends JavaFileObject-> File = FileManager.GetJavaFileObjects (Path); Javacompiler.compilationTask compilationTask = javactool.getask (null, filemanager, null, null, null, file); Javactask javactask = (javactask) compilationTask; coba {iterable <!-? Extends CompilationUnittree-> hasil = javactask.parse (); untuk (CompilationUnittree Tree: hasil) {Tree.accept (Sourcevisitor baru (), null); }} catch (ioException e) {E.PrintStackTrace (); }} Sourcevisitor kelas statis memperluas Treescanner <void, void = ""> {private string currentpackagename = null; @Override public void vis visnCompiledUnit (compilationunittree node, void hindari) {return super.visitCompilationUnit (node, hindari); } @Override public void VisitVariable (node variableTree, void hindari) {formatPtrln ("Nama variabel: %s, type: %s, jenis: %s, paket: %s", node.getname (), node.gettype (), node.getKind (), currentpackagename); kembali nol; }} public static void formatPtrln (format string, objek ... args) {System.out.println (string.format (format, args)); } public static void main (string [] args) {new javaparser (). parsejavafile (); }} </void,>Kode pengguna.java adalah sebagai berikut:
paket com.ragnarok.javaparser; impor com.sun.istack.internal.nullable; import java.lang.override; pengguna kelas publik {@nullable private string foo = "123123"; Private foo a; public void usermethod () {} kelas statis foo {private string foostring = "123123"; public void foomethod () {}}}Hasil dari mengeksekusi javaparser di atas adalah sebagai berikut:
Variabel: foo, annotaion: nullableVariable Name: foo, type: string, jenis: variabel, paket: com.ragnarok.javaparserver nama variabel: a, tipe: foo, jenis: variabel, paket: com.ragnarok.javaparser
Di sini kami pertama -tama menguraikan file sumber melalui javacompiler.compilationTask, dan kemudian menggunakan Sourcevisitor Kustom (diwarisi dari Treescanner) untuk mengakses struktur kode sumber. Di kelas Sourcevisitor, kami kelebihan visitvariable untuk menguraikan unit kompilasi (file kode sumber tunggal) dan mengakses semua variabel. Dapat dilihat di sini bahwa kita tidak bisa mendapatkan nama yang sepenuhnya memenuhi syarat dari jenis variabel ini (termasuk nama paket), dan hanya bisa mendapatkan nama sederhana yang sesuai. Oleh karena itu, penentuan jenis membutuhkan implementasi eksternal untuk menentukannya dengan sendirinya. Misalnya, Anda dapat merekam nama paket di mana kelas berada, secara rekursif mencari seluruh direktori kode sumber untuk melacak nama yang sepenuhnya memenuhi syarat dari semua kelas, dan temukan apakah impor berisi jenis yang sesuai, dll.
Selain metode VisitVariable, Treescanner juga berisi sejumlah besar metode Visitxyz lainnya. Misalnya, Anda dapat melintasi semua impor, definisi metode, anotasi, dll. Untuk lebih spesifik, Anda dapat melihat kode sumber tentang ini di OpenJDK.
Di sini kami akan mengambil contoh lain, berlebihan metode VisitClass untuk mengakses semua kelas dalam dan kelas itu sendiri:
@Overridepublic void VisitClass (node classtree, void hindari) {formatPtrln ("Nama kelas: %s", node.getsimplename ()); untuk (anggota pohon: node.getMembers ()) {if (anggota anggota variableTree) {variableTree variable = (variableTree) anggota; Daftar <!-? Extends AnnotationTree-> annotations = variable.getModifiers (). getAnnotations (); if (annotations.size ()> 0) {formatPtrln ("Variabel: %s, annotaion: %s", variable.getName (), annotations.get (0) .getAnnotationType ()); } else {formatPtrln ("variabel: %s", variable.getName ()); }}} return super.visitclass (node, hindari); }Di sini kami cukup mencetak nama kelas dan nama variabel, ketik, dan jenis anotasi. Jalankan kode di atas, dan hasilnya adalah sebagai berikut:
Nama Kelas: UserVariable: Foo, Annotaion: NullableVariable: Class Name: Foovariable: Foostring
Dapat dilihat bahwa kita telah mencetak nama kelas dan variabel di kelas. Dalam metode VisitClass, kita bisa mendapatkan semua anggota kelas melalui metode GetMembers, termasuk variabel, metode, anotasi, dll., Yang sesuai dengan berbagai jenis. Misalnya, variabel sesuai dengan jenis variabelree, dan metode sesuai dengan tipe MethodTree.
Secara umum, meskipun penggunaannya sebenarnya tidak terlalu rumit, itu telah menyebabkan hambatan besar untuk digunakan karena kurangnya dokumentasi. Dan apa yang kami perkenalkan hanyalah sebagian kecil dari API ini. Saya akan terus mempelajari fungsi terkait API ini di masa depan.
Di atas adalah kompilasi data parser JDK untuk mengurai kode sumber Java. Kami akan terus menambahkan informasi yang relevan di masa mendatang. Terima kasih atas dukungan Anda untuk situs ini!