Golang程序通过Java运行时出现IllegalArgumentException错误

Golang程序通过Java运行时出现IllegalArgumentException错误 我的Go代码如下:

package main

import "C"

//export MyFunc
func MyFunc(records []string) [][]string {
   records := make([][]string, 0)
   .
   .
   .
   return records
}

我需要通过Java Native Access运行这个Go文件。 对应的Java代码如下:

public Class MyClass {
    public interface MyInterface extends Library {
        String[][] MyFunc(String[] records);
    }

    static{
        MyObj = (MyClass) Native.loadLibrary("/path/to/so_file", MyClass.class);
    }
    
    public static void main(String[] args) {
        String[] strArray = {"abc1|HLJHSA|hgah","abc2|ksahd|","abc3|876987","abc4"};
        String[][] records1 = MyObj.MyFunc(strArray );
    }
}

我正确执行了所有步骤,但遇到了以下错误:

Exception in thread "main" java.lang.IllegalArgumentException: Unsupported return type class [[Ljava.lang.String; in function MyFunc
	at com.sun.jna.Function.invoke(Function.java:373)
	at com.sun.jna.Function.invoke(Function.java:223)
	at com.sun.jna.Library$Handler.invoke(Library.java:204)

我还尝试了: ArrayList<ArrayList> MyFunc(String[] records); 和 List<List> MyFunc(String[] records);

请帮我找到Java中 make([][]string, 0) 的正确等价形式。


更多关于Golang程序通过Java运行时出现IllegalArgumentException错误的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

我相当确定你无法做到这一点。你可以将一个指向Go结构的指针传递给cgo/JNI,但你不能传递一个本身包含指针的结构的指针。切片的切片包含指向指针的指针。我建议以某种格式(例如,JSON对你来说可行吗?)序列化数据,将其传递给Java,执行一些工作,序列化响应,然后将其返回给Go。

更多关于Golang程序通过Java运行时出现IllegalArgumentException错误的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


问题在于JNA不支持直接映射Go的二维字符串切片([][]string)到Java的二维字符串数组(String[][])。JNA对复杂类型的支持有限,需要手动处理内存布局。

以下是解决方案:

1. 修改Go代码,使用C兼容的类型:

package main

import "C"
import "unsafe"

//export MyFunc
func MyFunc(cRecords **C.char, length C.int) (unsafe.Pointer, C.int) {
    // 将C字符串数组转换为Go的[]string
    goRecords := make([]string, length)
    slice := (*[1 << 30]*C.char)(unsafe.Pointer(cRecords))[:length:length]
    for i := 0; i < int(length); i++ {
        goRecords[i] = C.GoString(slice[i])
    }
    
    // 你的业务逻辑
    result := make([][]string, 0)
    // ... 填充result ...
    
    // 转换为C兼容的格式
    // 首先分配一个指针数组
    cResult := C.malloc(C.size_t(len(result)) * C.size_t(unsafe.Sizeof(uintptr(0))))
    defer C.free(cResult)
    
    ptrs := (*[1 << 30]unsafe.Pointer)(cResult)[:len(result):len(result)]
    
    for i, row := range result {
        // 为每行分配字符串数组
        rowPtr := C.malloc(C.size_t(len(row)) * C.size_t(unsafe.Sizeof(uintptr(0))))
        strPtrs := (*[1 << 30]*C.char)(rowPtr)[:len(row):len(row)]
        
        for j, str := range row {
            strPtrs[j] = C.CString(str)
        }
        ptrs[i] = rowPtr
    }
    
    return cResult, C.int(len(result))
}

//export FreeResult
func FreeResult(ptr unsafe.Pointer, rows C.int) {
    ptrs := (*[1 << 30]unsafe.Pointer)(ptr)[:rows:rows]
    for i := 0; i < int(rows); i++ {
        C.free(ptrs[i])
    }
    C.free(ptr)
}

2. 修改Java代码:

import com.sun.jna.*;
import com.sun.jna.ptr.PointerByReference;

public class MyClass {
    public interface MyInterface extends Library {
        // 返回指针和行数
        PointerByReference MyFunc(String[] records, int length);
        int GetResultRows(PointerByReference result);
        String[] GetResultRow(PointerByReference result, int rowIndex);
        void FreeResult(PointerByReference result);
    }
    
    private static MyInterface MyObj;
    
    static {
        MyObj = (MyInterface) Native.loadLibrary("/path/to/so_file", MyInterface.class);
    }
    
    public static void main(String[] args) {
        String[] strArray = {"abc1|HLJHSA|hgah","abc2|ksahd|","abc3|876987","abc4"};
        
        // 调用Go函数
        PointerByReference result = MyObj.MyFunc(strArray, strArray.length);
        
        try {
            // 获取行数
            int rows = MyObj.GetResultRows(result);
            
            // 读取结果
            String[][] records1 = new String[rows][];
            for (int i = 0; i < rows; i++) {
                String[] row = MyObj.GetResultRow(result, i);
                records1[i] = row;
            }
            
            // 使用records1...
            
        } finally {
            // 释放内存
            MyObj.FreeResult(result);
        }
    }
}

3. 或者使用更简单的序列化方式(推荐):

// Go代码 - 使用JSON序列化
package main

import "C"
import "encoding/json"
import "unsafe"

//export MyFunc
func MyFunc(input *C.char) *C.char {
    // 解析输入
    goInput := C.GoString(input)
    var records []string
    json.Unmarshal([]byte(goInput), &records)
    
    // 业务逻辑
    result := make([][]string, 0)
    // ... 填充result ...
    
    // 序列化结果
    jsonResult, _ := json.Marshal(result)
    return C.CString(string(jsonResult))
}

//export FreeString
func FreeString(str *C.char) {
    C.free(unsafe.Pointer(str))
}
// Java代码 - 使用JSON
import com.sun.jna.*;
import com.google.gson.Gson;

public class MyClass {
    public interface MyInterface extends Library {
        Pointer MyFunc(String input);
        void FreeString(Pointer str);
    }
    
    private static MyInterface MyObj;
    private static final Gson gson = new Gson();
    
    static {
        MyObj = (MyInterface) Native.loadLibrary("/path/to/so_file", MyInterface.class);
    }
    
    public static void main(String[] args) {
        String[] strArray = {"abc1|HLJHSA|hgah","abc2|ksahd|","abc3|876987","abc4"};
        
        // 序列化输入
        String inputJson = gson.toJson(strArray);
        
        // 调用Go函数
        Pointer resultPtr = MyObj.MyFunc(inputJson);
        
        try {
            // 获取结果字符串
            String resultJson = resultPtr.getString(0);
            
            // 反序列化结果
            String[][] records1 = gson.fromJson(resultJson, String[][].class);
            
            // 使用records1...
            
        } finally {
            MyObj.FreeString(resultPtr);
        }
    }
}

JSON序列化方案更简单,避免了复杂的内存管理问题。

回到顶部