Skip to content

Commit 4c0edc2

Browse files
committed
SPR-5515: NPE when passing null as a request to RestTemplate.postForLocation
1 parent 2d07054 commit 4c0edc2

File tree

3 files changed

+117
-75
lines changed

3 files changed

+117
-75
lines changed

org.springframework.web/src/main/java/org/springframework/web/client/RestOperations.java

Lines changed: 43 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package org.springframework.web.client;
1818

1919
import java.net.URI;
20-
import java.util.EnumSet;
2120
import java.util.Map;
2221
import java.util.Set;
2322

@@ -40,32 +39,30 @@ public interface RestOperations {
4039
/**
4140
* Retrieve a representation by doing a GET on the specified URL.
4241
* <p>URI Template variables are expanded using the given URI variables, if any.
43-
* @param uri the URI
42+
* @param uri the URI
4443
* @param responseType the type of the return value
4544
* @param uriVariables the variables to expand the template
4645
* @return the converted object
4746
*/
48-
<T> T getForObject(String uri, Class<T> responseType, String... uriVariables)
49-
throws RestClientException;
47+
<T> T getForObject(String uri, Class<T> responseType, String... uriVariables) throws RestClientException;
5048

5149
/**
5250
* Retrieve a representation by doing a GET on the URI template.
5351
* <p>URI Template variables are expanded using the given map.
54-
* @param uri the URI
52+
* @param uri the URI
5553
* @param responseType the type of the return value
5654
* @param uriVariables the map containing variables for the URI template
5755
* @return the converted object
5856
*/
59-
<T> T getForObject(String uri, Class<T> responseType, Map<String, String> uriVariables)
60-
throws RestClientException;
57+
<T> T getForObject(String uri, Class<T> responseType, Map<String, String> uriVariables) throws RestClientException;
6158

6259

6360
// HEAD
6461

6562
/**
6663
* Retrieve all headers of the resource specified by the URI template.
6764
* <p>URI Template variables are expanded using the given URI variables, if any.
68-
* @param uri the URI
65+
* @param uri the URI
6966
* @param uriVariables the variables to expand the template
7067
* @return all HTTP headers of that resource
7168
*/
@@ -74,7 +71,7 @@ <T> T getForObject(String uri, Class<T> responseType, Map<String, String> uriVar
7471
/**
7572
* Retrieve all headers of the resource specified by the URI template.
7673
* <p>URI Template variables are expanded using the given map.
77-
* @param uri the URI
74+
* @param uri the URI
7875
* @param uriVariables the map containing variables for the URI template
7976
* @return all HTTP headers of that resource
8077
*/
@@ -84,45 +81,43 @@ <T> T getForObject(String uri, Class<T> responseType, Map<String, String> uriVar
8481
// POST
8582

8683
/**
87-
* Create a new resource by POSTing the given object to the URI template. The value of the <code>Location</code>,
88-
* indicating where the new resource is stored, is returned.
84+
* Create a new resource by POSTing the given object to the URI template. The value of the <code>Location</code>
85+
* header, indicating where the new resource is stored, is returned.
8986
* <p>URI Template variables are expanded using the given URI variables, if any.
90-
* @param uri the URI
91-
* @param request the Object to be POSTED
87+
* @param uri the URI
88+
* @param request the Object to be POSTed, may be <code>null</code>
9289
* @return the value for the <code>Location</code> header
9390
*/
94-
URI postForLocation(String uri, Object request, String... uriVariables)
95-
throws RestClientException;
91+
URI postForLocation(String uri, Object request, String... uriVariables) throws RestClientException;
9692

9793
/**
98-
* Create a new resource by POSTing the given object to URI template. The value of the <code>Location</code>,
94+
* Create a new resource by POSTing the given object to URI template. The value of the <code>Location</code> header,
9995
* indicating where the new resource is stored, is returned.
10096
* <p>URI Template variables are expanded using the given map.
101-
* @param uri the URI
102-
* @param request the Object to be POSTed
97+
* @param uri the URI
98+
* @param request the Object to be POSTed, may be <code>null</code>
10399
* @param uriVariables the variables to expand the template
104100
* @return the value for the <code>Location</code> header
105101
*/
106-
URI postForLocation(String uri, Object request, Map<String, String> uriVariables)
107-
throws RestClientException;
102+
URI postForLocation(String uri, Object request, Map<String, String> uriVariables) throws RestClientException;
108103

109104

110105
// PUT
111106

112107
/**
113108
* Create or update a resource by PUTting the given object to the URI.
114109
* <p>URI Template variables are expanded using the given URI variables, if any.
115-
* @param uri the URI
116-
* @param request the Object to be POSTed
110+
* @param uri the URI
111+
* @param request the Object to be PUT, may be <code>null</code>
117112
* @param uriVariables the variables to expand the template
118113
*/
119114
void put(String uri, Object request, String... uriVariables) throws RestClientException;
120115

121116
/**
122117
* Creates a new resource by PUTting the given object to URI template.
123118
* <p>URI Template variables are expanded using the given map.
124-
* @param uri the URI
125-
* @param request the Object to be POSTed
119+
* @param uri the URI
120+
* @param request the Object to be PUT, may be <code>null</code>
126121
* @param uriVariables the variables to expand the template
127122
*/
128123
void put(String uri, Object request, Map<String, String> uriVariables) throws RestClientException;
@@ -133,15 +128,15 @@ URI postForLocation(String uri, Object request, Map<String, String> uriVariables
133128
/**
134129
* Delete the resources at the specified URI.
135130
* <p>URI Template variables are expanded using the given URI variables, if any.
136-
* @param uri the URI
131+
* @param uri the URI
137132
* @param uriVariables the variables to expand in the template
138133
*/
139134
void delete(String uri, String... uriVariables) throws RestClientException;
140135

141136
/**
142137
* Delete the resources at the specified URI.
143138
* <p>URI Template variables are expanded using the given map.
144-
* @param uri the URI
139+
* @param uri the URI
145140
* @param uriVariables the variables to expand the template
146141
*/
147142
void delete(String uri, Map<String, String> uriVariables) throws RestClientException;
@@ -152,22 +147,20 @@ URI postForLocation(String uri, Object request, Map<String, String> uriVariables
152147
/**
153148
* Return the value of the Allow header for the given URI.
154149
* <p>URI Template variables are expanded using the given URI variables, if any.
155-
* @param uri the URI
150+
* @param uri the URI
156151
* @param uriVariables the variables to expand in the template
157152
* @return the value of the allow header
158153
*/
159-
Set<HttpMethod> optionsForAllow(String uri, String... uriVariables)
160-
throws RestClientException;
154+
Set<HttpMethod> optionsForAllow(String uri, String... uriVariables) throws RestClientException;
161155

162156
/**
163157
* Return the value of the Allow header for the given URI.
164158
* <p>URI Template variables are expanded using the given map.
165-
* @param uri the URI
159+
* @param uri the URI
166160
* @param uriVariables the variables to expand in the template
167161
* @return the value of the allow header
168162
*/
169-
Set<HttpMethod> optionsForAllow(String uri, Map<String, String> uriVariables)
170-
throws RestClientException;
163+
Set<HttpMethod> optionsForAllow(String uri, Map<String, String> uriVariables) throws RestClientException;
171164

172165

173166
// general execution
@@ -176,30 +169,34 @@ Set<HttpMethod> optionsForAllow(String uri, Map<String, String> uriVariables)
176169
* Execute the HTTP methods to the given URI, preparing the request with the {@link RequestCallback},
177170
* and reading the response with a {@link ResponseExtractor}.
178171
* <p>URI Template variables are expanded using the given URI variables, if any.
179-
* @param uri the URI
180-
* @param method the HTTP method (GET, POST, etc)
181-
* @param requestCallback object that prepares the request
172+
* @param uri the URI
173+
* @param method the HTTP method (GET, POST, etc)
174+
* @param requestCallback object that prepares the request
182175
* @param responseExtractor object that extracts the return value from the response
183-
* @param uriVariables the variables to expand in the template
176+
* @param uriVariables the variables to expand in the template
184177
* @return an arbitrary object, as returned by the {@link ResponseExtractor}
185178
*/
186-
<T> T execute(String uri, HttpMethod method, RequestCallback requestCallback,
187-
ResponseExtractor<T> responseExtractor, String... uriVariables)
188-
throws RestClientException;
179+
<T> T execute(String uri,
180+
HttpMethod method,
181+
RequestCallback requestCallback,
182+
ResponseExtractor<T> responseExtractor,
183+
String... uriVariables) throws RestClientException;
189184

190185
/**
191186
* Execute the HTTP methods to the given URI, preparing the request with the {@link RequestCallback},
192187
* and reading the response with a {@link ResponseExtractor}.
193188
* <p>URI Template variables are expanded using the given URI variables map.
194-
* @param uri the URI
195-
* @param method the HTTP method (GET, POST, etc)
196-
* @param requestCallback object that prepares the request
189+
* @param uri the URI
190+
* @param method the HTTP method (GET, POST, etc)
191+
* @param requestCallback object that prepares the request
197192
* @param responseExtractor object that extracts the return value from the response
198-
* @param uriVariablesthe variables to expand in the template
193+
* @param uriVariables the variables to expand in the template
199194
* @return an arbitrary object, as returned by the {@link ResponseExtractor}
200195
*/
201-
<T> T execute(String uri, HttpMethod method, RequestCallback requestCallback,
202-
ResponseExtractor<T> responseExtractor, Map<String, String> uriVariables)
203-
throws RestClientException;
196+
<T> T execute(String uri,
197+
HttpMethod method,
198+
RequestCallback requestCallback,
199+
ResponseExtractor<T> responseExtractor,
200+
Map<String, String> uriVariables) throws RestClientException;
204201

205202
}

org.springframework.web/src/main/java/org/springframework/web/client/RestTemplate.java

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,13 @@ public class RestTemplate extends HttpAccessor implements RestOperations {
9191
private final ResponseExtractor<HttpHeaders> headersExtractor = new HeadersExtractor();
9292

9393
private HttpMessageConverter<?>[] messageConverters =
94-
new HttpMessageConverter[] {new ByteArrayHttpMessageConverter(), new StringHttpMessageConverter()};
94+
new HttpMessageConverter[]{new ByteArrayHttpMessageConverter(), new StringHttpMessageConverter()};
9595

9696
private ResponseErrorHandler errorHandler = new DefaultResponseErrorHandler();
9797

9898

9999
/**
100100
* Create a new instance of the {@link RestTemplate} using default settings.
101-
* @see #initDefaultStrategies()
102101
*/
103102
public RestTemplate() {
104103
}
@@ -166,8 +165,7 @@ public ResponseErrorHandler getErrorHandler() {
166165

167166
// GET
168167

169-
public <T> T getForObject(String url, Class<T> responseType, String... urlVariables)
170-
throws RestClientException {
168+
public <T> T getForObject(String url, Class<T> responseType, String... urlVariables) throws RestClientException {
171169

172170
checkForSupportedMessageConverter(responseType);
173171
return execute(url, HttpMethod.GET, new GetCallback<T>(responseType),
@@ -196,19 +194,20 @@ public HttpHeaders headForHeaders(String url, Map<String, String> urlVariables)
196194

197195
// POST
198196

199-
public URI postForLocation(String url, Object request, String... urlVariables)
200-
throws RestClientException {
201-
202-
checkForSupportedMessageConverter(request.getClass());
197+
public URI postForLocation(String url, Object request, String... urlVariables) throws RestClientException {
198+
if (request != null) {
199+
checkForSupportedMessageConverter(request.getClass());
200+
}
203201
HttpHeaders headers =
204202
execute(url, HttpMethod.POST, new PostPutCallback(request), this.headersExtractor, urlVariables);
205203
return headers.getLocation();
206204
}
207205

208206
public URI postForLocation(String url, Object request, Map<String, String> urlVariables)
209207
throws RestClientException {
210-
211-
checkForSupportedMessageConverter(request.getClass());
208+
if (request != null) {
209+
checkForSupportedMessageConverter(request.getClass());
210+
}
212211
HttpHeaders headers =
213212
execute(url, HttpMethod.POST, new PostPutCallback(request), this.headersExtractor, urlVariables);
214213
return headers.getLocation();
@@ -218,12 +217,16 @@ public URI postForLocation(String url, Object request, Map<String, String> urlVa
218217
// PUT
219218

220219
public void put(String url, Object request, String... urlVariables) throws RestClientException {
221-
checkForSupportedMessageConverter(request.getClass());
220+
if (request != null) {
221+
checkForSupportedMessageConverter(request.getClass());
222+
}
222223
execute(url, HttpMethod.PUT, new PostPutCallback(request), null, urlVariables);
223224
}
224225

225226
public void put(String url, Object request, Map<String, String> urlVariables) throws RestClientException {
226-
checkForSupportedMessageConverter(request.getClass());
227+
if (request != null) {
228+
checkForSupportedMessageConverter(request.getClass());
229+
}
227230
execute(url, HttpMethod.PUT, new PostPutCallback(request), null, urlVariables);
228231
}
229232

@@ -241,15 +244,13 @@ public void delete(String url, Map<String, String> urlVariables) throws RestClie
241244

242245
// OPTIONS
243246

244-
public Set<HttpMethod> optionsForAllow(String url, String... urlVariables)
245-
throws RestClientException {
247+
public Set<HttpMethod> optionsForAllow(String url, String... urlVariables) throws RestClientException {
246248

247249
HttpHeaders headers = execute(url, HttpMethod.OPTIONS, null, this.headersExtractor, urlVariables);
248250
return headers.getAllow();
249251
}
250252

251-
public Set<HttpMethod> optionsForAllow(String url, Map<String, String> urlVariables)
252-
throws RestClientException {
253+
public Set<HttpMethod> optionsForAllow(String url, Map<String, String> urlVariables) throws RestClientException {
253254

254255
HttpHeaders headers = execute(url, HttpMethod.OPTIONS, null, this.headersExtractor, urlVariables);
255256
return headers.getAllow();
@@ -258,18 +259,22 @@ public Set<HttpMethod> optionsForAllow(String url, Map<String, String> urlVariab
258259

259260
// general execution
260261

261-
public <T> T execute(String url, HttpMethod method, RequestCallback requestCallback,
262-
ResponseExtractor<T> responseExtractor, String... urlVariables)
263-
throws RestClientException {
262+
public <T> T execute(String url,
263+
HttpMethod method,
264+
RequestCallback requestCallback,
265+
ResponseExtractor<T> responseExtractor,
266+
String... urlVariables) throws RestClientException {
264267

265268
UriTemplate uriTemplate = new UriTemplate(url);
266269
URI expanded = uriTemplate.expand(urlVariables);
267270
return doExecute(expanded, method, requestCallback, responseExtractor);
268271
}
269272

270-
public <T> T execute(String url,HttpMethod method, RequestCallback requestCallback,
271-
ResponseExtractor<T> responseExtractor, Map<String, String> urlVariables)
272-
throws RestClientException {
273+
public <T> T execute(String url,
274+
HttpMethod method,
275+
RequestCallback requestCallback,
276+
ResponseExtractor<T> responseExtractor,
277+
Map<String, String> urlVariables) throws RestClientException {
273278

274279
UriTemplate uriTemplate = new UriTemplate(url);
275280
URI expanded = uriTemplate.expand(urlVariables);
@@ -279,13 +284,15 @@ public <T> T execute(String url,HttpMethod method, RequestCallback requestCallba
279284
/**
280285
* Execute the given method on the provided URI. The {@link ClientHttpRequest} is processed using the {@link
281286
* RequestCallback}; the response with the {@link ResponseExtractor}.
282-
* @param url the fully-expanded URL to connect to
283-
* @param method the HTTP method to execute (GET, POST, etc.)
284-
* @param requestCallback object that prepares the request (can be <code>null</code>)
287+
* @param url the fully-expanded URL to connect to
288+
* @param method the HTTP method to execute (GET, POST, etc.)
289+
* @param requestCallback object that prepares the request (can be <code>null</code>)
285290
* @param responseExtractor object that extracts the return value from the response (can be <code>null</code>)
286291
* @return an arbitrary object, as returned by the {@link ResponseExtractor}
287292
*/
288-
protected <T> T doExecute(URI url, HttpMethod method, RequestCallback requestCallback,
293+
protected <T> T doExecute(URI url,
294+
HttpMethod method,
295+
RequestCallback requestCallback,
289296
ResponseExtractor<T> responseExtractor) throws RestClientException {
290297

291298
Assert.notNull(url, "'url' must not be null");
@@ -376,12 +383,16 @@ private PostPutCallback(Object request) {
376383

377384
@SuppressWarnings("unchecked")
378385
public void doWithRequest(ClientHttpRequest httpRequest) throws IOException {
379-
HttpMessageConverter entityConverter = getSupportedMessageConverters(this.request.getClass()).get(0);
380-
entityConverter.write(this.request, httpRequest);
386+
if (request != null) {
387+
HttpMessageConverter entityConverter = getSupportedMessageConverters(this.request.getClass()).get(0);
388+
entityConverter.write(this.request, httpRequest);
389+
}
390+
else {
391+
httpRequest.getHeaders().setContentLength(0L);
392+
}
381393
}
382394
}
383395

384-
385396
/**
386397
* Response extractor that uses the registered {@linkplain HttpMessageConverter entity converters}
387398
* to convert the response into a type <code>T</code>.

0 commit comments

Comments
 (0)