diff --git a/bin/configs/java-native-useGzipFeature.yaml b/bin/configs/java-native-useGzipFeature.yaml index 6e8358ea5529..dd73fd6f0430 100644 --- a/bin/configs/java-native-useGzipFeature.yaml +++ b/bin/configs/java-native-useGzipFeature.yaml @@ -7,3 +7,4 @@ additionalProperties: artifactId: petstore-native-useGzipFeature hideGenerationTimestamp: "true" useJakartaEe: "true" + useGzipFeature: "true" diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/native/ApiClient.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/native/ApiClient.mustache index 4bc1825e2ace..0fd6071d3080 100644 --- a/modules/openapi-generator/src/main/resources/Java/libraries/native/ApiClient.mustache +++ b/modules/openapi-generator/src/main/resources/Java/libraries/native/ApiClient.mustache @@ -489,7 +489,7 @@ public class ApiClient { if (encoding.isPresent()) { for (String token : encoding.get().split(",")) { if ("gzip".equalsIgnoreCase(token.trim())) { - return new GZIPInputStream(body); + return new GZIPInputStream(body, 8192); } } } @@ -531,9 +531,9 @@ public class ApiClient { } private boolean fillBuffer() throws IOException { - ensureInitialized(); while (chunkPosition >= currentChunk.length) { buffer.reset(); + ensureInitialized(); if (finished) { return false; } @@ -570,6 +570,9 @@ public class ApiClient { @Override public int read(byte[] b, int off, int len) throws IOException { + if (len == 0) { + return 0; + } if (!fillBuffer()) { return -1; } diff --git a/samples/client/echo_api/java/native/src/main/java/org/openapitools/client/ApiClient.java b/samples/client/echo_api/java/native/src/main/java/org/openapitools/client/ApiClient.java index 317e9f918185..546baedc6b33 100644 --- a/samples/client/echo_api/java/native/src/main/java/org/openapitools/client/ApiClient.java +++ b/samples/client/echo_api/java/native/src/main/java/org/openapitools/client/ApiClient.java @@ -478,7 +478,7 @@ public static InputStream getResponseBody(HttpResponse response) th if (encoding.isPresent()) { for (String token : encoding.get().split(",")) { if ("gzip".equalsIgnoreCase(token.trim())) { - return new GZIPInputStream(body); + return new GZIPInputStream(body, 8192); } } } diff --git a/samples/client/petstore/java/native-async/src/main/java/org/openapitools/client/ApiClient.java b/samples/client/petstore/java/native-async/src/main/java/org/openapitools/client/ApiClient.java index 1936d2441e07..f72089b6a7c5 100644 --- a/samples/client/petstore/java/native-async/src/main/java/org/openapitools/client/ApiClient.java +++ b/samples/client/petstore/java/native-async/src/main/java/org/openapitools/client/ApiClient.java @@ -478,7 +478,7 @@ public static InputStream getResponseBody(HttpResponse response) th if (encoding.isPresent()) { for (String token : encoding.get().split(",")) { if ("gzip".equalsIgnoreCase(token.trim())) { - return new GZIPInputStream(body); + return new GZIPInputStream(body, 8192); } } } diff --git a/samples/client/petstore/java/native-jakarta/src/main/java/org/openapitools/client/ApiClient.java b/samples/client/petstore/java/native-jakarta/src/main/java/org/openapitools/client/ApiClient.java index d17d6492767f..7428066cc7e7 100644 --- a/samples/client/petstore/java/native-jakarta/src/main/java/org/openapitools/client/ApiClient.java +++ b/samples/client/petstore/java/native-jakarta/src/main/java/org/openapitools/client/ApiClient.java @@ -478,7 +478,7 @@ public static InputStream getResponseBody(HttpResponse response) th if (encoding.isPresent()) { for (String token : encoding.get().split(",")) { if ("gzip".equalsIgnoreCase(token.trim())) { - return new GZIPInputStream(body); + return new GZIPInputStream(body, 8192); } } } diff --git a/samples/client/petstore/java/native-useGzipFeature/src/main/java/org/openapitools/client/ApiClient.java b/samples/client/petstore/java/native-useGzipFeature/src/main/java/org/openapitools/client/ApiClient.java index d17d6492767f..cee7dfa0cfa9 100644 --- a/samples/client/petstore/java/native-useGzipFeature/src/main/java/org/openapitools/client/ApiClient.java +++ b/samples/client/petstore/java/native-useGzipFeature/src/main/java/org/openapitools/client/ApiClient.java @@ -21,6 +21,7 @@ import java.io.InputStream; import java.io.IOException; +import java.io.ByteArrayOutputStream; import java.net.URI; import java.net.URLEncoder; import java.net.http.HttpClient; @@ -37,6 +38,9 @@ import java.util.function.Consumer; import java.util.Optional; import java.util.zip.GZIPInputStream; +import java.util.function.Supplier; +import java.util.Objects; +import java.util.zip.GZIPOutputStream; import java.util.stream.Collectors; import static java.nio.charset.StandardCharsets.UTF_8; @@ -478,11 +482,122 @@ public static InputStream getResponseBody(HttpResponse response) th if (encoding.isPresent()) { for (String token : encoding.get().split(",")) { if ("gzip".equalsIgnoreCase(token.trim())) { - return new GZIPInputStream(body); + return new GZIPInputStream(body, 8192); } } } return body; } + /** + * Wraps a request body supplier with a streaming GZIP compressor so large payloads + * can be sent without buffering the entire contents in memory. + * + * @param bodySupplier Supplies the original request body InputStream + * @return BodyPublisher that emits gzip-compressed bytes from the supplied stream + */ + public static HttpRequest.BodyPublisher gzipRequestBody(Supplier bodySupplier) { + Objects.requireNonNull(bodySupplier, "bodySupplier must not be null"); + return HttpRequest.BodyPublishers.ofInputStream(() -> new GzipCompressingInputStream(bodySupplier)); + } + + private static final class GzipCompressingInputStream extends InputStream { + private final Supplier supplier; + private final byte[] readBuffer = new byte[8192]; + private final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + private InputStream source; + private GZIPOutputStream gzipStream; + private byte[] currentChunk = new byte[0]; + private int chunkPosition = 0; + private boolean finished = false; + + private GzipCompressingInputStream(Supplier supplier) { + this.supplier = Objects.requireNonNull(supplier, "bodySupplier must not be null"); + } + + private void ensureInitialized() throws IOException { + if (source == null) { + source = Objects.requireNonNull(supplier.get(), "bodySupplier returned null InputStream"); + gzipStream = new GZIPOutputStream(buffer, true); + } + } + + private boolean fillBuffer() throws IOException { + while (chunkPosition >= currentChunk.length) { + buffer.reset(); + ensureInitialized(); + if (finished) { + return false; + } + int bytesRead = source.read(readBuffer); + if (bytesRead == -1) { + gzipStream.finish(); + gzipStream.close(); + source.close(); + finished = true; + } else { + gzipStream.write(readBuffer, 0, bytesRead); + gzipStream.flush(); + } + currentChunk = buffer.toByteArray(); + chunkPosition = 0; + if (currentChunk.length == 0 && !finished) { + continue; + } + if (currentChunk.length == 0 && finished) { + return false; + } + return true; + } + return true; + } + + @Override + public int read() throws IOException { + if (!fillBuffer()) { + return -1; + } + return currentChunk[chunkPosition++] & 0xFF; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (len == 0) { + return 0; + } + if (!fillBuffer()) { + return -1; + } + int bytesToCopy = Math.min(len, currentChunk.length - chunkPosition); + System.arraycopy(currentChunk, chunkPosition, b, off, bytesToCopy); + chunkPosition += bytesToCopy; + return bytesToCopy; + } + + @Override + public void close() throws IOException { + IOException exception = null; + if (source != null) { + try { + source.close(); + } catch (IOException e) { + exception = e; + } finally { + source = null; + } + } + if (gzipStream != null) { + try { + gzipStream.close(); + } catch (IOException e) { + exception = exception == null ? e : exception; + } finally { + gzipStream = null; + } + } + if (exception != null) { + throw exception; + } + } + } } diff --git a/samples/client/petstore/java/native-useGzipFeature/src/main/java/org/openapitools/client/api/PetApi.java b/samples/client/petstore/java/native-useGzipFeature/src/main/java/org/openapitools/client/api/PetApi.java index daed499f06f5..c21fea251f7b 100644 --- a/samples/client/petstore/java/native-useGzipFeature/src/main/java/org/openapitools/client/api/PetApi.java +++ b/samples/client/petstore/java/native-useGzipFeature/src/main/java/org/openapitools/client/api/PetApi.java @@ -44,6 +44,7 @@ import java.util.Map; import java.util.Set; import java.util.function.Consumer; +import java.util.function.Supplier; @jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.19.0-SNAPSHOT") public class PetApi { @@ -267,10 +268,13 @@ private HttpRequest.Builder addPetRequestBuilder(@jakarta.annotation.Nonnull Pet localVarRequestBuilder.header("Content-Type", "application/json"); localVarRequestBuilder.header("Accept", "application/xml, application/json"); + localVarRequestBuilder.header("Accept-Encoding", "gzip"); try { byte[] localVarPostBody = memberVarObjectMapper.writeValueAsBytes(pet); - localVarRequestBuilder.method("POST", HttpRequest.BodyPublishers.ofByteArray(localVarPostBody)); + Supplier localVarRequestBodySupplier = () -> new ByteArrayInputStream(localVarPostBody); + localVarRequestBuilder.header("Content-Encoding", "gzip"); + localVarRequestBuilder.method("POST", ApiClient.gzipRequestBody(localVarRequestBodySupplier)); } catch (IOException e) { throw new ApiException(e); } diff --git a/samples/client/petstore/java/native/src/main/java/org/openapitools/client/ApiClient.java b/samples/client/petstore/java/native/src/main/java/org/openapitools/client/ApiClient.java index 1936d2441e07..f72089b6a7c5 100644 --- a/samples/client/petstore/java/native/src/main/java/org/openapitools/client/ApiClient.java +++ b/samples/client/petstore/java/native/src/main/java/org/openapitools/client/ApiClient.java @@ -478,7 +478,7 @@ public static InputStream getResponseBody(HttpResponse response) th if (encoding.isPresent()) { for (String token : encoding.get().split(",")) { if ("gzip".equalsIgnoreCase(token.trim())) { - return new GZIPInputStream(body); + return new GZIPInputStream(body, 8192); } } }