في JDK ، هناك مجموعة من واجهات برمجة تطبيقات التجميع ذات الصلة التي يمكن أن تبدأ عملية التجميع في ملفات Java ، Parse Java Source والحصول على شجرة بناء الجملة. يتم تضمين هذه المجموعة الكاملة من واجهات برمجة التطبيقات في Tools.jar من JDK (يمكن العثور عليها في/Library/Java/JavavirtualMachines/JDK_Version/Contents/Home/Lib بموجب OSX) ، ولكن هذا ليس واجهة برمجة تطبيقات عامة في إصدارات Oracle و OpenJDK ، لذلك لا يوجد وثائق رسمية رسمية لشرح هذه المجموعة من APIS. ومع ذلك ، استخدمت العديد من المشاريع هذه API للقيام بالكثير من الأشياء. على سبيل المثال ، استخدم Lombok الشهير API هذا لتعديل شجرة بناء الجملة في رمز المصدر أثناء مرحلة معالجة التعليقات التوضيحية. النتيجة النهائية تعادل إدخال رمز جديد مباشرة في الملف المصدر!
نظرًا لأن هذه المجموعة من واجهات برمجة التطبيقات تفتقر حاليًا إلى المستندات ذات الصلة ، فمن الصعب استخدامها. على سبيل المثال ، تحليل جميع المتغيرات في الكود المصدر وطباعتها:
الفئة العامة javaparser {private static final string path = "user.java" ؛ الخاص JavacfileManager FileManager ؛ Javactool Javactool الخاص ؛ javaparser العامة () {سياق السياق = سياق جديد () ؛ FileManager = New JavacFileManager (السياق ، True ، charset.defaultcharset ()) ؛ javactool = new Javactool () ؛ } parsejavafiles parsejavafiles () {iterable <!-؟ يمتد javafileObject-> files = filemanager.getjavafileObjects (path) ؛ javacompiler.compilationTask compilationTask = javactool.getTask (null ، filemanager ، null ، null ، null ، files) ؛ javactask javactask = (javactask) compilationTask ؛ حاول {itervable <!-؟ يمتد compilationUnittree-> النتيجة = javactask.parse () ؛ لـ (compilationUnittree tree: result) {tree.accept (new sourceVisitor () ، null) ؛ }} catch (ioException e) {E.PrintStackTrace () ؛ }} static class sourceVisitor يمتد Treescanner <void ، void = ""> {private string currentPackagename = null ؛ Override public void issompilationUnit (compilationUnittree node ، void تجنب) {return super.visitCompilationUnit (العقدة ، تجنب) ؛ } Override public void visitvariable (variabletree node ، void adving) {formatptrln ("name fariable: ٪ s ، type: ٪ s ، kind: ٪ s ، package: ٪ s" ، node.getName () ، node.gettype () ، node.getkind () ، currentpackagename) ؛ العودة لاغية. }} public static void formatptrln (تنسيق السلسلة ، الكائن ... args) {system.out.println (string.format (format ، args)) ؛ } public static void main (string [] args) {new javaparser (). parsejavafiles () ؛ }} </void ،>رمز user.java كما يلي:
حزمة com.ragnarok.javaparser ؛ استيراد com.sun.istack.internal.nullable ؛ استيراد java.lang.override ؛ مستخدم الفئة العامة {nullable private string foo = "123123" ؛ Private Foo A ؛ public void usermethod () {} static class foo {private string fooString = "123123" ؛ الفراغ العام foomethod () {}}}نتيجة تنفيذ Javaparser أعلاه هي كما يلي:
المتغير: foo ، annotaion: nullablevariable الاسم: foo ، النوع: سلسلة ، النوع: متغير ، الحزمة: com.ragnarok.javaparserver الاسم: a ، النوع: النوع: المتغير ، الحزمة: com.ragnarok.javaparser
نحن هنا أولاً ، نستخدم الملف المصدر من خلال javacompiler.compilationTask ، ثم نستخدم المصدر المخصص (الموروث من Treescanner) للوصول إلى بنية الكود المصدري. في فئة SourceVisitor ، نقوم بإفراط في تحميل VisitVariable لتحليل وحدة التجميع (ملف رمز مصدر واحد) والوصول إلى جميع المتغيرات. يمكن ملاحظة هنا أنه لا يمكننا الحصول على الاسم المؤهل تمامًا لهذا النوع المتغير (بما في ذلك اسم الحزمة) ، ويمكننا الحصول على الاسم البسيط المقابل فقط. لذلك ، يتطلب تحديد النوع تنفيذًا خارجيًا لتحديده بنفسه. على سبيل المثال ، يمكنك تسجيل اسم الحزمة التي يوجد بها الفصل ، والبحث بشكل متكرر في دليل رمز المصدر بأكمله لتتبع الاسم المؤهل بالكامل لجميع الفئات ، والعثور على ما إذا كان الاستيراد يحتوي على النوع المقابل ، إلخ.
بالإضافة إلى طريقة VisitVariable ، يحتوي Treescanner أيضًا على عدد كبير من أساليب VisitXyz الأخرى. على سبيل المثال ، يمكنك اجتياز جميع الواردات ، وتعريفات الأسلوب ، والشرح ، وما إلى ذلك ، لمزيد من تحديد ، يمكنك عرض الكود المصدري حول هذا في OpenJDK.
سنأخذ مثالًا آخر هنا ، مع زيادة تحميل طريقة VisitClass للوصول إلى جميع الفئات الداخلية والفئة نفسها:
Overridepublic void visitClass (classtree node ، void تجنب) {formatptrln ("اسم الفئة: ٪ s" ، node.getSimplename ()) ؛ لـ (عضو الشجرة: node.getMembers ()) {if (extry extaryof variabletree) {variabletree variable = (variabletree) member ؛ قائمة <!-؟ يمتد annotationTree-> التعليقات التوضيحية = variable.getModifiers (). getAnnotations () ؛ if (enrotations.size ()> 0) {formatptrln ("المتغير: ٪ s ، annotaion: ٪ s" ، variable.getName () ، enrotations.get (0) .getAnnotationType ()) ؛ } آخر {formatptrln ("المتغير: ٪ s" ، variable.getName ()) ؛ }}} return super.visitClass (Node ، تجنب) ؛ }نحن هنا ببساطة طباعة اسم الفصل والاسم المتغير ، النوع ، ونوع التعليقات التوضيحية. تنفيذ الرمز أعلاه ، والنتيجة هي كما يلي:
اسم الفصل: USEVARAIBLE: FOO ، annotaion: Nullablevariable: اسم الفصل: foovariable: foostring
يمكن ملاحظة أننا قمنا بطباعة اسم الفصل والمتغيرات في الفصل. في طريقة VisitClass ، يمكننا الحصول على جميع أعضاء الفصل من خلال طريقة GetMembers ، بما في ذلك المتغيرات والأساليب والشرح ، وما إلى ذلك ، والتي تتوافق مع أنواع مختلفة. على سبيل المثال ، تتوافق المتغيرات مع نوع variobletree ، والطريقة تتوافق مع نوع MethodTree.
بشكل عام ، على الرغم من أن الاستخدام ليس معقدًا بشكل خاص في الواقع ، إلا أنه تسبب في استخدام عقبات كبيرة بسبب عدم وجود توثيق. وما نقدمه هو جزء صغير فقط من واجهة برمجة التطبيقات هذه. سأستمر في دراسة الوظائف ذات الصلة لهذا API في المستقبل.
ما سبق هو عبارة عن مجموعة من بيانات محلل JDK لتحليل رمز المصدر Java. سنستمر في إضافة المعلومات ذات الصلة في المستقبل. شكرا لك على دعمك لهذا الموقع!