Skip to content

Commit dbe0419

Browse files
authored
[Java][HttpClient] Fix memory leak with virtual threads (#21729) (#21752)
1 parent bae8082 commit dbe0419

File tree

3 files changed

+18
-21
lines changed
  • modules/openapi-generator/src/main/resources/Java/libraries/apache-httpclient
  • samples/client
    • echo_api/java/apache-httpclient/src/main/java/org/openapitools/client
    • petstore/java/apache-httpclient/src/main/java/org/openapitools/client

3 files changed

+18
-21
lines changed

modules/openapi-generator/src/main/resources/Java/libraries/apache-httpclient/ApiClient.mustache

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ import java.util.ArrayList;
5050
import java.util.Date;
5151
import java.util.function.Supplier;
5252
import java.util.TimeZone;
53-
import java.util.concurrent.ConcurrentHashMap;
5453
import java.util.regex.Matcher;
5554
import java.util.regex.Pattern;
5655

@@ -127,8 +126,8 @@ public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} {
127126

128127
protected Map<String, Authentication> authentications;
129128

130-
protected Map<Long, Integer> lastStatusCodeByThread = new ConcurrentHashMap<>();
131-
protected Map<Long, Map<String, List<String>>> lastResponseHeadersByThread = new ConcurrentHashMap<>();
129+
protected ThreadLocal<Integer> lastStatusCode = new ThreadLocal<>();
130+
protected ThreadLocal<Map<String, List<String>>> lastResponseHeaders = new ThreadLocal<>();
132131

133132
protected DateFormat dateFormat;
134133

@@ -284,7 +283,7 @@ public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} {
284283
*/
285284
@Deprecated
286285
public int getStatusCode() {
287-
return lastStatusCodeByThread.get(Thread.currentThread().getId());
286+
return lastStatusCode.get();
288287
}
289288

290289
/**
@@ -293,7 +292,7 @@ public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} {
293292
*/
294293
@Deprecated
295294
public Map<String, List<String>> getResponseHeaders() {
296-
return lastResponseHeadersByThread.get(Thread.currentThread().getId());
295+
return lastResponseHeaders.get();
297296
}
298297

299298
/**
@@ -1015,13 +1014,13 @@ public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} {
10151014

10161015
protected <T> T processResponse(CloseableHttpResponse response, TypeReference<T> returnType) throws ApiException, IOException, ParseException {
10171016
int statusCode = response.getCode();
1018-
lastStatusCodeByThread.put(Thread.currentThread().getId(), statusCode);
1017+
lastStatusCode.set(statusCode);
10191018
if (statusCode == HttpStatus.SC_NO_CONTENT) {
10201019
return null;
10211020
}
10221021

10231022
Map<String, List<String>> responseHeaders = transformResponseHeaders(response.getHeaders());
1024-
lastResponseHeadersByThread.put(Thread.currentThread().getId(), responseHeaders);
1023+
lastResponseHeaders.set(responseHeaders);
10251024

10261025
if (isSuccessfulStatus(statusCode)) {
10271026
return this.deserialize(response, returnType);

samples/client/echo_api/java/apache-httpclient/src/main/java/org/openapitools/client/ApiClient.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@
5656
import java.util.Date;
5757
import java.util.function.Supplier;
5858
import java.util.TimeZone;
59-
import java.util.concurrent.ConcurrentHashMap;
6059
import java.util.regex.Matcher;
6160
import java.util.regex.Pattern;
6261

@@ -104,8 +103,8 @@ public class ApiClient extends JavaTimeFormatter {
104103

105104
protected Map<String, Authentication> authentications;
106105

107-
protected Map<Long, Integer> lastStatusCodeByThread = new ConcurrentHashMap<>();
108-
protected Map<Long, Map<String, List<String>>> lastResponseHeadersByThread = new ConcurrentHashMap<>();
106+
protected ThreadLocal<Integer> lastStatusCode = new ThreadLocal<>();
107+
protected ThreadLocal<Map<String, List<String>>> lastResponseHeaders = new ThreadLocal<>();
109108

110109
protected DateFormat dateFormat;
111110

@@ -254,7 +253,7 @@ public ApiClient setServerVariables(Map<String, String> serverVariables) {
254253
*/
255254
@Deprecated
256255
public int getStatusCode() {
257-
return lastStatusCodeByThread.get(Thread.currentThread().getId());
256+
return lastStatusCode.get();
258257
}
259258

260259
/**
@@ -263,7 +262,7 @@ public int getStatusCode() {
263262
*/
264263
@Deprecated
265264
public Map<String, List<String>> getResponseHeaders() {
266-
return lastResponseHeadersByThread.get(Thread.currentThread().getId());
265+
return lastResponseHeaders.get();
267266
}
268267

269268
/**
@@ -932,13 +931,13 @@ protected Cookie buildCookie(String key, String value, URI uri) {
932931

933932
protected <T> T processResponse(CloseableHttpResponse response, TypeReference<T> returnType) throws ApiException, IOException, ParseException {
934933
int statusCode = response.getCode();
935-
lastStatusCodeByThread.put(Thread.currentThread().getId(), statusCode);
934+
lastStatusCode.set(statusCode);
936935
if (statusCode == HttpStatus.SC_NO_CONTENT) {
937936
return null;
938937
}
939938

940939
Map<String, List<String>> responseHeaders = transformResponseHeaders(response.getHeaders());
941-
lastResponseHeadersByThread.put(Thread.currentThread().getId(), responseHeaders);
940+
lastResponseHeaders.set(responseHeaders);
942941

943942
if (isSuccessfulStatus(statusCode)) {
944943
return this.deserialize(response, returnType);

samples/client/petstore/java/apache-httpclient/src/main/java/org/openapitools/client/ApiClient.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@
5656
import java.util.Date;
5757
import java.util.function.Supplier;
5858
import java.util.TimeZone;
59-
import java.util.concurrent.ConcurrentHashMap;
6059
import java.util.regex.Matcher;
6160
import java.util.regex.Pattern;
6261

@@ -149,8 +148,8 @@ public class ApiClient extends JavaTimeFormatter {
149148

150149
protected Map<String, Authentication> authentications;
151150

152-
protected Map<Long, Integer> lastStatusCodeByThread = new ConcurrentHashMap<>();
153-
protected Map<Long, Map<String, List<String>>> lastResponseHeadersByThread = new ConcurrentHashMap<>();
151+
protected ThreadLocal<Integer> lastStatusCode = new ThreadLocal<>();
152+
protected ThreadLocal<Map<String, List<String>>> lastResponseHeaders = new ThreadLocal<>();
154153

155154
protected DateFormat dateFormat;
156155

@@ -302,7 +301,7 @@ public ApiClient setServerVariables(Map<String, String> serverVariables) {
302301
*/
303302
@Deprecated
304303
public int getStatusCode() {
305-
return lastStatusCodeByThread.get(Thread.currentThread().getId());
304+
return lastStatusCode.get();
306305
}
307306

308307
/**
@@ -311,7 +310,7 @@ public int getStatusCode() {
311310
*/
312311
@Deprecated
313312
public Map<String, List<String>> getResponseHeaders() {
314-
return lastResponseHeadersByThread.get(Thread.currentThread().getId());
313+
return lastResponseHeaders.get();
315314
}
316315

317316
/**
@@ -1025,13 +1024,13 @@ protected Cookie buildCookie(String key, String value, URI uri) {
10251024

10261025
protected <T> T processResponse(CloseableHttpResponse response, TypeReference<T> returnType) throws ApiException, IOException, ParseException {
10271026
int statusCode = response.getCode();
1028-
lastStatusCodeByThread.put(Thread.currentThread().getId(), statusCode);
1027+
lastStatusCode.set(statusCode);
10291028
if (statusCode == HttpStatus.SC_NO_CONTENT) {
10301029
return null;
10311030
}
10321031

10331032
Map<String, List<String>> responseHeaders = transformResponseHeaders(response.getHeaders());
1034-
lastResponseHeadersByThread.put(Thread.currentThread().getId(), responseHeaders);
1033+
lastResponseHeaders.set(responseHeaders);
10351034

10361035
if (isSuccessfulStatus(statusCode)) {
10371036
return this.deserialize(response, returnType);

0 commit comments

Comments
 (0)