Обертывание BodySubscriber<InputStream> в GZIPInputStream приводит к зависанию

Я использую новый java.net.http классы для обработки асинхронного обмена HTTP-запросами + ответами, и я пытаюсь найти способ, чтобы BodySubscriber обрабатывал различные типы кодирования, такие как gzip.

Тем не менее, картирование BodySubsriber<InputStream> так что основной поток обернут GZIPInputStream (когда в заголовке ответа найдено "Content-Encoding: gzip"), это приводит к зависанию. Без исключений, просто полное прекращение деятельности.

Код, который отображает BodySubscriber выглядит так:

private HttpResponse.BodySubscriber<InputStream> gzippedBodySubscriber(
        HttpResponse.ResponseInfo responseInfo) {
    return HttpResponse.BodySubscribers.mapping(
            HttpResponse.BodySubscribers.ofInputStream(),
            this::decodeGzipStream);
}

private InputStream decodeGzipStream(InputStream gzippedStream) {
    System.out.println("Entered decodeGzipStream method.");
    try {
        InputStream decodedStream = new GZIPInputStream(gzippedStream);
        System.out.println(
                "Created GZIPInputStream to handle response body stream.");
        return decodedStream;
    } catch (IOException ex) {
        System.out.println("IOException occurred while trying to create GZIPInputStream.");
        throw new UncheckedIOException(ex);
    }
}

Получение HTTP-ответа с кодировкой "gzip" приводит к выводу на консоль только этого:

Введен метод EncodedBodyHandler.apply.
Введен метод decodeGzipStream.

Больше ничего не видно, поэтому линия после звонка на GZIPInputStream Конструктор никогда не выполняется.

Кто-нибудь знает, почему эта попытка обернуть InputStream из BodySubscriber<InputStream> в GZIPInputStream висит?

Примечание. Эквивалентный метод для тел без ответа (необработанного текста) HTTP-ответа содержит просто вызов BodySubscribers.ofInputStream() без сопоставления, и это позволяет ответу быть принятым и отображенным без проблем.

0 ответов

Это действительно ошибка. Я вошел в систему JDK-8217264. Я могу предложить два обходных пути:

Обходной путь один

Не использовать BodySubscribers.mapping - но преобразуй InputStream в GZIPInputStream после получения тела HttpResponse:

GZIPInputStream gzin = new GZIPInputStream(resp.getBody());

Обходной путь два

Пусть функция отображения возвращает Supplier<InputStream> вместо этого, стараясь не создавать GZIPInputStream до тех пор Supplier::get называется

static final class ISS implements Supplier<InputStream> {
    final InputStream in;
    GZIPInputStream gz;
    ISS(InputStream in) {
        this.in = in;
    }
    public synchronized InputStream get() {
        if (gz == null) {
            try {
                gz = new GZIPInputStream(in);
            } catch (IOException t) {
                throw new UncheckedIOException(t);
            }
        }
        return gz;
    }
}

Столкнулся с точно такой же проблемой. Я попробовал пример в Javadoc BodySubscribers.mapping метод. Такое же поведение, приложение зависает без ошибок.

Может быть ошибка, потому что это официальный пример из Javadoc.

  public static <W> BodySubscriber<W> asJSON(Class<W> targetType) {
     BodySubscriber<InputStream> upstream = BodySubscribers.ofInputStream();

     BodySubscriber<W> downstream = BodySubscribers.mapping(
           upstream,
           (InputStream is) -> {
               try (InputStream stream = is) {
                   ObjectMapper objectMapper = new ObjectMapper();
                   return objectMapper.readValue(stream, targetType);
               } catch (IOException e) {
                   throw new UncheckedIOException(e);
               }
           });
    return downstream;
 } }
Другие вопросы по тегам