从JDK8升级到JDK17后,如何解决java.lang.IllegalAccessError X509CertReader错误?
升级后抛出如下错误:
java.lang.IllegalAccessError: class com.oracle.pic.commons.client.https.X509CertReader (in unnamed module @0x74582ff6) cannot access class sun.security.x509.X509CertImpl (in module java.base) because module java.base does not export sun.security.x509 to unnamed module @0x74582ff6
完整错误日志:
2023-06-02 11:51:30.778 INFO 9 --- [http-nio-9070-exec-1] c.oracle.pic.vault.InternalVaultClient : 202105 VaultJavaSdk: Going to refresh the certs now 2023-06-02 11:51:30.786 INFO 9 --- [http-nio-9070-exec-1] c.o.p.c.c.http.OracleHttpClientBuilder : DynamicSslContextProviderConfig is not configured. Attempting to use tlsConfig 2023-06-02 11:51:30.861 INFO 9 --- [http-nio-9070-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.IllegalAccessError: class com.oracle.pic.commons.client.https.X509CertReader (in unnamed module @0x74582ff6) cannot access class sun.security.x509.X509CertImpl (in module java.base) because module java.base does not export sun.security.x509 to unnamed module @0x74582ff6] with root cause java.lang.IllegalAccessError: class com.oracle.pic.commons.client.https.X509CertReader (in unnamed module @0x74582ff6) cannot access class sun.security.x509.X509CertImpl (in module java.base) because module java.base does not export sun.security.x509 to unnamed module @0x74582ff6 at com.oracle.pic.commons.client.https.X509CertReader.fromPem(X509CertReader.java:81) at com.oracle.pic.commons.client.https.X509CertReader.readCertificatesFromPem(X509CertReader.java:41) at com.oracle.pic.commons.client.http.auth.KeystoreGenerator.createTrustStoreWithServerCa(KeystoreGenerator.java:48) at com.oracle.pic.commons.client.http.auth.TlsConfigurator.configureClientTrustStore(TlsConfigurator.java:85) at com.oracle.pic.commons.client.http.auth.TlsConfigurator.customizeBuilder(TlsConfigurator.java:55) at
临时缓解方案:添加JVM参数开放模块访问
JDK9+引入模块系统后,sun.security.x509属于java.base模块的内部API,默认不对外暴露。可通过添加JVM启动参数强制开放访问:
--add-exports java.base/sun.security.x509=ALL-UNNAMED
如果使用Maven插件运行项目(如spring-boot-maven-plugin),需在插件配置中添加jvm参数:
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <jvmArguments>--add-exports java.base/sun.security.x509=ALL-UNNAMED</jvmArguments> </configuration> </plugin>
长期修复方案
1. 更新Oracle PIC依赖包
检查所用Oracle PIC相关SDK(如VaultJavaSdk)是否有适配JDK17的新版本。官方通常会在新版本中替换对JDK内部API的依赖,改用标准Java API实现证书读取逻辑。
2. 替换内部API调用(若有权限修改代码)
如果可以修改X509CertReader类代码,将依赖sun.security.x509.X509CertImpl的逻辑替换为标准Java安全API,示例代码:
import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.io.ByteArrayInputStream; import java.util.Base64; public static X509Certificate fromPem(String pem) throws Exception { // 清理PEM格式的头部、尾部及空白字符 String cleanPem = pem.replace("-----BEGIN CERTIFICATE-----", "") .replace("-----END CERTIFICATE-----", "") .replaceAll("\\s+", ""); byte[] certBytes = Base64.getDecoder().decode(cleanPem); CertificateFactory cf = CertificateFactory.getInstance("X.509"); return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(certBytes)); }
该实现完全基于标准API,无需依赖JDK内部类,兼容JDK8至JDK17及更高版本。
内容的提问来源于stack exchange,提问作者Rohit Agrawal

