问题描述
我正在尝试使用graalvm创建Java代码的共享库(带有标头和lib文件的dll)。
会有一个带有2个String类型参数的Java方法,我将从c ++调用
。我正在使用Maven项目,无法使用Java代码创建dll,而是使用graalvm将Java代码转换为dll。
我的Java代码如下:
package demo;
import org.graalvm.nativeimage.IsolateThread;
import org.graalvm.nativeimage.c.function.CEntryPoint;
public class MyClass{
@CEntryPoint (name = "myFunc")
public static byte[] myfunc(IsolateThread thread,String x,String y) {
// logic goes here
byte[] arr = "byte array will contain actual bytes".getBytes();
return arr;
}
错误:入口点方法参数类型仅限于基本类型,单词类型和枚举(@CEnum):demo.MyClass.myFunc(IsolateThread,String,String)
我进行了搜索,但没有找到适合该问题的解决方案。 有人可以告诉我如何使用非原始数据类型从c ++调用Java方法 任何形式的建议都会对您有所帮助
解决方法
要在GraalVM中从C或C ++成功运行Java方法,必须满足一些特定的先决条件。
在设计将用@CEntryPoint
注释的Java入口点方法时,也应考虑这些因素。 in the CEntryPoint documentation中提到了以下前提条件。
- Java入口点方法仅允许包含原始Java类型,单词值和枚举。同样,为了实际使用
Enum
,enum class
必须具有CEnum
注释。In the CEntryPoint documentation。 - Java入口点方法应该是静态的。
- Java入口点方法应捕获所有异常,因为它不应引发任何异常。如果未捕获到异常,则将其打印,然后终止该过程。但是
@CEntryPoint
文档明确提到要捕获Java入口点方法内部的所有异常。 - 需要
IsolateThread
参数。更精确地
必须将执行上下文作为参数传递,并且可以是 特定于当前线程的IsolateThread或Isolate 用于连接当前线程的隔离。这些指针 可以通过CurrentIsolate的方法获得。当还有更多 而不是这些类型的一个参数,则其中一个参数必须 用CEntryPoint.IsolateThreadContext注释IsolateThread, 或CEntryPoint.IsolateContext进行隔离。
您的问题中的示例引发此错误,因为myFunc
方法签名包括对象,例如String
参数。即x
和y
。根据上面的前提 1 ,不允许这样做。这就是错误描述要说的。
解决方案是使用提供的功能在Java类型和C类型之间进行转换。在这种情况下,为了在C
和Java
之间传递文本,我们可以使用CCharPointer
。由于文本在C
和Java
中的建模方式不同,因此必须将Java String
转换为C *char
,反之亦然。
创建并返回Java字符串
下面有一个示例,当byte[]
表示文本时即可使用。
//These are the imports needed
import org.graalvm.nativeimage.c.type.CCharPointer;
import org.graalvm.nativeimage.c.type.CTypeConversion;
@CEntryPoint(name = "myFunc")
public static CCharPointer myFunc(IsolateThread thread,CCharPointer x,CCharPointer y) {
//Convert C *char to Java String
final String xString= CTypeConversion.toJavaString(x);
final String yString= CTypeConversion.toJavaString(y);
//logic goes here
//Convert Java String to C *char
try(final CTypeConversion.CCharPointerHolder holder=CTypeConversion.toCString("Hello from Java")){
final CCharPointer result=holder.get();
return result;
}
}
使用并返回在C中分配的数组
您还可以遵循C样式并将C中的数组作为参数传递,然后使用该数组在Java中写入结果字节值。方法CCharPointer.write(int,byte)可以将Java byte
的值写入*char
或char[]
中的特定数组索引。如果需要,也可以返回字节数组。
@CEntryPoint(name = "myFunc2")
public static CCharPointer myFunc2(IsolateThread thread,CCharPointer y,CCharPointer resultArray,int resultArrayLength) {
//Convert C *char to Java String
final String xString= CTypeConversion.toJavaString(x);
final String yString= CTypeConversion.toJavaString(y);
//logic goes here
//Fill in the result array
final byte sampleByteValue=7;
for(int index =0; index<resultArrayLength; index++){
resultArray.write(index,sampleByteValue);
}
return resultArray;
}
对于较大的字节数组,您可以检查CTypeConversion,以创建具有特定容量的Java NIO ByteBuffer
,该容量引用本地内存。请注意
调用方负责确保可以安全存储 在使用ByteBuffer时访问,并用于释放内存 之后。