ใน JDK มีชุดของ API การรวบรวมที่เกี่ยวข้องซึ่งสามารถเริ่มต้นกระบวนการรวบรวมใน Java, Parse Java Source Files และรับแผนผังไวยากรณ์ ชุด APIs ที่สมบูรณ์นี้รวมอยู่ในเครื่องมือ jar ของ JDK (สามารถพบได้ใน/ห้องสมุด/java/javavirtualmachines/jdk_version/เนื้อหา/บ้าน/lib ภายใต้ OSX) แต่นี่ไม่ใช่ API สาธารณะใน Oracle และ OpenJDK อย่างไรก็ตามหลายโครงการได้ใช้ API นี้เพื่อทำสิ่งต่าง ๆ มากมาย ตัวอย่างเช่นลอมบอกที่มีชื่อเสียงใช้ API นี้เพื่อปรับเปลี่ยนแผนผังไวยากรณ์ในซอร์สโค้ดในระหว่างขั้นตอนการประมวลผลคำอธิบายประกอบ ผลลัพธ์สุดท้ายเทียบเท่ากับการแทรกรหัสใหม่ลงในไฟล์ต้นฉบับโดยตรง!
เนื่องจาก APIs ชุดนี้ไม่มีเอกสารที่เกี่ยวข้องจึงยากที่จะใช้ ตัวอย่างเช่นแยกวิเคราะห์ตัวแปรทั้งหมดในซอร์สโค้ดและพิมพ์ออกมา:
Javaparser คลาสสาธารณะ {Private Static Final String Path = "user.java"; JavacfileManager ส่วนตัว; Javactool Javactool ส่วนตัว; Javaparser สาธารณะ () {บริบทบริบท = บริบทใหม่ (); fileManager = ใหม่ javacfileManager (บริบท, true, charset.defaultCharset ()); Javactool = new Javactool (); } โมฆะสาธารณะ parsejavafiles () {iterable <!-? ขยาย JavafileObject-> files = fileManager.getJavafileObjects (เส้นทาง); javacompiler.compilationTask CompilationTask = javactool.getTask (null, fileManager, null, null, null, ไฟล์); Javactask Javactask = (Javactask) CompilationTask; ลอง {iterable <!-? ขยาย CompilationunitTree-> result = javactask.parse (); สำหรับ (Tree CompilationUnitTree: ผลลัพธ์) {tree.accept (ใหม่ sourcevisitor (), null); }} catch (ioexception e) {e.printstacktrace (); }} คลาสคงที่ sourceVisitor ขยาย treescanner <void, void = ""> {สตริงส่วนตัว currentpackagename = null; @Override เป็นโมฆะสาธารณะ VISTCOMPILITIONONIT (CompileMunitTree Node, Void หลีกเลี่ยง) {return Super.VisitCompiveNitUnit (โหนด, หลีกเลี่ยง); } @Override โมฆะสาธารณะ VisitVariable (VariableTree Node, Void หลีกเลี่ยง) {formatptrln ("ชื่อตัวแปร: %s, ประเภท: %s, ชนิด: %s, แพ็คเกจ: %s", node.getName (), node.getType (), node.getKind () คืนค่า null; }} โมฆะแบบคงที่สาธารณะรูปแบบ ptrln (รูปแบบสตริง, วัตถุ ... args) {system.out.println (string.format (รูปแบบ, args)); } โมฆะคงที่สาธารณะหลัก (สตริง [] args) {javaparser ใหม่ (). parsejavafiles (); }} </void,>รหัสของ user.java มีดังนี้:
แพ็คเกจ com.ragnarok.javaparser; นำเข้า com.sun.istack.internal.nullable; นำเข้า java.lang.override; ผู้ใช้คลาสสาธารณะ {@Nullable Private String foo = "123123"; Private Foo A; โมฆะสาธารณะ usermethod () {} คลาสคงที่ foo {สตริงส่วนตัว foostring = "123123"; โมฆะสาธารณะ foomethod () {}}}ผลลัพธ์ของการดำเนินการ javaparser ข้างต้นมีดังนี้:
ตัวแปร: foo, annotaion: nullablevariable ชื่อ: foo, ประเภท: สตริง, ชนิด: ตัวแปร, แพ็คเกจ: com.ragnarok.javaparserver ตัวแปรชื่อ: a, ประเภท: foo, ชนิด: ตัวแปร, แพ็คเกจ: com.ragnarok.javaparser
ที่นี่เราแยกวิเคราะห์ไฟล์ต้นฉบับผ่าน Javacompiler.CompilationTask จากนั้นใช้ sourcevisitor ที่กำหนดเอง (สืบทอดมาจาก Treescanner) เพื่อเข้าถึงโครงสร้างของซอร์สโค้ด ในคลาส SourceVisitor เรา overload เยี่ยมชมการแยกวิเคราะห์หน่วยการรวบรวม (ไฟล์ซอร์สซอร์สเดียว) และเข้าถึงตัวแปรทั้งหมด จะเห็นได้ที่นี่ว่าเราไม่สามารถรับชื่อที่มีคุณสมบัติครบถ้วนของประเภทตัวแปรนี้ (รวมถึงชื่อแพ็คเกจ) และสามารถรับชื่อง่าย ๆ ที่สอดคล้องกันเท่านั้น ดังนั้นการกำหนดประเภทต้องใช้การใช้งานภายนอกเพื่อตรวจสอบด้วยตัวเอง ตัวอย่างเช่นคุณสามารถบันทึกชื่อแพ็คเกจที่ชั้นเรียนอยู่ค้นหาไดเรกทอรีซอร์สโค้ดทั้งหมดซ้ำเพื่อติดตามชื่อที่ผ่านการรับรองของคลาสทั้งหมดและค้นหาว่าการนำเข้ามีประเภทที่สอดคล้องกัน ฯลฯ ฯลฯ
นอกเหนือจากวิธีการเยี่ยมชมที่มีการเยี่ยมชม Treescanner ยังมีวิธีการเยี่ยมชมอื่น ๆ จำนวนมาก ตัวอย่างเช่นคุณสามารถสำรวจการนำเข้าทั้งหมดคำจำกัดความวิธีการคำอธิบายประกอบ ฯลฯ สำหรับเฉพาะเจาะจงมากขึ้นคุณสามารถดูซอร์สโค้ดเกี่ยวกับสิ่งนี้ใน OpenJDK
ที่นี่เราจะนำตัวอย่างอื่นมาใช้วิธีการ VisitClass เพื่อเข้าถึงคลาสภายในทั้งหมดและคลาสเอง:
@OverridePublic เป็นโมฆะ VISTCLASS (CLASSTREE NODE, VOID หลีกเลี่ยง) {FormatPTRLN ("ชื่อคลาส: %s", node.getSimplename ()); สำหรับ (Tree Member: node.getMembers ()) {ถ้า (สมาชิกอินสแตนซ์ของ VariableTree) {variableTree variable = (variableTree) สมาชิก; รายการ <!-? ขยาย AnnotationTree-> Annotations = Variable.getModifiers (). getannotations (); if (Annotations.size ()> 0) {formatptrln ("ตัวแปร: %s, annotaion: %s", variable.getName (), Annotations.get (0) .getAnnotationType ()); } else {formatptrln ("ตัวแปร: %s", variable.getName ()); }}} return super.visitclass (โหนด, หลีกเลี่ยง); -ที่นี่เราเพียงพิมพ์ชื่อคลาสและชื่อตัวแปรประเภทและประเภทคำอธิบายประกอบ ดำเนินการรหัสด้านบนและผลลัพธ์มีดังนี้:
ชื่อคลาส: USERVARIABLE: FOO, Annotaion: nullableVariable: ชื่อคลาส: foovariable: foostring
จะเห็นได้ว่าเราได้พิมพ์ชื่อคลาสและตัวแปรในชั้นเรียน ในวิธีการเยี่ยมชมคลาสเราสามารถรับสมาชิกทั้งหมดของชั้นเรียนผ่านวิธี getMembers รวมถึงตัวแปรวิธีการคำอธิบายประกอบ ฯลฯ ซึ่งสอดคล้องกับประเภทที่แตกต่างกัน ตัวอย่างเช่นตัวแปรสอดคล้องกับประเภทตัวแปรและวิธีการสอดคล้องกับประเภทของเมธอด
โดยทั่วไปแม้ว่าการใช้งานจะไม่ซับซ้อนเป็นพิเศษในความเป็นจริง แต่ก็ทำให้เกิดอุปสรรคที่ดีในการใช้เนื่องจากขาดเอกสาร และสิ่งที่เรากำลังแนะนำเป็นเพียงส่วนเล็ก ๆ ของ API นี้ ฉันจะศึกษาหน้าที่ที่เกี่ยวข้องของ API นี้ต่อไปในอนาคต
ข้างต้นเป็นการรวบรวมข้อมูลตัวแยกวิเคราะห์ของ JDK เพื่อแยกวิเคราะห์ซอร์สโค้ด Java เราจะยังคงเพิ่มข้อมูลที่เกี่ยวข้องในอนาคต ขอบคุณสำหรับการสนับสนุนเว็บไซต์นี้!