【问题标题】:How to get a jclass in JNI from class residing in an OSGi bundle如何从驻留在 OSGi 包中的类中获取 JNI 中的 jclass
【发布时间】:2012-12-26 09:28:23
【问题描述】:

在 C/C++ 中,您需要一个 jclass 值才能使用声明为 native 的方法将本机函数注册到 Java 类。

考虑这个 Java 类:

public class Native {
  public native int f(int i);
}

要为Native.f() 注册一个本地 C/C++ 函数,我们需要在 C++ 端调用它:

JNIEnv* env = ...;
jclass nativeClass = ...;

JNINativeMethod nativeMethod = {
  (char*) "f",
  (char*) "(I)I",
  (void*) Java_org_example_Native_f // The native C function
};

env->RegisterNatives(nativeClass, &nativeMethod, 1);

如果无法从默认类加载器访问该类,则有问题的部分是获取 jclass 值。如果 Native 类驻留在加载在 JVM 内运行的 OSGi 容器(例如 Equinox)内的 OSGi 包中,则情况并非如此。

为了访问该类,我使用 Java 函数返回我的类的 Class<?> 实例:

public class Helper {
  public static Class<?> getNativeClass() {
    // Find bundle from system bundle context.
    Bundle bundle = ... // details left out.

    return bundle.loadClass("org.example.Native");
  }
}

此函数驻留在 OSGi 容器外部的类中。使用 JNI 从 C++ 端调用这个函数会给我们一个jobject,它是java.lang.Class&lt;&gt; 的一个实例。

// Load the `Helper` class.
jclass helperClass = env->FindClass("org.example.Helper");

// Get the method `Helper.getNativeClass()`.
jmethodId mid = env->GetStaticMethodID(helperClass,
                                       "getNativeClass",
                                       "()Ljava/lang/Class;");

// Call `Helper.getNativeClass()`.
jobject nativeClassInstance = env->CallStaticObjectMethod(helperClass, mid);

问题是我们确实需要一个“jclass”值(不是jobject 值)。为了得到它,我实例化了我的Native 类的一个对象并从中获取jclass

// This is the jclass for 'java.lang.Class<>'.
jclass classClass = env->GetObjectClass(nativeClassInstance);

// Now get the method id for function 'newInstance()'
jmethodId newInstanceMid = env->GetMethodID(helperClass,
                                            "newInstance",
                                            "()Ljava/lang/Object;");

// Instantiate our 'Native' class calling 'Class<Native>.newInstance()'.
jobject nativeInstance = env->CallObjectMethod(classClass,
                                               nativeClassInstance,
                                               newInstanceMid);

// Now, I can get the desired 'jclass' of my 'Native' class.
jclass nativeClass = env->GetObjectClass(nativeInstance);

但这只是因为我可以实例化我的Native 类。

任何想法如何获得所需的jclass 而不必实例化Native 类的对象?

【问题讨论】:

  • 我不明白这个问题。如果类有本地方法,只要在正常的Java执行过程中加载它,就会导致其静态初始化方法中的System.loadLibrary()调用被执行,这将自动注册自己的本地函数。你为什么要从头到尾这样做?
  • @EJP 因为我有一个静态链接的 C++ 服务器(跨平台,包括 Win32),我想在其中嵌入一个 JVM(并且在该 JVM 中我需要运行 OSGi)。在 Win32 中,混合静态和动态链接的 C/C++ 运行时库并不是一个好主意,因此我的本机实现需要静态链接到 C++ 应用程序。

标签: java c++ java-native-interface osgi


【解决方案1】:

您应该能够使用由您的辅助方法返回的Class&lt;Native&gt; 类型的jobject 作为jclass,只需强制转换即可:

jclass nativeClass = (jclass)nativeClassInstance;

【讨论】:

  • 简单得令人尴尬:-)。我没有意识到jclass 只是jobject 的子类——就像jstring 一样。我也尝试使用dynamic_cast&lt;jclass&gt;(...)(在阅读了您的回复后),但意识到jobjectjclass 不是多态的,因为(出于效率原因,我猜)没有虚拟方法,甚至没有析构函数。
【解决方案2】:

如果您不需要在包中定义本机代码存根,则有一种更简单的方法。

将本机代码放入 JVM 类路径中的类中。 启动捆绑包时使用org.osgi.framework.system.packages.extra=package.in.jvm。现在,您可以从您的 OSGi 包中获得该软件包,并且您可以在链接它们后调用您的本机函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-16
    • 1970-01-01
    相关资源
    最近更新 更多