5

我正在尝试将我的代码从 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 版本使用从 jdk 和 jlink 构建的缩减 jre,而 MacOS 版本使用 AdoptOpenJDk jre 构建。MacOS 版本是使用 InfiniteKinds fork 创建的AppBundler

这是堆栈跟踪:

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 服务获取数据。

更新open我从下面的答案向我的源代码添加了示例测试,并修改了我的构建以在应用程序运行时使其成为启动类,它给了我这个堆栈跟踪(当使用嵌入的 java 运行时 从命令行运行包时由无限种类的 appbundle 提供的捆绑包)

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它运行示例并打印出加载没有错误,如果我从 /Library/Java 指定完整路径,它也适用于所有情况(Java 11/Java 14/JDk 和 JRE)

更新 根据下面的答案,我取得了一些进展。

MacOS 上安装的 JRE 包含一个conf文件夹,当使用 InfiniteKinds appbundler 将 JRE 添加到我的包 (SongKong) 中时,它没有 conf 文件夹。它确实有一个包含 a 的 lib/security 文件夹,default.policy但这似乎还不够。

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

位置然后示例代码和我的原始代码在从捆绑包运行时都可以正常工作。

此外,它似乎正在寻找的是无限文件夹及其内容(这两个文件实际上是相同的),所以如果我删除一些文件,那么我就剩下

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

然后它继续工作。

问题(除了为什么它不能开箱即用之外)是我假设我无法将文件复制到此位置以用于强化运行时应用程序,因此我需要将这些策略文件存储在其他地方,以便它们可以作为 appbundler 构建的一部分安装。因此,作为测试,我已重命名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作为另一个选项,但这只会导致有关日志记录权限的新错误。)

4

2 回答 2

2

我已经在 Spring Tools Suite 4、AdoptedOpenJDK Java 11.0.6、macOS catalina 10.15.4 和 Maven 3.8.1 上测试了代码

我采用了导致问题的一部分代码。

Example.java

package com.example;

import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;

import org.apache.http.ssl.TrustStrategy;

class NaiveTrustStrategy implements TrustStrategy {

    public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        return true;
    }

}

public class Example {

    public static void main(String... args) throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
        SSLContext sslcontext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(new NaiveTrustStrategy())
                .build();
        System.out.println("Loaded");
    }

}

注意:我使用了 javax.net.ssl.SSLContext。

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>Test</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.3</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <!-- <target>11</target> <source>11</source> -->
                    <verbose>true</verbose>
                    <fork>true</fork>
                    <executable>
                        /Library/Java/JavaVirtualMachines/adoptopenjdk-11.jdk/Contents/Home/bin/javac
                    </executable>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

输出(用于测试):没有错误

在此处输入图像描述

我看过这个链接:https ://github.com/TheInfiniteKind/appbundler/

请将 JDK/JRE 更改为指向 11。

如果问题仍然存在,请下载最新版本appbundler并尝试再次运行。


来自 Oracle 文档 ( https://www.oracle.com/java/technologies/javase-jce-all-downloads.html ):

当前版本的 JDK 不需要这些策略文件。

JDK 9 及更高版本附带并默认使用无限策略文件。

只有 JDK 8、7 和 6 需要无限制的策略文件。

您可以从上面的文档链接下载这些策略文件。

我认为策略文件可能丢失或其他问题。请核实。

于 2020-04-19T07:45:09.350 回答
2

最终在 Anish 的帮助下解决了缺少策略文件的问题,并且只是使用AppBunder构建的捆绑包的问题。

jdk 代码似乎真的希望conf在 JRE 中有一个文件夹,OpenJDk 中有一个文件夹,但没有一次使用 AppBundler 捆绑到我的应用程序中。所以我下载了最新的 AppBundler src 代码并重建了它,重建了我的 appbundle 并修复了它,现在包含了 conf 文件夹并且应用程序运行没有错误。

于 2020-04-22T16:45:05.347 回答