迁移至Java 9使用GeoTools遇DatumFactory非ImageIO SPI类异常求助
DatumFactory is not an ImageIO SPI class异常 这个问题我之前帮团队排查过,本质是Java 9引入的模块系统(JPMS)对SPI加载的权限控制变严格,和GeoTools的工厂注册机制冲突导致的——即使升级到GeoTools 19.x/20.x,也需要额外配置才能解决,下面是具体的解决步骤:
1. 确保GeoTools依赖版本完全一致
首先检查你的项目依赖,确保所有GeoTools相关的artifact(比如gt-referencing、gt-main等)都升级到同一版本的Java 9兼容版(19.x及以上),混合不同版本的GeoTools依赖很容易引发SPI加载异常。
2. 添加JVM启动参数解决权限问题
Java 9的ServiceRegistry对ImageIO相关的SPI类做了强制检查,而GeoTools的FactoryRegistry继承了这个类却用来加载OGC标准的工厂类(比如DatumFactory),这就触发了权限检查失败。你需要添加以下JVM参数来绕过这个限制:
--add-modules java.se.ee --add-opens java.desktop/javax.imageio.spi=ALL-UNNAMED
--add-modules java.se.ee:Java 9拆分了部分EE模块,GeoTools需要用到这些模块里的类;--add-opens java.desktop/javax.imageio.spi=ALL-UNNAMED:允许未命名模块(大多数非模块化项目都属于这个范畴)访问ImageIO的SPI包,让GeoTools的工厂注册机制正常工作。
如果是用Maven exec插件运行项目,可以这样配置:
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>3.1.0</version> <configuration> <mainClass>your.package.MainClass</mainClass> <arguments> <argument>--add-modules</argument> <argument>java.se.ee</argument> <argument>--add-opens</argument> <argument>java.desktop/javax.imageio.spi=ALL-UNNAMED</argument> </arguments> </configuration> </plugin>
3. 模块化项目额外配置(如果用了JPMS)
如果你的项目是基于Java模块系统开发的(有module-info.java),还需要:
- 在
module-info.java中声明对GeoTools模块的依赖,比如:module your.module.name { requires transitive org.geotools.referencing; requires transitive org.geotools.main; // 允许GeoTools通过反射访问你的模块(如果需要) opens your.package.to.expose to org.geotools.referencing; } - 对于GeoTools的SPI类,需要用
uses声明:uses org.opengis.referencing.datum.DatumFactory;
原因解释
Java 9之前的SPI加载是基于类路径的,没有严格的权限检查;而JPMS引入后,javax.imageio.spi.ServiceRegistry新增了checkClassAllowed方法,强制要求注册的类必须是ImageIO相关的SPI类。GeoTools的FactoryRegistry继承了这个类,但用来加载OGC标准的地理空间工厂类,自然触发了IllegalArgumentException。GeoTools 19.x虽然做了适配,但无法绕过JPMS的权限限制,所以必须通过JVM参数或模块配置来解决。
内容的提问来源于stack exchange,提问作者Gent

