Ошибка Apache HttpClient с Java 11 в macOS

Я пытаюсь перенести свой код с 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;
}

}

здесь не работает (AdoptOpenJdk) Java 11.0.6 на MacOS,

SSLContext sslcontext = org.apache.http.ssl.SSLContexts.custom()
            .loadTrustMaterial(new NaiveTrustStrategy())
            .build();

Он без проблем работает в Windows (также с использованием AdoptOpenJdk Java 11.0.6). Одно отличие состоит в том, что версия для Windows использует урезанную jre, созданную из jdk с jlink, тогда как версия для MacOS использует сборку AdoptOpenJDk jre. Сборка MacOS создана с использованием форка InfiniteKinds 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.

Обновление Я добавил пример теста в свой исходный код из ответа ниже и изменил свою сборку, чтобы сделать его стартовым классом при запуске приложения, и он дает мне эту трассировку стека (когда пакет запускается из командной строки с open с использованием среды выполнения java, встроенной в пакет с помощью 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)

Обновление. На основании приведенного ниже ответа я добился определенного прогресса.

JRE, установленная на MacOS, содержит папку conf, когда JRE добавляется в мой пакет (SongKong) с помощью приложения InfiniteKinds appbundler, у него нет папки conf. У него есть папка 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

e.g

/Applications/SongKong.app/Contents/PlugIns/adoptopenjdk-11.jre/Contents/Home

location, то и код примера, и мой исходный код работают без ошибок при запуске из пакета.

Кроме того, похоже, что он ищет неограниченную папку и ее содержимое (два файла на самом деле одинаковы), поэтому, если я удалю несколько файлов, у меня останется

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 в качестве другого варианта, но это вызвало новую ошибку о разрешениях на ведение журнала.)


person Paul Taylor    schedule 13.04.2020    source источник
comment
Как соотносятся stacktrace и исходный код? В какой строке происходит сбой? У вас 10.5k репутации, и вы должны знать, как предоставлять правильную информацию :-)   -  person Melvin    schedule 15.04.2020
comment
@Melvin, честно говоря, я слишком сжал код, теперь исправлено, чтобы было понятнее   -  person Paul Taylor    schedule 15.04.2020
comment
Не могли бы вы предоставить тип исключения + сообщение? Он удален из вашей трассировки стека. Это ошибка класса не найден?   -  person amanin    schedule 16.04.2020
comment
Вероятно, это какая-то зависимость от javax, которая больше не включена в основной JDK и должна быть добавлена ​​явно. Это только предположение, пока вы не поделитесь типом исключения и сообщением (как предлагали другие).   -  person Martin Tarjányi    schedule 16.04.2020
comment
Извините за недосмотр с моей стороны, теперь добавлен отсутствующий класс sun.security.ssl.SSLContextImpl $ TLSContext   -  person Paul Taylor    schedule 17.04.2020
comment
Добавлено сообщение об ошибке @Melvin, спасибо   -  person Paul Taylor    schedule 17.04.2020
comment
Не могли бы вы привести минимальный воспроизводимый пример? Потому что я не могу воспроизвести вашу проблему с AdoptOpenJdk 11.0.6 на macOS. Ваш код работает как шарм   -  person Denis Stafichuk    schedule 17.04.2020
comment
@DenisStafichuk попробовать вместо этого использовать AdoptOpenJdk JRE?   -  person Paul Taylor    schedule 18.04.2020
comment
Вы используете maven?   -  person Anish B.    schedule 19.04.2020
comment
@ AnishB.yes, я использую maven   -  person Paul Taylor    schedule 19.04.2020
comment
Я пробовал AdoptOpenJdk JRE и получил тот же результат. Оно работает. Проблема в другом   -  person Denis Stafichuk    schedule 19.04.2020
comment
Я думаю, что что-то не так со свойствами вашей системы. Можете ли вы запустить приложение с флагом -XshowSettings:properties и добавить его результат в вопрос? stackoverflow.com/a/36045464/3249257   -  person Denis Stafichuk    schedule 20.04.2020
comment
@DenisStafichuk Ive добавил -XshowSettings: свойства к вопросу по запросу, спасибо   -  person Paul Taylor    schedule 21.04.2020
comment
Удалены свойства из вопроса, потому что кажутся нерелевантными   -  person Paul Taylor    schedule 22.04.2020
comment
@DenisStafichuk проблема с файлами .policy, есть идеи?   -  person Paul Taylor    schedule 22.04.2020


Ответы (2)


В конце концов, с помощью Аниша выяснилось, что это проблема с отсутствующими файлами политик, и проблема была только в пакете, созданном с помощью AppBunder.

Код jdk действительно ожидал наличия папки conf в JRE, она была в OpenJDk, но ни разу не была включена в мое приложение с AppBundler. Итак, я загрузил последний код AppBundler src и перестроил его, перестроил свой appbundle, и это было исправлено, теперь папка conf была включена, и приложение запускается без ошибок.

person Paul Taylor    schedule 22.04.2020
comment
@AnishB. я не знаю, я назначил вам награду и пометил ее, но на самом деле правильный ответ действительно мой, все, что мне нужно было сделать в конце, это получить последний код appbundler, как вы думаете? - person Paul Taylor; 22.04.2020
comment
У меня нет проблем. Я просто спросил. +1 за ваше исправление, так как я также узнал кое-что новое по этому вопросу. Спасибо :) - person Anish B.; 22.04.2020

Я тестировал код в 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.

Вы можете скачать эти файлы политик по ссылке на документацию выше.

Я думаю, что файлы политик могут отсутствовать или возникла другая проблема. Пожалуйста, подтвердите.

person Anish B.    schedule 19.04.2020
comment
Комментарии не подлежат расширенному обсуждению; этот разговор был перешел в чат. - person Samuel Liew♦; 23.04.2020