GIS-gdal-java.lang.NoSuchMethodError
背景概述
这段时间使用gdal的时候,出现了一个找不到方法的的问题,具体报错内容如下:
java.lang.NoSuchMethodError: 'int org.gdal.gdal.Dataset.FlushCache()'at it.geosolutions.imageio.gdalframework.GDALImageWriter.write(GDALImageWriter.java:357)
问题解决
通过定位,这个错误是Dataset报出来的,我们知道对GDAL的调用最终要走到native,具体方法定义下:
// Dataset 中的方法public void FlushCache() {gdalJNI.Dataset_FlushCache(swigCPtr, this);}
// native 方法
public final static native void Dataset_FlushCache(long jarg1, Dataset jarg1_);
我们可以看到,它最终是要去调用一个void的方法。由于我本地用的gdal是3.9.0
ldd /usr/lib/x86_64-linux-gnu/libgdalalljni.so | grep gdal
# 结果为 libgdal.so.39 或 libgdal.so.3.9.x
在3.9的时候c++的方法FlushCache的返回值已经被修改了,返回的是一个int ,这样在调用的时候JVM 在链接 JNI 方法时发现签名不匹配,我需要的是一个void方法,找到的确实一个int,我没有int方法与之匹配,所以就爆出了上面这个错误。
这里可能存在一些误解,我们可能会认为难道不是应该报错java.lang.NoSuchMethodError: ‘void org.gdal.gdal.Dataset.FlushCache()’ 因为是这个方法找不到,这里的机制不是这样的,我们看下面的对应关系:
| 层级 | 版本 | FlushCache() 定义 | 返回类型 |
|---|---|---|---|
Java 层 (gdal.jar) | 3.2.0 | public native void FlushCache(); | void |
底 层 (libgdalalljni.so) | 3.9.0 | JNIEXPORT void JNICALL Java_org_gdal_gdal_Dataset_FlushCache | int |
当 JVM 加载 gdal.jar 时,这个类有个:
void org.gdal.gdal.Dataset.FlushCache()
gdalJNI 是一个java类,里面定义对应的native方法,也就是去c++找一个void 的方法:
public final static native void Dataset_FlushCache(long jarg1, Dataset jarg1_);
但是我们在最终的c++层面libgdalalljni.so中只有int 类型方法,我们JVM层没有对应的int org.gdal.gdal.Dataset.FlushCache() 与之对应,所以报错java.lang.NoSuchMethodError: ‘int org.gdal.gdal.Dataset.FlushCache()’,所以这里是以底层为准。
