Bir sınıfın hangi JAR dosyasından geldiğini belirleme


154

Şu anda bir IDE'nin önünde değilim, sadece API özelliklerine bakıyorum.

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

Bir sınıfın hangi JAR dosyasından olduğunu belirlemek istiyorum. Bunu yapmanın yolu bu mu?


2
Bunu konsoldan yapmanın bir yolu var mı? Gibi bir şey java -findjar -cp /some/path/with/libs/*.jar my.java.Class-> my.jar.
kub1x

Yanıtlar:


191

Evet. Bootstrap classloader tarafından yüklenen sınıflar hariç tüm sınıflar için çalışır. Bunu belirlemenin diğer yolu:

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

Notnoop'un işaret ettiği gibi klass.getResource()yöntem, sınıf dosyasının kendisini döndürür. Örneğin:

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

getProtectionDomain().getCodeSource().getLocation()Yöntem kavanoz dosya veya CLASSPATH'e konumunu döndürür

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

Bu, sınıf adından sınıf dosyasına eşleme varsayımlarını yapar. Anonim sınıflar için düzgün çalışır mı? İç içe dersler?
Thorbjørn Ravn Andersen

1
Bu, kavanozun kendisini değil, sınıfın url'sini gösterir. Jar dosyasını bulmak için url'nin ayrıştırılması gerekir.
notnoop

@notnoop. Cevabı açıkladım.
Chandra Patni

19
Cevapta yazıldığı gibi tam getProtectionDomain().getCodeSource().getLocation()
peter

Bu yanıt için teşekkürler, bu cevap bana ilham bu soruyu .
kriegaex

12

Ödemeye LiveInjector.findPathJar()gelen Lombok yamalıLiveInjector.java . Dosyanın gerçekten bir kavanozda yaşamadığı özel durumları ve bunu değiştirmek isteyebileceğinizi unutmayın.

/**
 * 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
Bu çok basit bir şey elde etmek için aşırı karmaşık görünüyor. Daha önce oturup bulduklarımı denedim ve işe yarıyor gibi görünüyor. Biraz doğrulama istedim.

İyi. Kodunuz bootclass yollarındaki dosyaları işlemez ve Chandra'nın çözümü URL'yi jar dosyasına değil dosyaya döndürür, bu nedenle jar dosyasını bulmak için yolu ayrıştırmanız gerekir.
notnoop

2

kullanım

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

Bu birden çok giriş içeriyorsa, bazı alt dize işlemleri yapın.


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();
    }


}

Yukarıdaki kod yoldaki herhangi bir kaynağı bulacaktır. Bir Kavanozda kavanoz bulacaksa, kavanozun boyutunu ve tarihini ve kavanozun içindeki kaynağın boyutunu ve tarihini yazdırın
Don
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.