ตรวจสอบว่าไฟล์ JAR คลาสใดมาจาก


154

ฉันไม่ได้อยู่หน้า IDE ตอนนี้แค่ดูรายละเอียด API

CodeSource src = MyClass.class.getProtectionDomain().getCodeSource();
if (src != null) {
    URL jar = src.getLocation();
}

ฉันต้องการตรวจสอบไฟล์ JAR ว่าเป็นคลาสใด นี่เป็นวิธีที่จะทำหรือไม่


2
มีวิธีทำจากคอนโซลหรือไม่ สิ่งที่ชอบ->java -findjar -cp /some/path/with/libs/*.jar my.java.Class my.jar
kub1x

คำตอบ:


191

ใช่. มันใช้ได้กับทุกคลาสยกเว้นคลาสที่โหลดโดย bootstrap classloader วิธีอื่นในการพิจารณาคือ:

Class klass = String.class;
URL location = klass.getResource('/' + klass.getName().replace('.', '/') + ".class");

ในฐานะที่เป็น nonoop ชี้ให้เห็นklass.getResource()วิธีการส่งกลับสถานที่ตั้งของไฟล์คลาสตัวเอง ตัวอย่างเช่น:

jar:file:/jdk/jre/lib/rt.jar!/java/lang/String.class
file:/projects/classes/pkg/MyClass$1.class

getProtectionDomain().getCodeSource().getLocation()วิธีการส่งกลับที่ตั้งของไฟล์ขวดหรือ CLASSPATH ที่

file:/Users/home/java/libs/ejb3-persistence-1.0.2.GA.jar
file:/projects/classes

สิ่งนี้ทำให้สมมติฐานเกี่ยวกับการแม็พจากชื่อคลาสไปยังไฟล์คลาส มันจะทำงานได้อย่างถูกต้องสำหรับคลาสที่ไม่ระบุชื่อหรือไม่ คลาสที่ซ้อนกัน?
Thorbjørn Ravn Andersen

1
นี่ชี้ไปที่ url ของคลาสไม่ใช่ jar ต้องแยกวิเคราะห์ url เพื่อค้นหาไฟล์ jar
notnoop

@notnoop ฉันได้ชี้แจงคำตอบ
Chandra Patni

19
เป็นวิธีอื่น ๆ ตามที่เขียนไว้ในคำตอบใช้getProtectionDomain().getCodeSource().getLocation()ถ้าคุณต้องการรับตำแหน่งไฟล์ jar
peter

ขอบคุณสำหรับคำตอบนี้มันเป็นแรงบันดาลใจให้ฉันตอบคำถามนี้
kriegaex

12

เช็คเอาท์LiveInjector.findPathJar()จากลอมบอก LiveInjector.javaPatcher โปรดทราบว่าเป็นกรณีพิเศษที่ไฟล์ไม่ได้อยู่ในขวดจริงและคุณอาจต้องการเปลี่ยนแปลง

/**
 * If the provided class has been loaded from a jar file that is on the local file system, will find the absolute path to that jar file.
 * 
 * @param context The jar file that contained the class file that represents this class will be found. Specify {@code null} to let {@code LiveInjector}
 *                find its own jar.
 * @throws IllegalStateException If the specified class was loaded from a directory or in some other way (such as via HTTP, from a database, or some
 *                               other custom classloading device).
 */
public static String findPathJar(Class<?> context) throws IllegalStateException {
    if (context == null) context = LiveInjector.class;
    String rawName = context.getName();
    String classFileName;
    /* rawName is something like package.name.ContainingClass$ClassName. We need to turn this into ContainingClass$ClassName.class. */ {
        int idx = rawName.lastIndexOf('.');
        classFileName = (idx == -1 ? rawName : rawName.substring(idx+1)) + ".class";
    }

    String uri = context.getResource(classFileName).toString();
    if (uri.startsWith("file:")) throw new IllegalStateException("This class has been loaded from a directory and not from a jar file.");
    if (!uri.startsWith("jar:file:")) {
        int idx = uri.indexOf(':');
        String protocol = idx == -1 ? "(unknown)" : uri.substring(0, idx);
        throw new IllegalStateException("This class has been loaded remotely via the " + protocol +
                " protocol. Only loading from a jar on the local file system is supported.");
    }

    int idx = uri.indexOf('!');
    //As far as I know, the if statement below can't ever trigger, so it's more of a sanity check thing.
    if (idx == -1) throw new IllegalStateException("You appear to have loaded this class from a local jar file, but I can't make sense of the URL!");

    try {
        String fileName = URLDecoder.decode(uri.substring("jar:file:".length(), idx), Charset.defaultCharset().name());
        return new File(fileName).getAbsolutePath();
    } catch (UnsupportedEncodingException e) {
        throw new InternalError("default charset doesn't exist. Your VM is borked.");
    }
}

2
ดูเหมือนจะซับซ้อนเกินไปที่จะได้สิ่งที่ง่ายมาก ฉันเพิ่งนั่งลงและลองสิ่งที่ฉันพบก่อนหน้านี้และดูเหมือนว่าจะทำงาน แค่ต้องการการตรวจสอบบางอย่าง

ดี. รหัสของคุณไม่ได้จัดการไฟล์ในเส้นทาง bootclass และโซลูชันของ Chandra จะส่งคืน URL ไปที่ไฟล์ไม่ใช่ไฟล์ jar ดังนั้นคุณจะต้องแยกวิเคราะห์เส้นทางเพื่อค้นหาไฟล์ jar
notnoop

2

ใช้

String path = <Any of your class within the jar>.class.getProtectionDomain().getCodeSource().getLocation().getPath(); 

หากสิ่งนี้มีหลายรายการให้ทำการดำเนินการย่อยบางอย่าง


1
private String resourceLookup(String lookupResourceName) {



    try {

        if (lookupResourceName == null || lookupResourceName.length()==0) {
            return "";
        }
        // "/java/lang/String.class"

        // Check if entered data was in java class name format
        if (lookupResourceName.indexOf("/")==-1) {
            lookupResourceName = lookupResourceName.replaceAll("[.]", "/");
            lookupResourceName =  "/" + lookupResourceName + ".class";
        }

        URL url = this.getClass().getResource(lookupResourceName);
        if (url == null) {
            return("Unable to locate resource "+ lookupResourceName);

        }

        String resourceUrl = url.toExternalForm();

        Pattern pattern =
            Pattern.compile("(zip:|jar:file:/)(.*)!/(.*)", Pattern.CASE_INSENSITIVE);

        String jarFilename = null;
        String resourceFilename = null;
        Matcher m = pattern.matcher(resourceUrl);
        if (m.find()) {
            jarFilename = m.group(2);
            resourceFilename = m.group(3);
        } else {
            return "Unable to parse URL: "+ resourceUrl;

        }

        if (!jarFilename.startsWith("C:") ){
          jarFilename = "/"+jarFilename;  // make absolute path on Linux
        }

        File file = new File(jarFilename);
        Long jarSize=null;
        Date jarDate=null;
        Long resourceSize=null;
        Date resourceDate=null;
        if (file.exists() && file.isFile()) {

            jarSize = file.length();
            jarDate = new Date(file.lastModified());

            try {
                JarFile jarFile = new JarFile(file, false);
                ZipEntry entry = jarFile.getEntry(resourceFilename);
                resourceSize = entry.getSize();
                resourceDate = new Date(entry.getTime());
            } catch (Throwable e) {
                return ("Unable to open JAR" + jarFilename + "   "+resourceUrl +"\n"+e.getMessage());

            }

           return "\nresource: "+resourceFilename+"\njar: "+jarFilename + "  \nJarSize: " +jarSize+"  \nJarDate: " +jarDate.toString()+"  \nresourceSize: " +resourceSize+"  \nresourceDate: " +resourceDate.toString()+"\n";


        } else {
            return("Unable to load jar:" + jarFilename+ "  \nUrl: " +resourceUrl);

        }
    } catch (Exception e){
        return e.getMessage();
    }


}

รหัสด้านบนจะค้นหาทรัพยากรใด ๆ บนเส้นทาง หากใน Jar จะพบ jar พิมพ์ขนาด & วันที่ของ jar และขนาดและวันที่ของทรัพยากรภายใน jar
Don
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.