非Android环境调用newTrustedTransport遇KeyStoreException:JKS实现未找到
我之前在IBM i环境中处理过类似的Google API兼容性问题,你的报错核心是IBM i的J9 JVM在JDK 1.6版本下默认不使用JKS作为密钥库类型,而Google的GoogleNetHttpTransport.newTrustedTransport()底层硬编码依赖了JKS实现,导致CL调用时抛出异常(本地JVM可能默认是JKS所以正常)。下面是分步解决方法:
一、明确问题根源
IBM i的JDK 1.6(J9)默认密钥库类型通常是PKCS12而非JKS,且java.security配置中可能未注册Sun的JKS Provider。Google的SecurityUtils.getJavaKeyStore()方法直接调用KeyStore.getInstance("JKS"),在IBM i环境中找不到对应实现,就会抛出KeyStoreException。
二、具体解决方案
1. 手动构建HttpTransport(最可靠的方法)
绕过Google提供的newTrustedTransport(),手动基于IBM i JVM支持的默认密钥库构建SSL传输:
import com.google.api.client.http.javanet.NetHttpTransport; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; import java.security.KeyStore; import java.security.SecureRandom; // 替换原来的GoogleNetHttpTransport.newTrustedTransport()调用 public static NetHttpTransport getCustomTransport() throws Exception { // 使用IBM i JVM默认的密钥库类型(通常是PKCS12) TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); // 加载系统默认信任库 ks.load(null, null); tmf.init(ks); SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, tmf.getTrustManagers(), new SecureRandom()); return new NetHttpTransport.Builder() .setSslSocketFactory(sslContext.getSocketFactory()) .build(); }
然后在你的代码中用getCustomTransport()替代原来的GoogleNetHttpTransport.newTrustedTransport()即可。
2. 确保Google API依赖兼容JDK 1.6
JDK 1.6已经非常老旧,高版本的Google API客户端不再支持它。你需要在Gradle中指定兼容的版本:
dependencies { // 必须使用1.32.x版本,这是支持JDK 1.6的最后一个大版本 implementation 'com.google.api-client:google-api-client:1.32.1' implementation 'com.google.oauth-client:google-oauth-client-jetty:1.32.1' implementation 'com.google.apis:google-api-services-sheets:v4-rev20220715-1.32.1' }
构建Jar包时务必确认依赖没有引入高版本的JDK 1.7+兼容类。
3. 通过CL命令指定JVM参数(临时适配)
如果不想修改代码,可以在CL的RUNJVA命令中添加JVM参数,强制指定密钥库类型和Provider:
RUNJVA CLASS(prueba.Principal) JAVAOPT('-Dkeystore.type=JKS' '-Djava.security.provider=com.ibm.crypto.provider.IBMJCE')
注意:IBM i的JVM可能需要使用IBM自带的JCE Provider,而非Sun的,所以这里用com.ibm.crypto.provider.IBMJCE,如果不行可以尝试sun.security.provider.Sun(需要确认JVM中包含该Provider)。
4. 验证JVM的安全Provider(调试用)
如果不确定JVM支持哪些Provider,可以在代码中添加调试打印:
import java.security.Security; import java.security.Provider; // 在程序开头添加 for (Provider provider : Security.getProviders()) { System.out.println("Provider: " + provider.getName() + " | Info: " + provider.getInfo()); }
运行后查看输出,确认是否有支持JKS的Provider存在。
三、总结
最推荐的方案是手动构建HttpTransport,既避免了Google API对JKS的硬编码依赖,又适配了IBM i的JVM环境。同时一定要确保使用兼容JDK 1.6的Google API版本,否则还会出现其他兼容性问题。
内容的提问来源于stack exchange,提问作者Jorge Burgos

