简体   繁体   English

如何使用 GraalVM 从 C++ 调用具有非原始类型作为参数的 Java 入口点方法

[英]How to call a Java entrypoint method with non-primitive types as parameters from C++ using GraalVM

I am trying to create a shared library(dll with header and lib files) of a java code using graalvm.我正在尝试使用 graalvm 创建 Java 代码的共享库(带有头文件和 lib 文件的 dll)。

there will be one java method with 2 parameters of type String which I will call from c++.将有一个带有 2 个 String 类型参数的 java 方法,我将从 C++ 调用它。

I am using a maven project, I am not able to create the dll out of my java code, I am using graalvm to convert my java code to dll.我正在使用一个 Maven 项目,我无法从我的 java 代码中创建 dll,我正在使用 graalvm 将我的 java 代码转换为 dll。

My java code looks like this:我的 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;
    }

but when I try to build the code into dll, I got this error但是当我尝试将代码构建到 dll 中时,我收到了这个错误

Error: Entry point method parameter types are restricted to primitive types, word types and enumerations (@CEnum): demo.MyClass.myFunc(IsolateThread, String, String)错误:入口点方法参数类型仅限于原始类型、单词类型和枚举(@CEnum):demo.MyClass.myFunc(IsolateThread, String, String)

I searched but didn't find suitable solutions to this problem.我进行了搜索,但没有找到解决此问题的合适方法。 can anyone here please tell me how to call java methods from c++ with non-primitive datatypes any suggestions of any kind will be a great help, thanks in advance这里的任何人都可以告诉我如何使用非原始数据类型从 C++ 调用 java 方法任何类型的任何建议都会有很大帮助,在此先感谢

There are specific preconditions that the a java method needs to fulfill in order to be successfully run from C or C++ in GraalVM.为了在 GraalVM 中从 C 或 C++ 成功运行 java 方法需要满足特定的先决条件。 These should also be taken into account when designing the Java entry point methods that are going to be annotated with @CEntryPoint .在设计将使用@CEntryPoint注释的 Java 入口点方法时,也应该考虑这些。 The following preconditions are mentioned in the CEntryPoint documentation . CEntryPoint 文档中提到以下先决条件。

  1. The Java entry point method is only allowed to include primitive Java types, word values and enums. Java 入口点方法只允许包含原始 Java 类型、字值和枚举。 Also in order to actually use an Enum the enum class must have a CEnum annotation.同样为了实际使用Enumenum class必须有一个CEnum注释。 In the CEntryPoint documentation . 在 CEntryPoint 文档中
  2. The Java entry point method should be static. Java 入口点方法应该是静态的。
  3. The Java entry point method should catch all exceptions, since it should NOT throw ANY exception. Java 入口点方法应该捕获所有异常,因为它不应该抛出任何异常。 In case an exception is not caught, it is printed and then the process is terminated.如果未捕获异常,则打印异常,然后终止进程。 However the @CEntryPoint documentation explicitly mention to catch all exceptions inside the java entry point methods.但是, @CEntryPoint文档明确提到要捕获 java 入口点方法中的所有异常。
  4. An IsolateThread parameter is required.需要一个IsolateThread参数。 More precisely更确切地说

An execution context must be passed as a parameter and can be either an IsolateThread that is specific to the current thread, or an Isolate for an isolate in which the current thread is attached.执行上下文必须作为参数传递,并且可以是特定于当前线程的 IsolateThread,也可以是连接当前线程的隔离的 Isolate。 These pointers can be obtained via the methods of CurrentIsolate.这些指针可以通过 CurrentIsolate 的方法获得。 When there is more than one parameter of these types, exactly one of the parameters must be annotated with CEntryPoint.IsolateThreadContext for IsolateThread, or CEntryPoint.IsolateContext for Isolate.当这些类型的参数不止一个时,必须用 CEntryPoint.IsolateThreadContext 为 IsolateThread 或 CEntryPoint.IsolateContext 为 Isolate 对其中一个参数进行注释。

The sample in your question throws this error since the myFunc method signature includes objects, for instance the String parameters.您问题中的示例会引发此错误,因为myFunc方法签名包含对象,例如String参数。 Namely x and y .xy This is not allowed according to the precondition 1 from above.根据上述前提条件1 ,这是不允许的。 This is what the error description tries to say.这就是错误描述试图说明的内容。

The solution is to use the functionality provided to convert between Java types and C types.解决方案是使用提供的功能在 Java 类型和 C 类型之间进行转换。 In this case in order to pass text between C and Java we can use a CCharPointer .在这种情况下,为了在CJava之间传递文本,我们可以使用CCharPointer Since text is modeled differently in C and Java , a Java String must be converted to C *char and vice versa.由于文本在CJava建模不同,因此必须将Java String转换为C *char ,反之亦然。

Creating and returning a Java String创建并返回 Java 字符串

There is an example below that can be used when byte[] represents text.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;
         }
        
  }

Using and returning an array allocated in C使用和返回在 C 中分配的数组

You can also follow a C style and pass as an argument an array in C and then use this array to write the result byte values in Java.您也可以遵循 C 风格并将 C 中的数组作为参数传递,然后使用该数组在 Java 中写入结果字节值。 The method CCharPointer.write(int,byte) can write Java byte values to specific array indexes in the *char or char[] .方法CCharPointer.write(int,byte)可以将Java byte值写入*charchar[]中的特定数组索引。 The byte array can also be returned, if needed.如果需要,也可以返回字节数组。

@CEntryPoint(name = "myFunc2")
  public static CCharPointer myFunc2(IsolateThread thread
         , CCharPointer x, 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;
  }

Using a Java NIO ByteBuffer使用Java NIO ByteBuffer

For larger byte arrays you can check CTypeConversion that can create a Java NIO ByteBuffer with a specific capacity that refers to the native memory.对于更大的字节数组,您可以检查CTypeConversion ,它可以创建一个具有特定容量的Java NIO ByteBuffer ,该容量是指本机内存。 Note that注意

the caller is responsible for ensuring that the memory can be safely accessed while the ByteBuffer is used, and for freeing the memory afterwards.调用者负责确保在使用 ByteBuffer 时可以安全地访问内存,并在之后释放内存。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Java 8-如何处理非基本类型的数组? - Java 8 - how to process arrays of non-primitive types? 原始类型或非原始类型应该在Java接口中首选吗? - Should primitive types or non-primitive types be preferred in Java interfaces? 如何使用空指针将字节数组从 C 传递到 GraalVM 本机图像 Java 入口点? - How to pass byte array from C to GraalVM native-image Java entrypoint using a void pointer? Java:如何在Java Reflection中使用非原始类型的constructor.newInstance()? - Java: How to use non-primitive types for constructor.newInstance() in Java Reflection? 从线程返回时设置非基本类型 - Set non-primitive types when returning from thread 结合使用带有非原始参数的JNI的扩展c ++库 - Use extensive c++ library with JNI with non-primitive arguments Kotlin数据类型是基于原始或非原始Java数据类型构建的吗? - Are Kotlin data types built off primitive or non-primitive Java data types? 为非基本类型(类)定义包装器 - Define a Wrapper for non-primitive types(classes) 使用休眠过滤非基本类型 - Filtering non-primitive types with hibernate 如何使用 GraalVM 使用 CCharPointer 类型将 Java 字符串发布到 java 入口点方法? - How to post Java String to java entryPoint method with CCharPointer type using GraalVM?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM