سؤال

لا أحد يعرف كيفية العثور programmaticly من حيث classloader جافا يحمل فعلا الفئة من؟

وأنا غالبا ما تعمل على مشاريع كبيرة حيث يحصل CLASSPATH طويلة جدا والبحث اليدوي ليست في الحقيقة خيارا. وقد أتيحت لي مؤخرا مشكلة حيث classloader وتحميل إصدار غير صحيح ل الطبقة لأنه كان على CLASSPATH في مكانين مختلفين.

ولكن كيف يمكنني الحصول على classloader ليقول لي مكان على القرص ملف فئة الفعلي يأتي من؟

على تحرير: ما، هناك حوالي إذا فشل classloader فعلا لتحميل الفصل الدراسي نظرا لعدم تطابق إصدار (أو أي شيء آخر) على أي حال يمكن أن نجد ما ملف في محاولة لقراءة قبل أن يقرأ عليه؟

هل كانت مفيدة؟

المحلول

وهنا مثال:

package foo;

public class Test
{
    public static void main(String[] args)
    {
        ClassLoader loader = Test.class.getClassLoader();
        System.out.println(loader.getResource("foo/Test.class"));
    }
}

وهذا طباعتها:

file:/C:/Users/Jon/Test/foo/Test.class

نصائح أخرى

وهناك طريقة أخرى لمعرفة أين يتم تحميل فئة من (دون التلاعب المصدر) ومن المقرر أن يبدأ جافا VM مع خيار: -verbose:class

getClass().getProtectionDomain().getCodeSource().getLocation();

وهذا هو ما نستخدمه:

public static String getClassResource(Class<?> klass) {
  return klass.getClassLoader().getResource(
     klass.getName().replace('.', '/') + ".class").toString();
}

وهذا سيعمل اعتمادا على تنفيذ ClassLoader: getClass().getProtectionDomain().getCodeSource().getLocation()

ونسخة جون لفشل عندما يتم تسجيل ClassLoader الكائن كما null التي يبدو انها تعني أن تم تحميله من قبل ClassLoader التمهيد.

وهذه الطريقة يتعامل مع هذه المسألة:

public static String whereFrom(Object o) {
  if ( o == null ) {
    return null;
  }
  Class<?> c = o.getClass();
  ClassLoader loader = c.getClassLoader();
  if ( loader == null ) {
    // Try the bootstrap classloader - obtained from the ultimate parent of the System Class Loader.
    loader = ClassLoader.getSystemClassLoader();
    while ( loader != null && loader.getParent() != null ) {
      loader = loader.getParent();
    }
  }
  if (loader != null) {
    String name = c.getCanonicalName();
    URL resource = loader.getResource(name.replace(".", "/") + ".class");
    if ( resource != null ) {
      return resource.toString();
    }
  }
  return "Unknown";
}

وتحرير فقط 1 السطر: Main.class

Class<?> c = Main.class;
String path = c.getResource(c.getSimpleName() + ".class").getPath().replace(c.getSimpleName() + ".class", "");

System.out.println(path);

وإخراج:

/C:/Users/Test/bin/

وربما سيئة نمط ولكن يعمل بشكل جيد!

ونلقي نظرة على هذا السؤال مماثل. <وأ href = "https://stackoverflow.com/questions/135971/is-there-a-tool-to-discover-if-the-same-class-exists-in-multiple-jars-in-the-cl # 136292 "> أداة لاكتشاف نفس الفئة ..

وأعتقد أن العقبة الأكثر أهمية هو إذا كان لديك classloader مخصصة (جاري من ديسيبل أو LDAP)

وعادة، نحن لا ما لاستخدام hardcoding. يمكننا الحصول على اسم_الفئة أولا، ثم استخدام ClassLoader للحصول على URL الصف.

        String className = MyClass.class.getName().replace(".", "/")+".class";
        URL classUrl  = MyClass.class.getClassLoader().getResource(className);
        String fullPath = classUrl==null ? null : classUrl.getPath();

وهذا النهج يعمل لكلا الملفين والجرار:

Class clazz = Class.forName(nameOfClassYouWant);

URL resourceUrl = clazz.getResource("/" + clazz.getCanonicalName().replace(".", "/") + ".class");
InputStream classStream = resourceUrl.openStream(); // load the bytecode, if you wish

وعلى افتراض أن كنت تعمل مع فئة المسمى MyClass، يجب أن تعمل ما يلي:

MyClass.class.getClassLoader();

وأم لا يمكنك الحصول على موقع على القرص من الملف. الطبقة تعتمد على classloader نفسها. على سبيل المثال، إذا كنت تستخدم شيئا مثل BCEL، فئة معينة قد لا يكون لها تمثيل على القرص.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top