2011-02-17 85 views
0

我正在使用命令行应用程序在运行时加载用户指定的文本翻译器(通过命令行参数提供的类文件路径/ jar)。基本上我采取了这一论点,并用它来创建一个URLClassLoader。然后,我需要找到可用于实现Transable接口的URLClassloader的所有类。Java,获得实现特定接口的URLClassLoader的所有类

现在我只允许这个命令行arg是一个包含类文件的目录。使解决方案非常简单(下面的代码)。但老实说,我不喜欢解决方案,因为它打破了jar文件,jar文件的目录等等。另外,这对于具有定义的包的任何类来说都是明显的失败,因为loadClass需要包含包的全名。任何人都有更好的方法?

File d = new File(path); 
    if(d.isDirectory()) { 
     URL url = d.toURI().toURL(); 
     ClassLoader cl = new URLClassLoader(new URL[]{url}); 

     FilenameFilter filter = new FilenameFilter() { 
      @Override 
      public boolean accept(File dir, String name) { 
       return name.endsWith(".class"); 
      } 
     }; 

     for(File f : d.listFiles(filter)) { 
      String name = f.getName().substring(0, f.getName().indexOf(".")); 
      String key = ""; 
      if(name.endsWith("Translator")) { 
       key = name.substring(0, name.indexOf("Translator")); 
      } 
      else if(name.endsWith("translator")) { 
       key = name.substring(0, name.indexOf("translator")); 
      } 
      else 
       key = name; 

      Class c = cl.loadClass(name); 
      if(Transable.class.isAssignableFrom(c)) { 
       Transable t = (Transable)c.newInstance(); 
       env.registerTranslator(key, t); 
      } 
      else { 
       System.out.println("[ClassLoader] "+c.getCanonicalName()+" will not be loaded. It is not a translator class"); 
      } 
     } 
    } 
    else { 
     throw new Error("NOT IMPLEMENTED"); 
    } 
+0

只需进入jar文件并检查所有条目。 – irreputable 2011-02-17 00:32:17

回答

3

如果你继续沿着这条路走下去,你可能只需要暴力。据我所知,默认的类加载器甚至不会将类加载到JVM中,除非它以某种方式被引用。这意味着,除非你知道他们完全合格的类名来加载它们,否则你的一些类基本上是不可见的。

您可能想重新考虑您的要求。因为加载一组您已被授予类名称的译员将更加容易。

+0

我正在考虑将其中的一些内容移到一个需要显式名称的配置文件,或者至少是包含翻译器类的包的名称。它是一个更好的方法,我只是想确保其他选项不能先清理干净。 – jdc0589 2011-02-17 00:14:56

+0

@ jdc0589 JAR和本地文件有解决方案,但AFAIK不是任何类加载器的通用解决方案。 – biziclop 2011-02-17 00:18:18

+0

照顾详细?我只关心本地文件和本地文件夹 – jdc0589 2011-02-17 03:45:23

0

这会有帮助吗?

由于类c = cl.loadClass(name);

类方法getInterfaces()返回的类

检查匹配翻译类名每个类名称的数组。

3

原则上这不适用于任意类加载器,因为它们可能以任何可以想象的方式实际加载类,并且根本没有任何“目录监听”函数。

类加载器甚至可能产生在飞行类(即字节代码的类)每当loadClass来了,和想象TransableClassloader每个这样的自动定义的类将实现你的界面 - 你的程序将永远不会结束。


这就是说,对于一个URLClassloader您可以使用getURLs(),并为jar:file: URL可以使用JarFileFile API来获取文件名列表(因此类名)来尝试。由于您拥有URL中给出的包层次结构的根目录,因此找到正确的包名并不困难。

(如果你需要更多的细节,说出来。)


编辑:对于包名,它们对应于您的层次结构内的目录名。所以,当你有一个对应于(说)dir/classes的基础URL,并找到一个名为dir/classes/com/company/gui/SimpleTranslator.class的类文件时,它对应于类com.company.gui.SimpleTranslator

因此,删除基地前缀并将/替换.(并剪切.class)。 (在JarFile中,您不必删除前缀)

实际上,如果您使用递归方法来遍历文件层次结构,则可以使用相同的方法构建包名,只需通过追加字符串(给他们作为参数传递给下一个递归调用):

public void searchClassesInDir(File dir, String packagePrefix) { 
    if(dir.isDirectory()) { 
     String prefix = packagePrefix + dir.getName() + "."; 
     for(File f : dir.listFiles()) { 
      searchClasses(f, prefix); 
     } 
    } 
    else { 
     String fileName = dir.getName(); 
     if(! fileName.endsWith(".class")) 
      return; 
     String className = packagePrefix + fileName.substring(0, fileName.length()-".class".length()); 
     // now do the rest of your processing 
    } 
} 

searchClasses(new File(url.toURI()), ""); 
4

而是明确地寻找实现者,你应该USS Java的服务提供者接口(SPI)和ServiceLoader类(在Java 6中引入)。 SPI是一种非常标准的方式来执行您在Java中描述的内容。

关于如何创建服务提供者以及如何在运行时使用ServiceLoader,请参阅official Java tutorial

相关问题