2009-12-31 7 views
113

Al momento non sono di fronte a un IDE, ma solo alle specifiche API.Determina quale file JAR è una classe da

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

Voglio determinare da quale file JAR appartiene una classe. È questo il modo di farlo?

+0

C'è un modo per fare questo da console? Qualcosa come 'java -findjar -cp /some/path/with/libs/*.jar my.java.Class' ->' my.jar'. – kub1x

risposta

148

Sì. Funziona su tutte le classi tranne le classi caricate dal programma di caricamento di classe bootstrap. L'altro modo per determinare è:

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

Come notnoop sottolineato getProtectionDomain().getCodeSource().getLocation() metodo restituisce la posizione del file classe stessa. Per esempio:

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

Il metodo klass.getResource() restituisce la posizione del file jar o CLASSPATH

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

Questo rende le ipotesi sopra il mapping dal nome della classe al file di classe. Funzionerà correttamente per le classi anonime? Classi annidate? –

+1

Ciò indica l'url della classe e non il jar stesso. L'URL deve essere analizzato per trovare il file jar. – notnoop

+0

@notnoop. Ho chiarito la risposta. –

11

Checkout il LiveInjector.findPathJar() da Lombok Patcher LiveInjector.java. Si noti che si tratta di casi speciali in cui il file non risiede in un barattolo e potrebbe essere necessario cambiarlo.

/** 
* 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

Questo sembra troppo complicato per ottenere qualcosa di molto semplice. Mi sono seduto e ho provato quello che ho trovato prima, e sembra funzionare. Volevo solo qualche convalida. –

+0

Bene. Il tuo codice non gestisce i file nei percorsi bootclass e la soluzione di Chandra restituisce l'url al file non al file jar, quindi dovrai analizzare il percorso per trovare il file jar. – notnoop

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


} 
+0

Il codice sopra troverà qualsiasi risorsa sul percorso. Se in un barattolo troverai il barattolo stampare la dimensione e la data del barattolo e le dimensioni e la data della risorsa all'interno del barattolo – Don

Problemi correlati