加载具有本机代码依赖性的Java类

时间:2009-12-29 14:59:45

标签: java classloader

我正在编写一个程序来加载指定文件夹中的所有类。

有些类在静态块中创建对象,而这些对象又在创建过程中进行一些本机调用。由于我没有本机库,我看到了java.lang.UnsatisfiedLinkError

以下是一个示例场景。

Class A extends SuperA
{
  public static B b = new B(); 
  ...
  ...
}

Class B
{
   public B()
   {
      someNativeCall(); // Causing the LinkError
   }
}

Class.forName("A"); // Loading of Class A

我在这里加载A类来检查它的一些属性,比如它的Super Classes等。所以我甚至不在乎是否创建了B :) 既然在给定的文件夹中可以有很多像A这样的类,那么是否有一种通用的方法可以确保像A这样的类的加载不会失败?

更新:我知道本地库需要存在以及如何添加它。但我没有本地库,因此我要求这个黑客。

5 个答案:

答案 0 :(得分:3)

实现本机功能的.DLL或.so需要位于系统路径上。 VM将调用loadlibrary来加载相关的.dll / .so,如果找不到,它将抛出UnsatisfiedLinkError。

您可以捕获UnsatisfiedLinkError以忽略该问题,但您将无法使用依赖于它的类。

如果要检查类但不实际使用它们,可以使用Java Dissasembeler, javap。您可以以编程方式访问所需的功能 - javap在包sun.tools.javap中定义,实现在$ JDK \ lib \ tools.jar

答案 1 :(得分:2)

有一个Class.forName的重载,它允许你指定是否要初始化类(如果你只是想稍微反映一下,你就不会这样做):

class X {

    static { if (true) throw new ExceptionInInitializerError("OH NOES!!!"); }

}

public class Y {
    public static void main(String[] args) throws Throwable{
        // Breaks:
        System.out.println(Class.forName("X").getSuperclass());
        // Works:
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        System.out.println(Class.forName("X", false, cl).getSuperclass());
    }
}

答案 2 :(得分:1)

您必须修改A以使其不再依赖于B,否则修改B以使其不再依赖本机代码,或者替换B。

具体来说,您可以使用自定义ClassLoader并手动加载您自己的B版本,该版本与提供的版本不同,因为它没有任何本机依赖项。然后在同一个ClassLoader中加载A,然后按照自己的意愿执行操作。

答案 3 :(得分:1)

也许您可以编写生成,编译和加载缺少的本机库的模拟版本?看起来好像很多工作。

答案 4 :(得分:0)

为什么没有本机库的课程?如果无法初始化基类,则派生类将不起作用。使用-Djava.library.path指定本机库的位置。