Skip to content

Commit 3a8874b

Browse files
authored
Merge pull request #9737 from thomasJoei/feature/fix-issue-9685
[Issue 9685] Make RestTemplate thread safe by using the withHttpInfo pattern used …
2 parents c9252e8 + 781ee9a commit 3a8874b

File tree

11 files changed

+619
-199
lines changed

11 files changed

+619
-199
lines changed

modules/swagger-codegen/src/main/resources/Java/libraries/resttemplate/ApiClient.mustache

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,6 @@ public class ApiClient {
9191
private RestTemplate restTemplate;
9292

9393
private Map<String, Authentication> authentications;
94-
95-
private HttpStatus statusCode;
96-
private MultiValueMap<String, String> responseHeaders;
9794

9895
private DateFormat dateFormat;
9996

@@ -146,22 +143,6 @@ public class ApiClient {
146143
return this;
147144
}
148145

149-
/**
150-
* Gets the status code of the previous request
151-
* @return HttpStatus the status code
152-
*/
153-
public HttpStatus getStatusCode() {
154-
return statusCode;
155-
}
156-
157-
/**
158-
* Gets the response headers of the previous request
159-
* @return MultiValueMap a map of response headers
160-
*/
161-
public MultiValueMap<String, String> getResponseHeaders() {
162-
return responseHeaders;
163-
}
164-
165146
/**
166147
* Get authentications (key: authentication name, value: authentication).
167148
* @return Map the currently configured authentication types
@@ -520,9 +501,9 @@ public class ApiClient {
520501
* @param contentType The request's Content-Type header
521502
* @param authNames The authentications to apply
522503
* @param returnType The return type into which to deserialize the response
523-
* @return The response body in chosen type
504+
* @return ResponseEntity&lt;T&gt; The response of the chosen type
524505
*/
525-
public <T> T invokeAPI(String path, HttpMethod method, MultiValueMap<String, String> queryParams, Object body, HttpHeaders headerParams, MultiValueMap<String, Object> formParams, List<MediaType> accept, MediaType contentType, String[] authNames, ParameterizedTypeReference<T> returnType) throws RestClientException {
506+
public <T> ResponseEntity<T> invokeAPI(String path, HttpMethod method, MultiValueMap<String, String> queryParams, Object body, HttpHeaders headerParams, MultiValueMap<String, Object> formParams, List<MediaType> accept, MediaType contentType, String[] authNames, ParameterizedTypeReference<T> returnType) throws RestClientException {
526507
updateParamsForAuth(authNames, queryParams, headerParams);
527508
528509
final UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(basePath).path(path);
@@ -544,20 +525,12 @@ public class ApiClient {
544525
RequestEntity<Object> requestEntity = requestBuilder.body(selectBody(body, formParams, contentType));
545526

546527
ResponseEntity<T> responseEntity = restTemplate.exchange(requestEntity, returnType);
547-
548-
statusCode = responseEntity.getStatusCode();
549-
responseHeaders = responseEntity.getHeaders();
550528

551-
if (responseEntity.getStatusCode() == HttpStatus.NO_CONTENT) {
552-
return null;
553-
} else if (responseEntity.getStatusCode().is2xxSuccessful()) {
554-
if (returnType == null) {
555-
return null;
556-
}
557-
return responseEntity.getBody();
529+
if (responseEntity.getStatusCode().is2xxSuccessful()) {
530+
return responseEntity;
558531
} else {
559532
// The error handler built into the RestTemplate should handle 400 and 500 series errors.
560-
throw new RestClientException("API returned " + statusCode + " and it wasn't handled by the RestTemplate error handler");
533+
throw new RestClientException("API returned " + responseEntity.getStatusCode() + " and it wasn't handled by the RestTemplate error handler");
561534
}
562535
}
563536

modules/swagger-codegen/src/main/resources/Java/libraries/resttemplate/api.mustache

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import org.springframework.http.HttpHeaders;
2323
import org.springframework.http.HttpMethod;
2424
import org.springframework.http.HttpStatus;
2525
import org.springframework.http.MediaType;
26+
import org.springframework.http.ResponseEntity;
2627

2728
{{>generatedAnnotation}}
2829
@Component("{{package}}.{{classname}}")
@@ -51,16 +52,53 @@ public class {{classname}} {
5152
/**
5253
* {{summary}}
5354
* {{notes}}
54-
{{#responses}} * <p><b>{{code}}</b>{{#message}} - {{message}}{{/message}}
55-
{{/responses}}{{#allParams}} * @param {{paramName}} {{description}}{{^description}}The {{paramName}} parameter{{/description}}
56-
{{/allParams}}{{#returnType}} * @return {{returnType}}
57-
{{/returnType}} * @throws RestClientException if an error occurs while attempting to invoke the API
58-
{{#externalDocs}}
59-
* {{description}}
60-
* @see <a href="{{url}}">{{summary}} Documentation</a>
61-
{{/externalDocs}}
55+
{{#responses}}
56+
* <p><b>{{code}}</b>{{#message}} - {{message}}{{/message}}
57+
{{/responses}}
58+
{{#allParams}}
59+
* @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}
60+
{{/allParams}}
61+
{{#returnType}}
62+
* @return {{returnType}}
63+
{{/returnType}}
64+
* @throws RestClientException if an error occurs while attempting to invoke the API
65+
{{#externalDocs}}
66+
* {{description}}
67+
* @see <a href="{{url}}">{{summary}} Documentation</a>
68+
{{/externalDocs}}
6269
*/
70+
{{#isDeprecated}}
71+
@Deprecated
72+
{{/isDeprecated}}
6373
public {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{operationId}}({{#allParams}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws RestClientException {
74+
{{#returnType}}
75+
return {{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}).getBody();
76+
{{/returnType}}
77+
{{^returnType}}
78+
{{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
79+
{{/returnType}}
80+
}
81+
82+
/**
83+
* {{summary}}
84+
* {{notes}}
85+
{{#responses}}
86+
* <p><b>{{code}}</b>{{#message}} - {{message}}{{/message}}
87+
{{/responses}}
88+
{{#allParams}}
89+
* @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}
90+
{{/allParams}}
91+
* @return ResponseEntity&lt;{{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}Void{{/returnType}}&gt;
92+
* @throws RestClientException if an error occurs while attempting to invoke the API
93+
{{#externalDocs}}
94+
* {{description}}
95+
* @see <a href="{{url}}">{{summary}} Documentation</a>
96+
{{/externalDocs}}
97+
*/
98+
{{#isDeprecated}}
99+
@Deprecated
100+
{{/isDeprecated}}
101+
public ResponseEntity<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{operationId}}WithHttpInfo({{#allParams}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws RestClientException {
64102
Object {{localVariablePrefix}}postBody = {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}};
65103
{{#allParams}}{{#required}}
66104
// verify the required parameter '{{paramName}}' is set
@@ -72,18 +110,18 @@ public class {{classname}} {
72110
final Map<String, Object> uriVariables = new HashMap<String, Object>();{{#pathParams}}
73111
uriVariables.put("{{baseName}}", {{{paramName}}});{{/pathParams}}{{/hasPathParams}}
74112
String {{localVariablePrefix}}path = UriComponentsBuilder.fromPath("{{{path}}}"){{#hasPathParams}}.buildAndExpand(uriVariables){{/hasPathParams}}{{^hasPathParams}}.build(){{/hasPathParams}}.toUriString();
75-
113+
76114
final MultiValueMap<String, String> {{localVariablePrefix}}queryParams = new LinkedMultiValueMap<String, String>();
77115
final HttpHeaders {{localVariablePrefix}}headerParams = new HttpHeaders();
78116
final MultiValueMap<String, Object> {{localVariablePrefix}}formParams = new LinkedMultiValueMap<String, Object>();{{#hasQueryParams}}
79-
117+
80118
{{#queryParams}}{{localVariablePrefix}}queryParams.putAll({{localVariablePrefix}}apiClient.parameterToMultiValueMap({{#collectionFormat}}ApiClient.CollectionFormat.valueOf("{{{collectionFormat}}}".toUpperCase()){{/collectionFormat}}{{^collectionFormat}}null{{/collectionFormat}}, "{{baseName}}", {{paramName}}));{{#hasMore}}
81119
{{/hasMore}}{{/queryParams}}{{/hasQueryParams}}{{#hasHeaderParams}}
82-
120+
83121
{{#headerParams}}if ({{paramName}} != null)
84122
{{localVariablePrefix}}headerParams.add("{{baseName}}", {{localVariablePrefix}}apiClient.parameterToString({{paramName}}));{{#hasMore}}
85123
{{/hasMore}}{{/headerParams}}{{/hasHeaderParams}}{{#hasFormParams}}
86-
124+
87125
{{#formParams}}if ({{paramName}} != null)
88126
{{localVariablePrefix}}formParams.add("{{baseName}}", {{#isFile}}new FileSystemResource({{paramName}}){{/isFile}}{{^isFile}}{{paramName}}{{/isFile}});{{#hasMore}}
89127
{{/hasMore}}{{/formParams}}{{/hasFormParams}}
@@ -100,7 +138,7 @@ public class {{classname}} {
100138
String[] {{localVariablePrefix}}authNames = new String[] { {{#authMethods}}"{{name}}"{{#hasMore}}, {{/hasMore}}{{/authMethods}} };
101139

102140
{{#returnType}}ParameterizedTypeReference<{{{returnType}}}> {{localVariablePrefix}}returnType = new ParameterizedTypeReference<{{{returnType}}}>() {};{{/returnType}}{{^returnType}}ParameterizedTypeReference<Void> {{localVariablePrefix}}returnType = new ParameterizedTypeReference<Void>() {};{{/returnType}}
103-
{{#returnType}}return {{/returnType}}{{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}path, HttpMethod.{{httpMethod}}, {{localVariablePrefix}}queryParams, {{localVariablePrefix}}postBody, {{localVariablePrefix}}headerParams, {{localVariablePrefix}}formParams, {{localVariablePrefix}}accept, {{localVariablePrefix}}contentType, {{localVariablePrefix}}authNames, {{localVariablePrefix}}returnType);
141+
return {{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}path, HttpMethod.{{httpMethod}}, {{localVariablePrefix}}queryParams, {{localVariablePrefix}}postBody, {{localVariablePrefix}}headerParams, {{localVariablePrefix}}formParams, {{localVariablePrefix}}accept, {{localVariablePrefix}}contentType, {{localVariablePrefix}}authNames, {{localVariablePrefix}}returnType);
104142
}
105143
{{/operation}}
106144
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.4.8-SNAPSHOT
1+
2.4.9-SNAPSHOT
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.4.8-SNAPSHOT
1+
2.4.9-SNAPSHOT

samples/client/petstore/java/resttemplate/src/main/java/io/swagger/client/ApiClient.java

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,6 @@ private String collectionToString(Collection<? extends CharSequence> collection)
8080
private RestTemplate restTemplate;
8181

8282
private Map<String, Authentication> authentications;
83-
84-
private HttpStatus statusCode;
85-
private MultiValueMap<String, String> responseHeaders;
8683

8784
private DateFormat dateFormat;
8885

@@ -136,22 +133,6 @@ public ApiClient setBasePath(String basePath) {
136133
return this;
137134
}
138135

139-
/**
140-
* Gets the status code of the previous request
141-
* @return HttpStatus the status code
142-
*/
143-
public HttpStatus getStatusCode() {
144-
return statusCode;
145-
}
146-
147-
/**
148-
* Gets the response headers of the previous request
149-
* @return MultiValueMap a map of response headers
150-
*/
151-
public MultiValueMap<String, String> getResponseHeaders() {
152-
return responseHeaders;
153-
}
154-
155136
/**
156137
* Get authentications (key: authentication name, value: authentication).
157138
* @return Map the currently configured authentication types
@@ -508,9 +489,9 @@ protected Object selectBody(Object obj, MultiValueMap<String, Object> formParams
508489
* @param contentType The request's Content-Type header
509490
* @param authNames The authentications to apply
510491
* @param returnType The return type into which to deserialize the response
511-
* @return The response body in chosen type
492+
* @return ResponseEntity&lt;T&gt; The response of the chosen type
512493
*/
513-
public <T> T invokeAPI(String path, HttpMethod method, MultiValueMap<String, String> queryParams, Object body, HttpHeaders headerParams, MultiValueMap<String, Object> formParams, List<MediaType> accept, MediaType contentType, String[] authNames, ParameterizedTypeReference<T> returnType) throws RestClientException {
494+
public <T> ResponseEntity<T> invokeAPI(String path, HttpMethod method, MultiValueMap<String, String> queryParams, Object body, HttpHeaders headerParams, MultiValueMap<String, Object> formParams, List<MediaType> accept, MediaType contentType, String[] authNames, ParameterizedTypeReference<T> returnType) throws RestClientException {
514495
updateParamsForAuth(authNames, queryParams, headerParams);
515496

516497
final UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(basePath).path(path);
@@ -532,20 +513,12 @@ public <T> T invokeAPI(String path, HttpMethod method, MultiValueMap<String, Str
532513
RequestEntity<Object> requestEntity = requestBuilder.body(selectBody(body, formParams, contentType));
533514

534515
ResponseEntity<T> responseEntity = restTemplate.exchange(requestEntity, returnType);
535-
536-
statusCode = responseEntity.getStatusCode();
537-
responseHeaders = responseEntity.getHeaders();
538516

539-
if (responseEntity.getStatusCode() == HttpStatus.NO_CONTENT) {
540-
return null;
541-
} else if (responseEntity.getStatusCode().is2xxSuccessful()) {
542-
if (returnType == null) {
543-
return null;
544-
}
545-
return responseEntity.getBody();
517+
if (responseEntity.getStatusCode().is2xxSuccessful()) {
518+
return responseEntity;
546519
} else {
547520
// The error handler built into the RestTemplate should handle 400 and 500 series errors.
548-
throw new RestClientException("API returned " + statusCode + " and it wasn't handled by the RestTemplate error handler");
521+
throw new RestClientException("API returned " + responseEntity.getStatusCode() + " and it wasn't handled by the RestTemplate error handler");
549522
}
550523
}
551524

samples/client/petstore/java/resttemplate/src/main/java/io/swagger/client/api/AnotherFakeApi.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.springframework.http.HttpMethod;
2323
import org.springframework.http.HttpStatus;
2424
import org.springframework.http.MediaType;
25+
import org.springframework.http.ResponseEntity;
2526

2627

2728
@Component("io.swagger.client.api.AnotherFakeApi")
@@ -49,11 +50,23 @@ public void setApiClient(ApiClient apiClient) {
4950
* To test special tags
5051
* To test special tags
5152
* <p><b>200</b> - successful operation
52-
* @param body client model
53+
* @param body client model (required)
5354
* @return Client
5455
* @throws RestClientException if an error occurs while attempting to invoke the API
5556
*/
5657
public Client testSpecialTags(Client body) throws RestClientException {
58+
return testSpecialTagsWithHttpInfo(body).getBody();
59+
}
60+
61+
/**
62+
* To test special tags
63+
* To test special tags
64+
* <p><b>200</b> - successful operation
65+
* @param body client model (required)
66+
* @return ResponseEntity&lt;Client&gt;
67+
* @throws RestClientException if an error occurs while attempting to invoke the API
68+
*/
69+
public ResponseEntity<Client> testSpecialTagsWithHttpInfo(Client body) throws RestClientException {
5770
Object postBody = body;
5871

5972
// verify the required parameter 'body' is set
@@ -62,7 +75,7 @@ public Client testSpecialTags(Client body) throws RestClientException {
6275
}
6376

6477
String path = UriComponentsBuilder.fromPath("/another-fake/dummy").build().toUriString();
65-
78+
6679
final MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<String, String>();
6780
final HttpHeaders headerParams = new HttpHeaders();
6881
final MultiValueMap<String, Object> formParams = new LinkedMultiValueMap<String, Object>();

0 commit comments

Comments
 (0)