blob: 9caeddb0b52256a413c108a9c5ac55c90c239413 [file]
<!DOCTYPE html>
<!--
| Generated by Apache Maven Doxia Site Renderer 2.0.0 from src/site/xdoc/docs/http2-java-client.xml at 2026-05-18
| Rendered using Apache Maven Fluido Skin 2.0.0-M11
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="generator" content="Apache Maven Doxia Site Renderer 2.0.0" />
<title>HTTP/2 Java Client — Sample Code – Apache Axis2</title>
<link rel="stylesheet" href="../css/apache-maven-fluido-2.0.0-M11.min.css" />
<link rel="stylesheet" href="../css/site.css" />
<link rel="stylesheet" href="../css/print.css" media="print" />
<script src="../js/apache-maven-fluido-2.0.0-M11.min.js"></script>
</head>
<body>
<div class="container-fluid container-fluid-top">
<header>
<div id="banner">
<div class="pull-left"><div id="bannerLeft"><h1><a href="https://www.apache.org/"><img class="class java.lang.Object" src="https://www.apache.org/images/asf_logo_wide.png" /> Apache Axis2</a></h1></div></div>
<div class="pull-right"><div id="bannerRight"><h1><a href="https://axis.apache.org/axis2/java/core/"><img class="class java.lang.Object" src="https://axis.apache.org/axis2/java/core/images/axis.jpg" /></a></h1></div></div>
<div class="clear"><hr/></div>
</div>
<div id="breadcrumbs">
<ul class="breadcrumb">
<li id="publishDate">Last Published: 2026-05-17<span class="divider">|</span>
</li>
<li id="projectVersion">Version: 2.0.1<span class="divider">|</span></li>
<li><a href="https://www.apache.org" class="externalLink">Apache</a><span class="divider">/</span></li>
<li><a href="../index.html">Axis2/Java</a><span class="divider">/</span></li>
<li class="active">HTTP/2 Java Client — Sample Code</li>
</ul>
</div>
</header>
<div class="row-fluid">
<header id="leftColumn" class="span2">
<nav class="well sidebar-nav">
<ul class="nav nav-list">
<li class="nav-header">Axis2/Java</li>
<li><a href="../index.html">Home</a></li>
<li><a href="../download.html">Downloads</a></li>
<li><a href="javascript:void(0)"><span class="icon-chevron-down"></span>Release Notes</a>
<ul class="nav nav-list">
<li><a href="../release-notes/1.6.1.html">1.6.1</a></li>
<li><a href="../release-notes/1.6.2.html">1.6.2</a></li>
<li><a href="../release-notes/1.6.3.html">1.6.3</a></li>
<li><a href="../release-notes/1.6.4.html">1.6.4</a></li>
<li><a href="../release-notes/1.7.0.html">1.7.0</a></li>
<li><a href="../release-notes/1.7.1.html">1.7.1</a></li>
<li><a href="../release-notes/1.7.2.html">1.7.2</a></li>
<li><a href="../release-notes/1.7.3.html">1.7.3</a></li>
<li><a href="../release-notes/1.7.4.html">1.7.4</a></li>
<li><a href="../release-notes/1.7.5.html">1.7.5</a></li>
<li><a href="../release-notes/1.7.6.html">1.7.6</a></li>
<li><a href="../release-notes/1.7.7.html">1.7.7</a></li>
<li><a href="../release-notes/1.7.8.html">1.7.8</a></li>
<li><a href="../release-notes/1.7.9.html">1.7.9</a></li>
<li><a href="../release-notes/1.8.0.html">1.8.0</a></li>
<li><a href="../release-notes/1.8.1.html">1.8.1</a></li>
<li><a href="../release-notes/1.8.2.html">1.8.2</a></li>
<li><a href="../release-notes/2.0.0.html">2.0.0</a></li>
<li><a href="../release-notes/2.0.1.html">2.0.1</a></li>
</ul></li>
<li><a href="../modules/index.html">Modules</a></li>
<li><a href="../tools/index.html">Tools</a></li>
<li class="nav-header">Documentation</li>
<li><a href="../docs/toc.html">Table of Contents</a></li>
<li><a href="../docs/installationguide.html">Installation Guide</a></li>
<li><a href="../docs/quickstartguide.html">QuickStart Guide</a></li>
<li><a href="../docs/userguide.html">User Guide</a></li>
<li><a href="../docs/jaxws-guide.html">JAXWS Guide</a></li>
<li><a href="../docs/pojoguide.html">POJO Guide</a></li>
<li><a href="../docs/spring.html">Spring Guide</a></li>
<li><a href="../docs/webadminguide.html">Web Administrator&apos;s Guide</a></li>
<li><a href="../docs/migration.html">Migration Guide (from Axis1)</a></li>
<li class="nav-header">Resources</li>
<li><a href="../faq.html">FAQ</a></li>
<li><a href="https://github.com/apache/axis-axis2-java-core" class="externalLink">Source Code</a></li>
<li class="nav-header">Get Involved</li>
<li><a href="../overview.html">Overview</a></li>
<li><a href="../mail-lists.html">Mailing Lists</a></li>
<li><a href="../release-process.html">Release Process</a></li>
<li><a href="../guidelines.html">Developer Guidelines</a></li>
<li><a href="../siteHowTo.html">Build the Site</a></li>
<li class="nav-header">Project Information</li>
<li><a href="https://github.com/apache/axis-axis2-java-core/graphs/contributors" class="externalLink">Contributors</a></li>
<li><a href="https://issues.apache.org/jira/projects/AXIS2/issues" class="externalLink">Issues</a></li>
<li class="nav-header">Apache</li>
<li><a href="https://www.apache.org/licenses/LICENSE-2.0.html" class="externalLink">License</a></li>
<li><a href="https://www.apache.org/foundation/sponsorship.html" class="externalLink">Sponsorship</a></li>
<li><a href="https://www.apache.org/foundation/thanks.html" class="externalLink">Thanks</a></li>
<li><a href="https://www.apache.org/security/" class="externalLink">Security</a></li>
</ul>
</nav>
<div class="well sidebar-nav">
<div id="poweredBy">
<div class="clear"></div>
<div class="clear"></div>
<a href="https://maven.apache.org/" class="builtBy" target="_blank"><img class="builtBy" alt="Built by Maven" src="../images/logos/maven-feather.png" /></a>
</div>
</div>
</header>
<main id="bodyColumn" class="span10">
<section><a id="HTTP.2F2_Java_Client_.E2.80.94_Sample_Code"></a>
<h1>HTTP/2 Java Client &#x2014; Sample Code</h1>
<p><strong>What this is:</strong> A standalone sample client
(<code>Http2JsonClient</code>) that demonstrates how to call Axis2
JSON-RPC services over HTTP/2 from plain Java using Apache HttpClient 5.
It is <em>not</em> part of the Axis2 framework &#x2014; it is example code
in the userguide samples that you can copy and adapt for your own
project.</p>
<p><strong>Why it exists:</strong> Java's built-in
<code>HttpURLConnection</code> does not support HTTP/2. Apache
HttpClient 5's convenience classes (<code>SimpleHttpRequest</code> /
<code>SimpleHttpResponse</code>) support HTTP/2 but silently buffer
the entire response in memory, defeating the streaming benefit.
This sample shows the correct pattern &#x2014; using
<code>AbstractBinResponseConsumer</code> with the async API &#x2014; so
you don't have to rediscover it the hard way.</p>
<p>Two execution modes:</p>
<ul>
<li><strong>Buffered</strong> &#x2014; returns the full response as a
<code>String</code>. Simple, suitable for responses that fit
in memory.</li>
<li><strong>Streaming</strong> &#x2014; writes response bytes to an
<code>OutputStream</code> in 64KB chunks as HTTP/2 DATA
frames arrive. Memory stays flat regardless of response size.
When paired with the
<a href="json-streaming-formatter.html">Streaming JSON
Formatter</a> (AXIS2-6103), data flows end-to-end in 64KB
chunks.</li>
</ul>
</section>
<section><a id="The_SimpleHttp.2A_Pitfall"></a>
<h1>The SimpleHttp* Pitfall</h1>
<p>Apache HttpClient 5 provides <code>SimpleHttpRequest</code> and
<code>SimpleHttpResponse</code> as convenience classes for async
requests. <strong>Do not use them for HTTP/2 workloads with large
responses.</strong> They appear to work, but they silently defeat
HTTP/2 streaming.</p>
<p><code>SimpleHttpResponse</code> is a buffering response object &#x2014;
it accumulates the entire response body in memory before returning
it to the caller. For a 100MB response:</p>
<ul>
<li><code>SimpleHttpResponse</code>: allocates 100MB+ of heap
(internal byte arrays, header maps, content type parsing)
before your code sees a single byte</li>
<li><code>AbstractBinResponseConsumer</code>: your
<code>data(ByteBuffer)</code> callback fires for each 64KB
HTTP/2 DATA frame &#x2014; memory stays flat at ~64KB working
set</li>
</ul>
<p>This is not obvious from the HttpClient 5 documentation, and
it is easy to write code that uses <code>SimpleHttpResponse</code>,
observes correct HTTP/2 ALPN negotiation in the logs, and concludes
that HTTP/2 streaming is working &#x2014; when in fact the response is
fully buffered before your code runs. The sample client avoids this
by using <code>AbstractBinResponseConsumer</code> for all requests,
including the buffered convenience method.</p>
</section>
<section><a id="Dependencies"></a>
<h1>Dependencies</h1>
<p>Requires Java 11+ (ALPN built in) and Apache HttpClient 5.4+:</p>
<pre class="prettyprint"><code>
&lt;!-- Maven --&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.apache.httpcomponents.client5&lt;/groupId&gt;
&lt;artifactId&gt;httpclient5&lt;/artifactId&gt;
&lt;version&gt;5.4.3&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.apache.httpcomponents.core5&lt;/groupId&gt;
&lt;artifactId&gt;httpcore5-h2&lt;/artifactId&gt;
&lt;version&gt;5.4.1&lt;/version&gt;
&lt;/dependency&gt;
</code></pre>
<p>These are the same dependencies used by Axis2's own
<code>H2TransportSender</code>. If you are already running Axis2
with HTTP/2 transport, they are already on your classpath.</p>
</section>
<section><a id="Buffered_Execution"></a>
<h1>Buffered Execution</h1>
<p>POST JSON-RPC to any Axis2 service, get the response as a String:</p>
<pre class="prettyprint"><code>
String url = &quot;https://localhost:8443/axis2-json-api/services/FinancialBenchmarkService&quot;;
String json = &quot;{\&quot;monteCarlo\&quot;:[{\&quot;arg0\&quot;:{\&quot;nSimulations\&quot;:100000,\&quot;nPeriods\&quot;:252,&quot;
+ &quot;\&quot;initialValue\&quot;:1000000,\&quot;expectedReturn\&quot;:0.10,\&quot;volatility\&quot;:0.223,&quot;
+ &quot;\&quot;nPeriodsPerYear\&quot;:252,\&quot;randomSeed\&quot;:42}}]}&quot;;
String response = Http2JsonClient.execute(url, json, 300);
System.out.println(response);
Http2JsonClient.shutdown();
</code></pre>
<p>The client negotiates HTTP/2 via ALPN on the TLS handshake.
Connections are pooled and multiplexed &#x2014; multiple concurrent requests
share a single TCP connection.</p>
</section>
<section><a id="Streaming_Execution"></a>
<h1>Streaming Execution</h1>
<p>For large responses (10MB+), stream to a file or parser instead
of buffering in heap:</p>
<pre class="prettyprint"><code>
String url = &quot;https://localhost:8443/axis2-json-api/services/BigDataH2Service&quot;;
String json = &quot;{\&quot;generate\&quot;:[{\&quot;arg0\&quot;:{\&quot;datasetSize\&quot;:52428800}}]}&quot;;
try (FileOutputStream fos = new FileOutputStream(&quot;/tmp/result.json&quot;)) {
int status = Http2JsonClient.executeStreaming(url, json, 300, fos);
System.out.println(&quot;HTTP &quot; + status);
}
Http2JsonClient.shutdown();
</code></pre>
<p>Each HTTP/2 DATA frame triggers a callback that writes directly
to your <code>OutputStream</code>. The <code>capacityIncrement()</code>
returns 64KB, creating natural HTTP/2 flow control backpressure &#x2014;
the client tells the server &quot;I can accept 64KB more&quot; after each
chunk.</p>
<p>When the server uses the
<a href="json-streaming-formatter.html">Streaming JSON Formatter</a>,
data flows end-to-end without full-body buffering on either side:</p>
<pre class="prettyprint"><code>
Server (MoshiStreamingMessageFormatter)
&#x2192; FlushingOutputStream flushes every 64KB
&#x2192; HTTP/2 DATA frames
&#x2192; Http2JsonClient.data() callback
&#x2192; your OutputStream
</code></pre>
</section>
<section><a id="Timeout_and_Cancellation"></a>
<h1>Timeout and Cancellation</h1>
<p>Both methods accept a <code>timeoutSeconds</code> parameter for
<code>Future.get()</code>. If the timeout expires or the thread is
interrupted, the underlying HTTP request is cancelled to prevent
zombie requests that would continue consuming resources:</p>
<pre class="prettyprint"><code>
try {
response = future.get(timeoutSeconds, TimeUnit.SECONDS);
} catch (Exception e) {
requestFuture.cancel(true); // Cancel the HTTP request
if (e instanceof InterruptedException) {
Thread.currentThread().interrupt(); // Restore interrupt flag
}
throw e;
}
</code></pre>
</section>
<section><a id="Source_Code"></a>
<h1>Source Code</h1>
<p>The complete sample client is available on GitHub:</p>
<p><a href="https://github.com/apache/axis-axis2-java-core/blob/master/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/client/Http2JsonClient.java" class="externalLink">
Http2JsonClient.java on GitHub</a></p>
<p>Copy and adapt it for your project. It has no dependency on
Axis2 itself &#x2014; only Apache HttpClient 5 and httpcore5-h2.</p>
</section>
</main>
</div>
</div>
<hr/>
<footer>
<div class="container-fluid">
<div class="row-fluid">
<p>© 2004–2026
<a href="https://www.apache.org/">The Apache Software Foundation</a>
</p>
</div>
</div>
</footer>
</body>
</html>