【发布时间】:2020-04-13 10:30:42
【问题描述】:
我正在尝试将我的代码从 Java 8 移动到 Java 11,这段代码...
private static String readMultiHttpsUrlResultAsString(List<String> mbRecordingIds, String level) throws Exception
{
String result = "";
class NaiveTrustStrategy implements TrustStrategy
{
@Override
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException
{
return true;
}
};
SSLContext sslcontext = org.apache.http.ssl.SSLContexts.custom()
.loadTrustMaterial(new NaiveTrustStrategy())
.build();
CloseableHttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(new SSLConnectionSocketFactory(sslcontext))
.build();
StringBuilder sb = new StringBuilder("?recording_ids=");
for(String next:mbRecordingIds)
{
sb.append(next + ";");
}
sb.setLength(sb.length() - 1);
try
{
String url = "https://acousticbrainz.org/api/v1"+level+sb;
HttpGet httpget = new HttpGet(url);
try (CloseableHttpResponse response = httpclient.execute(httpget);)
{
int statusCode = response.getStatusLine().getStatusCode();
if(statusCode!=HttpURLConnection.HTTP_OK)
{
return "";
}
HttpEntity entity = response.getEntity();
result = EntityUtils.toString(entity);
EntityUtils.consume(entity);
}
}
finally
{
httpclient.close();
}
return result;
}
}
在 MacOS 上使用 (AdoptOpenJdk) Java 11.0.6 失败,
SSLContext sslcontext = org.apache.http.ssl.SSLContexts.custom()
.loadTrustMaterial(new NaiveTrustStrategy())
.build();
它在 Windows 上运行没有问题(也使用 AdoptOpenJdk Java 11.0.6)。一个区别是 Windows 版本使用从带有 jlink 的 jdk 构建的缩减 jre,而 MacOS 版本使用 AdoptOpenJDk jre 构建。 MacOS 版本是使用 AppBundler 的 InfiniteKinds 分支创建的
这是堆栈跟踪:
java.lang.NoClassDefFoundError: Could not initialize class sun.security.ssl.SSLContextImpl$TLSContext
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:315)
at java.base/java.security.Provider$Service.getImplClass(Provider.java:1848)
at java.base/java.security.Provider$Service.newInstance(Provider.java:1824)
at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:236)
at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:164)
at java.base/javax.net.ssl.SSLContext.getInstance(SSLContext.java:168)
at org.apache.http.ssl.SSLContextBuilder.build(SSLContextBuilder.java:269)
at com.jthink.songkong.analyse.acousticbrainz.AcousticBrainz.readMultiHttpsUrlResultAsString(AcousticBrainz.java:409)
at com.jthink.songkong.analyse.acousticbrainz.AcousticBrainz.readLowLevelData(AcousticBrainz.java:373)
我正在使用 Apache Httpclient 4.5.3 并使用此库,因为我从需要使用 ssl 的 Web 服务获取数据。
更新
我从下面的答案中将示例测试添加到我的源代码中,并修改了我的构建以在应用程序运行时使其成为启动类,它给了我这个堆栈跟踪(当使用 java 运行时使用open 从命令行运行包时由infinitekind appbundler嵌入到包中)
Exception in thread "main" java.lang.ExceptionInInitializerError
at java.base/javax.crypto.Cipher.getInstance(Unknown Source)
at java.base/sun.security.ssl.JsseJce.getCipher(Unknown Source)
at java.base/sun.security.ssl.SSLCipher.isTransformationAvailable(Unknown Source)
at java.base/sun.security.ssl.SSLCipher.<init>(Unknown Source)
at java.base/sun.security.ssl.SSLCipher.<clinit>(Unknown Source)
at java.base/sun.security.ssl.CipherSuite.<clinit>(Unknown Source)
at java.base/sun.security.ssl.SSLContextImpl.getApplicableSupportedCipherSuites(Unknown Source)
at java.base/sun.security.ssl.SSLContextImpl$AbstractTLSContext.<clinit>(Unknown Source)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Unknown Source)
at java.base/java.security.Provider$Service.getImplClass(Unknown Source)
at java.base/java.security.Provider$Service.newInstance(Unknown Source)
at java.base/sun.security.jca.GetInstance.getInstance(Unknown Source)
at java.base/sun.security.jca.GetInstance.getInstance(Unknown Source)
at java.base/javax.net.ssl.SSLContext.getInstance(Unknown Source)
at org.apache.http.ssl.SSLContextBuilder.build(SSLContextBuilder.java:389)
at Example.main(Example.java:23)
Caused by: java.lang.SecurityException: Can not initialize cryptographic mechanism
at java.base/javax.crypto.JceSecurity.<clinit>(Unknown Source)
... 17 more
Caused by: java.lang.SecurityException: Can't read cryptographic policy directory: unlimited
at java.base/javax.crypto.JceSecurity.setupJurisdictionPolicies(Unknown Source)
at java.base/javax.crypto.JceSecurity$1.run(Unknown Source)
at java.base/javax.crypto.JceSecurity$1.run(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Native Method)
... 18 more
这与我以前的不同,但也许这是根本原因还是误导?
而如果我只是运行 java -jar songkong6.9.jar 它会运行 Example 并打印出 Loaded 而没有错误,如果我从 /Library/Java 指定完整路径它也适用于所有情况(Java 11/ Java 14/JDK 和 JRE)
更新 根据下面的答案,我已经取得了一些进展。
MacOS 上安装的 JRE 包含一个 conf 文件夹,当使用 InfiniteKinds appbundler 将 JRE 添加到我的包 (SongKong) 时,它没有 conf 文件夹。它确实有一个包含default.policy 的 lib/security 文件夹,但这似乎还不够。
pauls-Mac-mini:Home paul$ ls -lR lib/security
total 704
-rw-r--r-- 1 paul admin 1253 22 Apr 14:56 blacklisted.certs
-rw-r--r-- 1 paul admin 103147 22 Apr 14:56 cacerts
-rw-r--r-- 1 paul admin 8979 22 Apr 16:01 default.policy
-rw-r--r-- 1 paul admin 233897 22 Apr 14:56 public_suffix_list.dat
如果我手动将 conf 文件夹从已安装的 JRE 复制到 java 插件的主文件夹,则在安装构建的捆绑包后
例如
/Applications/SongKong.app/Contents/PlugIns/adoptopenjdk-11.jre/Contents/Home
location 那么示例代码和我的原始代码在从 bundle 运行时都可以正常工作。
此外,它似乎在寻找的是无限文件夹及其内容(这两个文件实际上是相同的),所以如果我删除了一些文件,那么我就剩下了
pauls-Mac-mini:Home paul$ pwd
/Applications/SongKong.app/Contents/PlugIns/adoptopenjdk-11.jre/Contents/Home
pauls-Mac-mini:Home paul$ ls -lR conf
total 0
drwxr-xr-x 3 paul admin 96 22 Apr 15:14 security
conf/security:
total 0
drwxr-xr-x 3 paul admin 96 22 Apr 15:22 policy
conf/security/policy:
total 0
drwxr-xr-x 4 paul admin 128 22 Apr 15:28 unlimited
conf/security/policy/unlimited:
total 16
-rw-r--r-- 1 paul admin 146 22 Apr 15:06 default_US_export.policy
-rw-r--r-- 1 paul admin 193 22 Apr 15:06 default_local.policy
然后它继续工作。
问题(除了它为什么不能开箱即用)是我假设我无法将文件复制到此位置以用于强化运行时应用程序,因此我需要将这些策略文件存储在其他地方以便它们可以作为一部分安装应用捆绑器构建。因此,作为测试,我重命名了 conf 文件夹 conf.old 文件夹并将以下参数添加到包中
<string>-Djava.security.policy=/Applications/SongKong.app/Contents/PlugIns/adoptopenjdk-11.jre/Contents/Home/conf.old/security/policy/unlimited/default_local.policy</string>
或替换而不是附加策略文件
<string>-Djava.security.policy==/Applications/SongKong.app/Contents/PlugIns/adoptopenjdk-11.jre/Contents/Home/conf.old/security/policy/unlimited/default_local.policy</string>
但它不起作用,我尝试了各种值但没有任何效果。唯一可行的是将它留在 conf 子文件夹中,然后我是否传递此参数都没有关系。 (我还尝试添加 -Dsecurity.manager 作为另一个选项,但这只会导致有关日志记录权限的新错误。)
【问题讨论】:
-
stacktrace 和 source-code 的相关性如何?故障发生在哪一行?你有 10.5k 的声誉,应该知道如何提供正确的信息 :-)
-
@Melvin 公平点我把代码压缩得太多了,现在修改以更清晰
-
能否提供异常类型+消息?它已从您的堆栈跟踪中剥离。是找不到类错误吗?
-
这可能是一些 javax 依赖项,不再包含在核心 JDK 中,需要显式添加。在您分享异常类型和消息(如其他人建议的那样)之前,这只是一个猜测。
-
@AnishB.yes 我正在使用 maven
标签: java ssl java-11 adoptopenjdk