لقاء مع الشبح: ما هو "unrecognized Attribute name MODULE"؟
\nهل سبق لك أن رأيت خطأً ينبعث منه الغموض؟ تخيل: أنت تكتب بلغة Kotlin الحديثة، كل شيء يعمل بسلاسة، وGradle يدندن، وفجأة - بام! - يظهر في السجلات شيء مثل:
\nunrecognized Attribute name MODULE (class com.sun.tools.javac.util.SharedNameTable$NameImpl)\nتبحث في Google، تجد Stack Overflow بآلاف المشاهدات، وتفهم: هذا ليس مجرد خطأ. إنه خطأ توافق بين العوالم. بين Java و Kotlin. بين نظام البناء القديم والعالم المعياري الجديد.
\nفي هذه المقالة، لن نقدم الحل فقط. سننظر تحت غطاء مترجم Java، ونحلل ما هو SharedNameTable، ولماذا JVM يعترض على كلمة MODULE، وكيف يرتبط ذلك بمشروع Kotlin الخاص بك. تنبيه: المذنب ليس Kotlin، بل Gradle القديم وJava 9+.
باختصار: كيفية الإصلاح (لغير الصبورين)
\nإذا كنت بحاجة ماسة لإصلاح البناء - إليك ثلاث طرق عملية. اختر حسب حالتك:
\n- \n
- الطريقة 1 (موصى بها): قم بتحديث Gradle إلى الإصدار 7.0+ و إضافة Kotlin Gradle إلى 1.5+. سيحل هذا المشكلة نهائياً. \n
- الطريقة 2 (حل سريع): حدد بوضوح هدف JVM في
build.gradle.kts: \n
kotlin {\n jvmToolchain(11) // أو 8 إذا كنت تريد التوافق القديم\n}\n- \n
- الطريقة 3 (حل مؤقت): أضف علامة للمترجم: \n
tasks.withType<KotlinCompile> {\n kotlinOptions {\n jvmTarget = "1.8"\n }\n}\nولكن إذا كنت تريد فهم لماذا يعمل هذا - تابع القراءة. سنغوص في أعماق مترجم Java.
\n\nتحت الغطاء: ما هو com.sun.tools.javac.util.SharedNameTable$NameImpl؟
\nدعنا نحلل هذا السطر المخيف جزءاً جزءاً. إنها ليست مجرد مجموعة عشوائية من الكلمات - إنها إشارة إلى فئة محددة داخل مجموعة تطوير Java (JDK).
\n- \n
com.sun.tools.javac- حزمة مترجم Java الداخلي (javac). نعم، ذلك الذي يحول.javaإلى.class. \n util.SharedNameTable- فئة خدمية تخزن الأسماء (المتغيرات، الدوال، الفئات) في مجموعة سلاسل للتحسين. إنها ذاكرة تخزين مؤقت لتجنب إنشاء ملايين السلاسل المتطابقة. \n $NameImpl- فئة داخلية تمثل اسماً محدداً. عندما يواجه المترجم كلمةmodule، يقوم بإنشاء كائنNameImpl. \n
والآن الجزء الأكثر إثارة للاهتمام: يحدث الخطأ عندما يصادف javac سمة MODULE في ملف class، لكنه لا يعرف ماذا يفعل بها. يحدث هذا إذا كنت تستخدم مترجماً قديماً (< Java 9) أو، على العكس، مترجماً جديداً ولكن بصيغة ملفات class قديمة.
\n\nلماذا MODULE كلمة خاصة؟
\nابتداءً من Java 9، ظهر في اللغة نظام الوحدات (Project Jigsaw). أصبحت الكلمة المحجوزة module محجوزة. ظهرت في ملفات class سمات جديدة مثل Module و ModulePackages و ModuleMainClass وغيرها.
عندما يقوم مترجم Kotlin بتوليد البايت كود، قد يضيف هذه السمة بشكل عشوائي (أو متعمد) إذا كان هدف JVM الخاص بك مضبوطاً على 9+. أما Gradle القديم أو Maven، باستخدام إصدار قديم من javac، فلا يفهم هذه السمات. ومن هنا يأتي الخطأ.
\n\nمثال واقعي: Kotlin + Gradle + Java 11
\nتخيل مشروع Kotlin بسيطاً على Gradle. إليك ملف build.gradle.kts:
plugins {\n kotlin("jvm") version