我想容器化一个 SpringBoot 应用程序并使用 gdal。 为此,我在我的 pom.xml
中使用<dependency>
<groupId>org.gdal</groupId>
<artifactId>gdal</artifactId>
<version>3.8.0</version>
</dependency>
和
FROM osgeo/gdal:ubuntu-full-3.6.3
在Dockerfile中。
但是看起来 org.gdal 引用了一个不存在的常量。我稍后会描述它。但首先是源代码的关键部分:
Dockerfile:
FROM maven:3.9.5-amazoncorretto-21 as build
WORKDIR /app
COPY target/converter-service-1.0.0-SNAPSHOT.jar app.jar
RUN mkdir -p target/extracted
RUN java -Djarmode=layertools -jar app.jar extract --destination target/extracted
FROM osgeo/gdal:ubuntu-full-3.6.3
ENV GDAL_DATA="/usr/share/gdal"
ENV GDAL_DRIVER_PATH="/usr/lib/x86_64-linux-gnu/gdalplugins"
ENV PROJ_LIB="/usr/share/proj"
ENV PATH="/usr/share/gdal:${PATH}"
WORKDIR app
RUN apt update && apt install -y openjdk-21-jre-headless
ARG EXTRACTED=/app/target/extracted
COPY --from=build ${EXTRACTED}/dependencies/ ./
COPY --from=build ${EXTRACTED}/spring-boot-loader/ ./
COPY --from=build ${EXTRACTED}/snapshot-dependencies/ ./
COPY --from=build ${EXTRACTED}/application/ ./
ENTRYPOINT ["java", "-Djava.library.path=/usr/share/java/", "org.springframework.boot.loader.launch.JarLauncher" ]
Java代码
package my;
import org.springframework.stereotype.Service;
import org.gdal.gdal.gdal;
import org.gdal.gdalconst.gdalconstConstants;
...
@Service
public class Grib2ToGeoTiffService {
static {
gdal.AllRegister();
}
@PostConstruct
private void postConstruct() {
convert(
ResourceUtils.getFile("classpath:file.grib2"),
new File("/tmp/output")
);
}
public boolean convert(File gribFile, File geotiffOutputDir) throws Exception {
if (!gribFile.exists()) {
log.error("File does not exist: '{}'", gribFile.getAbsolutePath());
return false;
}
var gribType = getGribType(gribFile.getName());
log.info("Grib type '{}' for '{}'", gribType, gribFile.getName());
Dataset dataset = gdal.Open(gribFile.getAbsolutePath(), gdalconstConstants.GA_ReadOnly);
if (dataset == null) {
log.warn("Unable to open file: " + gribFile.getAbsolutePath());
return false;
}
int bandCount = dataset.getRasterCount();
Map<String, Settings> settingsMap = getSettingsMap(gribType);
for (int bandId = 1; bandId <= bandCount; bandId++) {
if (settingsMap.containsKey(Integer.toString(bandId))) {
processBand(dataset, bandId, geotiffOutputDir, gribType, settingsMap);
}
}
dataset.delete();
return true;
}
}
应用程序在容器中运行后出现以下错误:
Caused by: java.lang.UnsatisfiedLinkError: 'int org.gdal.gdalconst.gdalconstJNI.GDT_Int8_get()'
at org.gdal.gdalconst.gdalconstJNI.GDT_Int8_get(Native Method) ~[gdal-3.8.0.jar:na]
at org.gdal.gdalconst.gdalconstConstants.<clinit>(gdalconstConstants.java:14) ~[gdal-3.8.0.jar:na]
at my.service.Grib2ToGeoTiffService.convert(Grib2ToGeoTiffService.java:121) ~[classes/:1.0.0-SNAPSHOT]
...
代码中对应的行是:
Dataset dataset = gdal.Open(gribFile.getAbsolutePath(), gdalconstConstants.GA_ReadOnly);
我从正在运行的容器中导出了gdal.h,但找不到常量。 以下是该文件的摘录,其中定义了常量:
...
/*! Pixel data types */
typedef enum
{
/*! Unknown or unspecified type */ GDT_Unknown = 0,
/*! Eight bit unsigned integer */ GDT_Byte = 1,
/*! Sixteen bit unsigned integer */ GDT_UInt16 = 2,
/*! Sixteen bit signed integer */ GDT_Int16 = 3,
/*! Thirty two bit unsigned integer */ GDT_UInt32 = 4,
/*! Thirty two bit signed integer */ GDT_Int32 = 5,
/*! 64 bit unsigned integer (GDAL >= 3.5)*/ GDT_UInt64 = 12,
/*! 64 bit signed integer (GDAL >= 3.5)*/ GDT_Int64 = 13,
/*! Thirty two bit floating point */ GDT_Float32 = 6,
/*! Sixty four bit floating point */ GDT_Float64 = 7,
/*! Complex Int16 */ GDT_CInt16 = 8,
/*! Complex Int32 */ GDT_CInt32 = 9,
/* TODO?(#6879): GDT_CInt64 */
/*! Complex Float32 */ GDT_CFloat32 = 10,
/*! Complex Float64 */ GDT_CFloat64 = 11,
GDT_TypeCount = 14 /* maximum type # + 1 */
} GDALDataType;
...
导致错误的原因是什么?也许
<dependency>
<groupId>org.gdal</groupId>
<artifactId>gdal</artifactId>
<version>3.8.0</version>
</dependency>
和
FROM osgeo/gdal:ubuntu-full-3.6.3
不兼容还是我做错了什么?
在互联网上进行一些研究后,我发现了讨论: https://openradar.discourse.group/t/attributeerror-module-osgeo-gdalconst-has-no-attribute-gdt-int8/333
该常量似乎出现在3.7版本中
所以我将 JNI 库降级为:
<dependency>
<groupId>org.gdal</groupId>
<artifactId>gdal</artifactId>
<version>3.6.0</version>
</dependency>
有问题的java代码此后开始工作。