ค้นหาตำแหน่งที่โหลดคลาส java


184

ไม่มีใครรู้วิธีการหาโปรแกรมโดยที่ java classloader จริงโหลดคลาสจาก?

ฉันมักจะทำงานในโครงการขนาดใหญ่ที่ classpath ใช้เวลานานและการค้นหาด้วยตนเองไม่ใช่ตัวเลือกจริงๆ ฉันเพิ่งมีปัญหาที่ classloader กำลังโหลดรุ่นที่ไม่ถูกต้องของชั้นเพราะมันอยู่ใน classpath ในสองสถานที่ที่แตกต่างกัน

ดังนั้นฉันจะรับ classloader เพื่อบอกฉันว่าอยู่ที่ไหนบนดิสก์ไฟล์คลาสจริงมาจากไหน

แก้ไข:จะเกิดอะไรขึ้นถ้า classloader ไม่สามารถโหลดคลาสได้เนื่องจากมีเวอร์ชันที่ไม่ตรงกัน (หรืออย่างอื่น) มีอยู่หรือไม่เราสามารถค้นหาไฟล์ที่พยายามอ่านก่อนที่จะอ่านได้หรือไม่


4
@JarrodRoberson ฉันไม่คิดว่านี้ควรได้รับการพิจารณาซ้ำ stackoverflow.com/questions/11747833/... ตั้งแต่คำถามนี้ถูกถามในปี 2008 และคำถามที่ถูกถามในปี 2012
ลุค

คำตอบ:


189

นี่คือตัวอย่าง:

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

32
หากต้องการลดการพิมพ์ซ้ำซ้อนเราสามารถใช้เวอร์ชันที่สั้นกว่า: Test.class.getResource("Test.class")ซึ่งไม่ได้ทำซ้ำชื่อแพ็คเกจ
meriton

1
จะทำอย่างไรถ้าคอมไพล์มีคลาสเช่นจากไฟล์. groovy
Ondra Žižka

35
@meriton: หรือเพื่อเอาตัวรอด refactorinsgs:Test.class.getResource(Test.class.getSimpleName() + ".class")
leonbloy

1
สำหรับBouncyCastleProviderชื่อแพคเกจแบบเต็มจำเป็นต้องมีอย่างไรก็ตาม
Pavel Vlasov

3
มันเป็นไปได้สำหรับการกลับมาgetClassLoader() nullดูที่นี่สำหรับส่วนขยายของวิธีนี้เพื่อจัดการกับสิ่งนั้น
OldCurmudgeon

100

อีกวิธีในการค้นหาตำแหน่งที่โหลดคลาส (โดยไม่ต้องจัดการกับแหล่งที่มา) คือการเริ่มต้น Java VM ด้วยตัวเลือก: -verbose:class


6
สิ่งนี้ทำงานได้ดีมากและไม่มีปัญหาในการจัดการกับคลาสด้วย null ClassLoader
lexicalscope

2
@ries หากไม่ต้องการทำสิ่งนี้โดยทางโปรแกรมนี่เป็นหนทางที่แน่นอนและมันก็แก้ปัญหาของฉันได้ อย่างไรก็ตาม OP ได้ถามวิธีการทำสิ่งนี้โดยเฉพาะทางโปรแกรม
SantiBailors

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

4
ใช่แม้ว่ามันจะไม่ทำงานกับตัวจัดการความปลอดภัยที่ติดตั้งและไม่มีสิทธิ์ที่จำเป็น
Tom Hawtin - tackline

1
FYI, NPE = ข้อยกเว้นตัวชี้ Null HTH!
Evgeni Sergeev

วิธีนี้เป็นที่ต้องการตราบใดที่คุณมีการอ้างอิงไปยังอินสแตนซ์เนื่องจากคุณสามารถโหลดคลาสเดียวกันจากสถานที่ที่แตกต่างกันสองแห่ง
Miguel Ping

1
ยังใช้งานไม่ได้เมื่อถูกเรียกจากโมดูล Java 9+ (ซึ่งแน่นอนว่าคุณไม่รู้จักในปี 2008)
Jeff G

28

นี่คือสิ่งที่เราใช้:

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

สิ่งนี้จะทำงานได้ขึ้นอยู่กับการใช้งาน ClassLoader: getClass().getProtectionDomain().getCodeSource().getLocation()


17

รุ่นของจอนล้มเหลวเมื่อมีวัตถุที่ClassLoaderมีการลงทะเบียนเป็นซึ่งดูเหมือนว่าจะบ่งบอกว่ามันถูกโหลดโดยการบูตnullClassLoader

วิธีการนี้เกี่ยวข้องกับปัญหานั้น:

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";
}

5

แก้ไขเพียงบรรทัดแรก: 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/

สไตล์ที่ไม่ดี แต่ใช้งานได้ดี!


3

โดยทั่วไปแล้วเราจะไม่ใช้ hardcoding เราสามารถรับ className ก่อนจากนั้นใช้ ClassLoader เพื่อรับ URL ของชั้นเรียน

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

ต้องเป็น: URL classUrl = MyClass.class.getClassLoader (). getResource ("/" + className);
Andrew Coates

MyClass.class เป็นส่วนสำคัญ - getClass () สามารถคืนค่าพร็อกซีได้! จากนั้นคุณจะได้รับชื่อเช่น MyClass $$ EnhancerBySpringCGLIB $$ a98db882.class และ URL ที่ไม่ระบุ
jalmasi


1

วิธีง่าย ๆ :

System.out.println (java.lang.String.class.getResource (String.class.getSimpleName () + "ชั้น."));

ตัวอย่าง:

โถ: file: / D: /Java/jdk1.8/jre/lib/rt.jar /java/lang/String.class

หรือ

String obj = "การทดสอบอย่างง่าย"; System.out.println (obj.getClass () getResource (obj.getClass () getSimpleName () +).. "ชั้น.");

ตัวอย่าง:

โถ: file: / D: /Java/jdk1.8/jre/lib/rt.jar /java/lang/String.class


0

วิธีนี้ใช้ได้ทั้งไฟล์และไห:

Class clazz = Class.forName(nameOfClassYouWant);

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

-1

สมมติว่าคุณกำลังทำงานกับคลาสที่มีชื่อMyClassดังต่อไปนี้ควรใช้งานได้:

MyClass.class.getClassLoader();

คุณสามารถขอรับตำแหน่งบนดิสก์ของไฟล์. class หรือไม่นั้นขึ้นอยู่กับ classloader เอง ตัวอย่างเช่นหากคุณกำลังใช้บางสิ่งบางอย่างเช่น BCEL คลาสที่แน่นอนอาจไม่มีการแสดงบนดิสก์


ส่งคืน ClassLoader ที่ใช้สำหรับการโหลดคลาสใช่หรือไม่ ไม่พบว่าไฟล์. class อยู่ที่ไหน
Koray Tugay

1
ไม่มันไม่ classloader จริงสามารถ reffer ไปยังเส้นทางที่แตกต่างกันอย่างสิ้นเชิง - หมายความว่ามันจะไม่สามารถ reah ทั้งหมดที่ตั้งของชั้นเรียนจริง
Tomáš Zato - Reinstate Monica
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.