使用本地代码依赖项加载Java类

3
我正在编写一个程序,它从指定的文件夹加载所有类。其中一些类在静态块中创建对象,并且这些对象在创建过程中进行了一些本地调用。由于我没有本地库,因此我会看到 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

我在这里加载Class A来检查它的一些属性,比如它的超类等。所以我并不关心B是否被创建了 :) 由于在给定文件夹中可能有许多像A这样的类,有没有一种通用的方法来确保像A这样的类的加载不会失败?
更新:我知道需要存在本地库以及如何添加它。但是我没有本地库,因此正在寻求此解决方案。

在运行时,我们能够识别所有类,比如B,并注入mock B对象吗?虽然我不知道实现的方法。 - Varun
请参见http://stackoverflow.com/questions/1029559/java-system-loadlibrarysomedllfile-gets-unstatisfied-link-error。 - finnw
我实现的解决方案是:可以通过编程方式访问javap,但API并不是非常清晰。最终使用了http://jakarta.apache.org/bcel/manual.html,它有类似于Java反射的清晰API。 - Varun
5个回答

3
实现本地函数的.DLL或.SO文件需要在系统路径中。虚拟机将调用loadlibrary加载相关的.dll/.so文件,如果找不到它会抛出UnsatisfiedLinkError。
您可以捕获UnsatisfiedLinkError以忽略问题,但无法使用依赖它的类。
如果您想检查类但实际上不使用它们,可以使用Java Dissasembeler, javap。您可能能够以编程方式访问所需的功能-javap定义在sun.tools.javap包中,实现在$JDK\lib\tools.jar中。

1
请注意,它不一定需要在系统路径中,只需要在JVM路径中即可。请参阅上面提到的Java启动标志。 - whatnick
我没有本地库。由于我不想运行应用程序,只需要加载一堆类,所以我正在寻找一种方法。 - Varun
1
@whatnick 说得很正确 - 你可以使用任何一种方法 - 不过在存在多个库版本的情况下,使用 java.library.path 更加具体/安全。 - Robert Christie
1
@Varun - 我更新了答案,加入了一些参考资料,可能可以满足你的需求。 - Robert Christie
@cb160 非常感谢。能够以编程方式访问反汇编器的功能将为我提供所需的解决方案。 - Varun

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

谢谢。我不知道这个API。这个完全可以正常运行 :) - Varun

1

你需要修改A,使其不再依赖B,或者修改B,使其不再依赖本地代码,或者替换B。

具体来说,你可以使用自定义的ClassLoader手动加载与提供的版本不同且没有任何本地依赖关系的B。然后在同一个ClassLoader中加载A并对其进行操作。


@Dan 很有趣。你能进一步解释一下吗? - Varun

1
也许你可以编写代码生成器,编译并加载缺失的本地库的模拟版本?不过这似乎需要很多工作。

0
为什么你的类没有本地库?如果基类无法初始化,派生类将无法工作。请使用-Djava.library.path指定本地库的位置。

这里的整个问题就在于本地库无法使用。如果可以使用,我就会添加它 :) - Varun
本地库的目的是什么,也许可以用类似的东西替代它吗? - Esko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接