Quarkus Native(GraalVM)下ElasticSearch Java客户端JsonProviderImpl缺失异常
Quarkus Native模式下Elasticsearch Java客户端找不到Parsson JsonProviderImpl的问题
环境
- Quarkus 2.16.6.Final
- Elasticsearch 8.7
- GraalVM Native镜像模式
核心代码
UpdateByQuery实现
try (Reader query = new StringReader(/*my json query String*/)) { var request = UpdateByQueryRequest.of(fn -> fn.index(index).withJson(query)); return client.updateByQuery(request); } catch (IOException e) { throw new RuntimeException(e); }
Elasticsearch客户端初始化
var credsProv = new BasicCredentialsProvider(); credsProv.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password)); var restClient = RestClient.builder(HttpHost.create(host)).setHttpClientConfigCallback( hc -> hc.disableAuthCaching().setDefaultCredentialsProvider(credsProv)).build(); var transport = new RestClientTransport(restClient, new JacksonJsonpMapper()); var client = new ElasticsearchAsyncClient(transport);
异常信息
Caused by: jakarta.json.JsonException: Provider org.eclipse.parsson.JsonProviderImpl not found at jakarta.json.spi.JsonProvider.newInstance(JsonProvider.java:160) at jakarta.json.spi.JsonProvider.provider(JsonProvider.java:144) at co.elastic.clients.json.JsonpUtils.findProvider(JsonpUtils.java:65) ... 54 more Caused by: java.lang.ClassNotFoundException: org.eclipse.parsson.JsonProviderImpl at java.base@17.0.7/java.lang.Class.forName(DynamicHub.java:1132) at java.base@17.0.7/java.lang.Class.forName(DynamicHub.java:1105) at jakarta.json.spi.JsonProvider.newInstance(JsonProvider.java:157)
Maven依赖配置
<dependency> <groupId>co.elastic.clients</groupId> <artifactId>elasticsearch-java</artifactId> <version>8.7.0</version> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> <exclusion> <groupId>jakarta.json</groupId> <artifactId>jakarta.json-api</artifactId> </exclusion> <exclusion> <groupId>org.eclipse.parsson</groupId> <artifactId>parsson</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>jakarta.json</groupId> <artifactId>jakarta.json-api</artifactId> <version>2.1.1</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.eclipse.parsson</groupId> <artifactId>parsson</artifactId> <version>1.1.1</version> <scope>compile</scope> </dependency>
问题
代码在常规JVM模式下运行正常,但GraalVM Native模式执行时抛出上述异常,已按要求添加依赖但问题未解决。
解决方案
1. 显式注册SPI实现
GraalVM原生镜像不会自动扫描SPI配置,需手动注册:
- 在项目
src/main/resources/META-INF/services目录下创建jakarta.json.spi.JsonProvider文件 - 文件内容仅一行:
org.eclipse.parsson.JsonProviderImpl
2. 使用Quarkus官方Elasticsearch扩展(推荐)
Quarkus的扩展会自动处理原生镜像兼容性,无需手动配置SPI和反射:
- 添加依赖:
<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-elasticsearch-rest-client</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-elasticsearch-java-client</artifactId> </dependency>
- 注入客户端替代手动初始化:
@Inject ElasticsearchAsyncClient client;
3. 手动配置GraalVM反射元数据
若坚持手动初始化客户端,需添加反射配置文件:
- 在
src/main/resources/META-INF/native-image目录下创建reflect-config.json - 内容如下:
[ { "name": "org.eclipse.parsson.JsonProviderImpl", "allDeclaredConstructors": true, "allPublicConstructors": true, "allDeclaredMethods": true, "allPublicMethods": true, "allDeclaredFields": true, "allPublicFields": true } ]
原因分析
常规JVM在运行时通过SPI机制自动发现META-INF/services中的配置,加载JsonProvider实现;而GraalVM原生镜像在构建阶段就完成了类的静态打包,不会在运行时动态扫描SPI,因此必须提前告知需要包含这些类。
内容的提问来源于stack exchange,提问作者Abhinab Kanrar
相关产品推荐
相关产品推荐

