SPR-5260: RestTemplate
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.client;
|
||||
|
||||
import org.springframework.web.http.HttpStatus;
|
||||
|
||||
/**
|
||||
* Exception thrown when a HTTP 4xx is received.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see org.springframework.web.client.core.SimpleHttpErrorHandler
|
||||
* @since 3.0
|
||||
*/
|
||||
public class HttpClientErrorException extends HttpStatusCodeException {
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@code HttpClientErrorException} based on a {@link HttpStatus}.
|
||||
*
|
||||
* @param statusCode the status code
|
||||
*/
|
||||
public HttpClientErrorException(HttpStatus statusCode) {
|
||||
super(statusCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@code HttpClientErrorException} based on a {@link HttpStatus} and status text.
|
||||
*
|
||||
* @param statusCode the status code
|
||||
* @param statusText the status text
|
||||
*/
|
||||
public HttpClientErrorException(HttpStatus statusCode, String statusText) {
|
||||
super(statusCode, statusText);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.client;
|
||||
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
|
||||
/**
|
||||
* Base class for exceptions thrown by the framework whenever it encounters client-side HTTP errors.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 3.0
|
||||
*/
|
||||
public class HttpClientException extends NestedRuntimeException {
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@code HttpClientException} with the given message.
|
||||
*
|
||||
* @param msg the message
|
||||
*/
|
||||
public HttpClientException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@code HttpClientException} with the given message and exception.
|
||||
*
|
||||
* @param msg the message
|
||||
* @param ex the exception
|
||||
*/
|
||||
public HttpClientException(String msg, Throwable ex) {
|
||||
super(msg, ex);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.client;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Exception thrown when a I/O error occurs.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 3.0
|
||||
*/
|
||||
public class HttpIOException extends HttpClientException {
|
||||
|
||||
/**
|
||||
* Constructs a new {@code HttpIOException} with the given message.
|
||||
*
|
||||
* @param msg the message
|
||||
*/
|
||||
public HttpIOException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code HttpIOException} with the given message and {@link IOException}.
|
||||
*
|
||||
* @param msg the message
|
||||
* @param ex the {@code IOException}
|
||||
*/
|
||||
public HttpIOException(String msg, IOException ex) {
|
||||
super(msg, ex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.client;
|
||||
|
||||
import org.springframework.web.http.HttpStatus;
|
||||
|
||||
/**
|
||||
* Exception thrown when a HTTP 5xx is received.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see org.springframework.web.client.core.SimpleHttpErrorHandler
|
||||
* @since 3.0
|
||||
*/
|
||||
public class HttpServerErrorException extends HttpStatusCodeException {
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@code HttpServerErrorException} based on a {@link HttpStatus}.
|
||||
*
|
||||
* @param statusCode the status code
|
||||
*/
|
||||
public HttpServerErrorException(HttpStatus statusCode) {
|
||||
super(statusCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@code HttpServerErrorException} based on a {@link HttpStatus} and status text.
|
||||
*
|
||||
* @param statusCode the status code
|
||||
* @param statusText the status text
|
||||
*/
|
||||
public HttpServerErrorException(HttpStatus statusCode, String statusText) {
|
||||
super(statusCode, statusText);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.client;
|
||||
|
||||
import org.springframework.web.http.HttpStatus;
|
||||
|
||||
/**
|
||||
* Abstract base class for exceptions based on a {@link HttpStatus}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 3.0
|
||||
*/
|
||||
public abstract class HttpStatusCodeException extends HttpClientException {
|
||||
|
||||
private final HttpStatus statusCode;
|
||||
|
||||
private final String statusText;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@code HttpStatusCodeException} based on a {@link HttpStatus}.
|
||||
*
|
||||
* @param statusCode the status code
|
||||
*/
|
||||
protected HttpStatusCodeException(HttpStatus statusCode) {
|
||||
super(statusCode.toString());
|
||||
this.statusCode = statusCode;
|
||||
this.statusText = statusCode.name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@code HttpStatusCodeException} based on a {@link HttpStatus} and status text.
|
||||
*
|
||||
* @param statusCode the status code
|
||||
* @param statusText the status text
|
||||
*/
|
||||
protected HttpStatusCodeException(HttpStatus statusCode, String statusText) {
|
||||
super(statusCode.value() + " " + statusText);
|
||||
this.statusCode = statusCode;
|
||||
this.statusText = statusText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTTP status code.
|
||||
*/
|
||||
public HttpStatus getStatusCode() {
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTTP status text.
|
||||
*/
|
||||
public String getStatusText() {
|
||||
return statusText;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.client.core;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.web.http.client.ClientHttpResponse;
|
||||
|
||||
/**
|
||||
* Strategy interface used by the {@link RestTemplate} to determine whether a particular response has an error or not.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface HttpErrorHandler {
|
||||
|
||||
/**
|
||||
* Indicates whether the given response has any errors.
|
||||
*
|
||||
* Implementations will typically inspect the {@link ClientHttpResponse#getStatusCode() HttpStatus} of the response.
|
||||
*
|
||||
* @param response the response to inspect
|
||||
* @return <code>true</code> if the response has an error; <code>false</code> otherwise
|
||||
* @throws IOException in case of I/O errors
|
||||
*/
|
||||
boolean hasError(ClientHttpResponse response) throws IOException;
|
||||
|
||||
/**
|
||||
* Handles the error in the given response.
|
||||
*
|
||||
* This method is only called when {@link #hasError(ClientHttpResponse)} has returned <code>true</code>.
|
||||
*
|
||||
* @param response the response with the error
|
||||
* @throws IOException in case of I/O errors
|
||||
* @throws org.springframework.web.client.HttpClientException
|
||||
* typically thrown by implementations of this interface
|
||||
*/
|
||||
void handleError(ClientHttpResponse response) throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.client.core;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.web.http.client.ClientHttpRequest;
|
||||
|
||||
/**
|
||||
* Callback interface for code that operates on a {@link ClientHttpRequest}. Allows to manipulate the request
|
||||
* headers, and write to the request body.
|
||||
*
|
||||
* <p>Used internally by the {@link RestTemplate}, but also useful for application code.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see RestTemplate#execute
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface HttpRequestCallback {
|
||||
|
||||
/**
|
||||
* Gets called by {@link RestTemplate#execute} with an opened {@code ClientHttpRequest}. Does not need to care about
|
||||
* closing the request, handling I/O errors, or about handling errors: this will all be handled by the {@code
|
||||
* RestTemplate}.
|
||||
*
|
||||
* @param request the active HTTP request
|
||||
* @throws IOException in case of I/O errors
|
||||
*/
|
||||
void doWithRequest(ClientHttpRequest request) throws IOException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.client.core;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.web.http.client.ClientHttpResponse;
|
||||
|
||||
/**
|
||||
* Generic callback interface used by {@link RestTemplate}'s retrieval methods. Implementations of this interface
|
||||
* perform the actual work of extracting data from a {@link ClientHttpResponse}, but don't need to worry about exception
|
||||
* handling or closing resources.
|
||||
*
|
||||
* <p>Used internally by the {@link RestTemplate}, but also useful for application code.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see RestTemplate#execute
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface HttpResponseExtractor<T> {
|
||||
|
||||
/**
|
||||
* Extracts data from the given {@code ClientHttpResponse} and returns it.
|
||||
*
|
||||
* @param response the HTTP response
|
||||
* @return the extracted data
|
||||
* @throws IOException in case of I/O errors
|
||||
*/
|
||||
T extractData(ClientHttpResponse response) throws IOException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.client.core;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.web.http.HttpHeaders;
|
||||
import org.springframework.web.http.HttpMethod;
|
||||
|
||||
/**
|
||||
* Interface specifying a basic set of RESTful operations. Implemented by {@link RestTemplate}. Not often used directly,
|
||||
* but a useful option to enhance testability, as it can easily be mocked or stubbed.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see RestTemplate
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface RestOperations {
|
||||
|
||||
// GET
|
||||
|
||||
/**
|
||||
* Retrieves a representation by doing a GET on the specified URL. URI Template variables are expanded using the
|
||||
* given URI variables, if any.
|
||||
*
|
||||
* @param uri the URI to GET
|
||||
* @param responseType the type of the return value
|
||||
* @param uriVariables the variables to expand the template
|
||||
* @return the converted object
|
||||
*/
|
||||
<T> T getForObject(String uri, Class<T> responseType, String... uriVariables);
|
||||
|
||||
/**
|
||||
* Retrieves a representation by doing a GET on the URI template. URI Template variables are expanded using the
|
||||
* given map.
|
||||
*
|
||||
* @param uri the URI to GET
|
||||
* @param responseType the type of the return value
|
||||
* @param uriVariables the map containing variables for the URI template
|
||||
* @return the converted object
|
||||
*/
|
||||
<T> T getForObject(String uri, Class<T> responseType, Map<String, String> uriVariables);
|
||||
|
||||
// HEAD
|
||||
|
||||
/**
|
||||
* Retrieves all headers of the resource specified by the URI template. URI Template variables are expanded using
|
||||
* the given URI variables, if any.
|
||||
*
|
||||
* @param uri the URI
|
||||
* @param uriVariables the variables to expand the template
|
||||
* @return all HTTP headers of that resource
|
||||
*/
|
||||
HttpHeaders headForHeaders(String uri, String... uriVariables);
|
||||
|
||||
/**
|
||||
* Retrieves all headers of the resource specified by the URI template. URI Template variables are expanded using
|
||||
* the given map.
|
||||
*
|
||||
* @param uri the URI
|
||||
* @param uriVariables the map containing variables for the URI template
|
||||
* @return all HTTP headers of that resource
|
||||
*/
|
||||
HttpHeaders headForHeaders(String uri, Map<String, String> uriVariables);
|
||||
|
||||
// POST
|
||||
|
||||
/**
|
||||
* Creates a new resource by POSTing the given object to the URI template. The value of the <code>Location</code>,
|
||||
* indicating where the new resource is stored, is returned. URI Template variables are expanded using the given URI
|
||||
* variables, if any.
|
||||
*
|
||||
* @param uri the URI
|
||||
* @param request the Object to be POSTED
|
||||
* @return the value for the <code>Location</code> header
|
||||
*/
|
||||
URI postForLocation(String uri, Object request, String... uriVariables);
|
||||
|
||||
/**
|
||||
* Creates a new resource by POSTing the given object to URI template. The value of the <code>Location</code>,
|
||||
* indicating where the new resource is stored, is returned. URI Template variables are expanded using the given
|
||||
* map.
|
||||
*
|
||||
* @param uri the URI
|
||||
* @param request the Object to be POSTed
|
||||
* @param uriVariables the variables to expand the template
|
||||
* @return the value for the <code>Location</code> header
|
||||
*/
|
||||
URI postForLocation(String uri, Object request, Map<String, String> uriVariables);
|
||||
|
||||
// PUT
|
||||
|
||||
/**
|
||||
* Creates or updates a resource by PUTting the given object to the URI. URI Template variables are expanded using
|
||||
* the given URI variables, if any.
|
||||
*
|
||||
* @param uri the URI
|
||||
* @param request the Object to be POSTed
|
||||
* @param uriVariables the variables to expand the template
|
||||
*/
|
||||
void put(String uri, Object request, String... uriVariables);
|
||||
|
||||
/**
|
||||
* Creates a new resource by PUTting the given object to URI template. URI Template variables are expanded using the
|
||||
* given map.
|
||||
*
|
||||
* @param uri the URI
|
||||
* @param request the Object to be POSTed
|
||||
* @param uriVariables the variables to expand the template
|
||||
*/
|
||||
void put(String uri, Object request, Map<String, String> uriVariables);
|
||||
|
||||
// DELETE
|
||||
|
||||
/**
|
||||
* Deletes the resources at the specified URI. URI Template variables are expanded using the given URI variables, if
|
||||
* any.
|
||||
*
|
||||
* @param uri the URI
|
||||
* @param uriVariables the variables to expand in the template
|
||||
*/
|
||||
void delete(String uri, String... uriVariables);
|
||||
|
||||
/**
|
||||
* Deletes the resources at the specified URI. URI Template variables are expanded using the given map.
|
||||
*
|
||||
* @param uri the URI
|
||||
* @param uriVariables the variables to expand the template
|
||||
*/
|
||||
void delete(String uri, Map<String, String> uriVariables);
|
||||
|
||||
//OPTIONS
|
||||
|
||||
/**
|
||||
* Returns value of the Allow header for the given URI. URI Template variables are expanded using the given URI
|
||||
* variables, if any.
|
||||
*
|
||||
* @param uri the URI
|
||||
* @param uriVariables the variables to expand in the template
|
||||
* @return the value of the allow header
|
||||
*/
|
||||
EnumSet<HttpMethod> optionsForAllow(String uri, String... uriVariables);
|
||||
|
||||
/**
|
||||
* Returns value of the Allow header for the given URI. URI Template variables are expanded using the given map.
|
||||
*
|
||||
* @param uri the URI
|
||||
* @param uriVariables the variables to expand in the template
|
||||
* @return the value of the allow header
|
||||
*/
|
||||
EnumSet<HttpMethod> optionsForAllow(String uri, Map<String, String> uriVariables);
|
||||
|
||||
/**
|
||||
* Executes the HTTP methods to the given URI, preparing the request with the {@link HttpRequestCallback}, and
|
||||
* reading the response with a {@link HttpResponseExtractor}. URI Template variables are expanded using the
|
||||
* given URI variables, if any.
|
||||
*
|
||||
* @param uri the URI
|
||||
* @param method the HTTP method (GET, POST, etc)
|
||||
* @param requestCallback object that prepares the request
|
||||
* @param responseExtractor object that extracts the return value from the response
|
||||
* @param uriVariables the variables to expand in the template
|
||||
* @return an arbitrary object, as returned by the {@link HttpResponseExtractor}
|
||||
*/
|
||||
<T> T execute(String uri,
|
||||
HttpMethod method,
|
||||
HttpRequestCallback requestCallback,
|
||||
HttpResponseExtractor<T> responseExtractor,
|
||||
String... uriVariables);
|
||||
|
||||
/**
|
||||
* Executes the HTTP methods to the given URI, preparing the request with the {@link HttpRequestCallback}, and
|
||||
* reading the response with a {@link HttpResponseExtractor}. URI Template variables are expanded using the
|
||||
* given URI variables map.
|
||||
*
|
||||
* @param uri the URI
|
||||
* @param method the HTTP method (GET, POST, etc)
|
||||
* @param requestCallback object that prepares the request
|
||||
* @param responseExtractor object that extracts the return value from the response
|
||||
* @param uriVariables the variables to expand in the template
|
||||
* @return an arbitrary object, as returned by the {@link HttpResponseExtractor}
|
||||
*/
|
||||
<T> T execute(String uri,
|
||||
HttpMethod method,
|
||||
HttpRequestCallback requestCallback,
|
||||
HttpResponseExtractor<T> responseExtractor,
|
||||
Map<String, String> uriVariables);
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,449 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.client.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.MediaType;
|
||||
import org.springframework.web.client.HttpClientException;
|
||||
import org.springframework.web.client.HttpIOException;
|
||||
import org.springframework.web.client.support.HttpAccessor;
|
||||
import org.springframework.web.converter.ByteArrayHttpMessageConverter;
|
||||
import org.springframework.web.converter.HttpMessageConverter;
|
||||
import org.springframework.web.converter.StringHttpMessageConverter;
|
||||
import org.springframework.web.http.HttpHeaders;
|
||||
import org.springframework.web.http.HttpMethod;
|
||||
import org.springframework.web.http.client.ClientHttpRequest;
|
||||
import org.springframework.web.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.web.http.client.ClientHttpResponse;
|
||||
import org.springframework.web.util.UriTemplate;
|
||||
|
||||
/**
|
||||
* <strong>The central class for client-side HTTP access.</strong>. It simplifies communication with HTTP servers, and
|
||||
* enforces RESTful principles. It handles HTTP connections, leaving application code to provide URLs (with possible
|
||||
* template variables) and extract results.
|
||||
*
|
||||
* <p>The main entry points of this template are the methods named after the five main HTTP methods:
|
||||
* <table>
|
||||
* <tr><th>HTTP method<th><th>RestTemplate methods</th></tr>
|
||||
* <tr><td>DELETE</td><td>{@link #delete}</td></tr>
|
||||
* <tr><td>GET</td><td>{@link #getForObject}</td></tr>
|
||||
* <tr><td>HEAD</td><td>{@link #headForHeaders}</td></tr>
|
||||
* <tr><td>OPTIONS</td><td>{@link #optionsForAllow}</td></tr>
|
||||
* <tr><td>POST</td><td>{@link #postForLocation}</td></tr>
|
||||
* <tr><td>PUT</td><td>{@link #put}</td></tr>
|
||||
* <tr><td>any</td><td>{@link #execute}</td></tr>
|
||||
* </table>
|
||||
*
|
||||
* <p>Each of these methods takes {@linkplain UriTemplate uri template} arguments in two forms: as a {@code String}
|
||||
* variable arguments array, or as a {@code Map<String, String>}. The string varargs variant expands the given template
|
||||
* variables in order, so that
|
||||
* <pre>
|
||||
* String result = restTemplate.getForObject("http://example.com/hotels/{hotel}/bookings/{booking}", String.class,"42", "21");
|
||||
* </pre>
|
||||
* will perform a GET on {@code http://example.com/hotels/42/bookings/21}. The map variant is explands the template
|
||||
* based on variable name, and is therefore more useful when using many variables, or when a single variable is used
|
||||
* multiple times. For example:
|
||||
* <pre>
|
||||
* Map<String, String> vars = Collections.singletonMap("hotel", 42);
|
||||
* String result = restTemplate.getForObject("http://example.com/hotels/{hotel}/rooms/{hotel}", String.class, vars);
|
||||
* </pre>
|
||||
* will perform a GET on {@code http://example.com/hotels/42/rooms/42}.
|
||||
*
|
||||
* <p>Objects passed to and returned from these methods are converted to and from HTTP messages by {@link
|
||||
* HttpMessageConverter} instances. Converters for the main mime types are registered by default, but you can also write
|
||||
* your own converter and register it via the {@link #setMessageConverters(HttpMessageConverter[]) messageConverters}
|
||||
* bean property.
|
||||
*
|
||||
* <p>This template uses a {@link org.springframework.web.http.client.SimpleClientHttpRequestFactory} and a {@link
|
||||
* SimpleHttpErrorHandler} as default strategies for for creating HTTP connections or handling HTTP errors, respectively.
|
||||
* These defaults can be overridden through the {@link #setRequestFactory(ClientHttpRequestFactory) requestFactory} and
|
||||
* {@link #setErrorHandler(HttpErrorHandler) errorHandler} bean properties.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see HttpMessageConverter
|
||||
* @see HttpRequestCallback
|
||||
* @see HttpResponseExtractor
|
||||
* @see HttpErrorHandler
|
||||
* @since 3.0
|
||||
*/
|
||||
public class RestTemplate extends HttpAccessor implements RestOperations {
|
||||
|
||||
private final HttpResponseExtractor<HttpHeaders> headersExtractor = new HeadersExtractor();
|
||||
|
||||
private HttpMessageConverter<?>[] messageConverters;
|
||||
|
||||
private HttpErrorHandler errorHandler;
|
||||
|
||||
/**
|
||||
* Creates a new instance of the {@link RestTemplate} using default settings.
|
||||
*
|
||||
* @see #initDefaultStrategies()
|
||||
*/
|
||||
public RestTemplate() {
|
||||
initDefaultStrategies();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of the {@link RestTemplate} based on the given {@link ClientHttpRequestFactory}.
|
||||
*
|
||||
* @param requestFactory HTTP request factory to use
|
||||
* @see org.springframework.web.http.client.SimpleClientHttpRequestFactory
|
||||
* @see org.springframework.web.http.client.commons.CommonsClientHttpRequestFactory
|
||||
*/
|
||||
public RestTemplate(ClientHttpRequestFactory requestFactory) {
|
||||
initDefaultStrategies();
|
||||
setRequestFactory(requestFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the default stragegies for this template.
|
||||
*
|
||||
* <p>Default implementation sets up the {@link SimpleHttpErrorHandler} and the {@link ByteArrayHttpMessageConverter} and
|
||||
* {@link StringHttpMessageConverter}.
|
||||
*/
|
||||
protected void initDefaultStrategies() {
|
||||
errorHandler = new SimpleHttpErrorHandler();
|
||||
messageConverters =
|
||||
new HttpMessageConverter[]{new ByteArrayHttpMessageConverter(), new StringHttpMessageConverter()};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array of message body converters. These converters are used to covert from and to HTTP requests and
|
||||
* responses.
|
||||
*/
|
||||
public HttpMessageConverter<?>[] getMessageConverters() {
|
||||
return messageConverters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of message body converters that support a particular type.
|
||||
*
|
||||
* @param type the type to return converters for
|
||||
* @return converts that support the given type
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> List<HttpMessageConverter<T>> getSupportedMessageConverters(Class<T> type) {
|
||||
HttpMessageConverter[] converters = getMessageConverters();
|
||||
List<HttpMessageConverter<T>> result = new ArrayList<HttpMessageConverter<T>>(converters.length);
|
||||
for (HttpMessageConverter converter : converters) {
|
||||
if (converter.supports(type)) {
|
||||
result.add((HttpMessageConverter<T>) converter);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the array of message body converters to use. These converters are used to covert from and to HTTP requests and
|
||||
* responses.
|
||||
*
|
||||
* <strong>Note</strong> that setting this property overrides the {@linkplain #initDefaultStrategies() default strategies}.
|
||||
*/
|
||||
public void setMessageConverters(HttpMessageConverter<?>[] messageConverters) {
|
||||
Assert.notEmpty(messageConverters, "'messageConverters' must not be empty");
|
||||
this.messageConverters = messageConverters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error handler. By default, this is the {@link SimpleHttpErrorHandler}.
|
||||
*/
|
||||
public HttpErrorHandler getErrorHandler() {
|
||||
return errorHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the error handler.
|
||||
*/
|
||||
public void setErrorHandler(HttpErrorHandler errorHandler) {
|
||||
Assert.notNull(errorHandler, "'errorHandler' must not be null");
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
// GET
|
||||
|
||||
public <T> T getForObject(String url, Class<T> responseType, String... urlVariables) {
|
||||
checkForSupportedEntityConverter(responseType);
|
||||
return execute(url, HttpMethod.GET, new GetCallback<T>(responseType),
|
||||
new HttpMessageConverterExtractor<T>(responseType), urlVariables);
|
||||
}
|
||||
|
||||
public <T> T getForObject(String url, Class<T> responseType, Map<String, String> urlVariables) {
|
||||
checkForSupportedEntityConverter(responseType);
|
||||
return execute(url, HttpMethod.GET, new GetCallback<T>(responseType),
|
||||
new HttpMessageConverterExtractor<T>(responseType), urlVariables);
|
||||
}
|
||||
|
||||
// POST
|
||||
|
||||
public URI postForLocation(String url, Object request, String... urlVariables) {
|
||||
checkForSupportedEntityConverter(request.getClass());
|
||||
HttpHeaders headers =
|
||||
execute(url, HttpMethod.POST, new PostPutCallback(request), headersExtractor, urlVariables);
|
||||
return headers.getLocation();
|
||||
}
|
||||
|
||||
public URI postForLocation(String url, Object request, Map<String, String> urlVariables) {
|
||||
checkForSupportedEntityConverter(request.getClass());
|
||||
HttpHeaders headers =
|
||||
execute(url, HttpMethod.POST, new PostPutCallback(request), headersExtractor, urlVariables);
|
||||
return headers.getLocation();
|
||||
}
|
||||
|
||||
// PUT
|
||||
|
||||
public void put(String url, Object request, String... urlVariables) {
|
||||
checkForSupportedEntityConverter(request.getClass());
|
||||
execute(url, HttpMethod.PUT, new PostPutCallback(request), null, urlVariables);
|
||||
}
|
||||
|
||||
public void put(String url, Object request, Map<String, String> urlVariables) {
|
||||
checkForSupportedEntityConverter(request.getClass());
|
||||
execute(url, HttpMethod.PUT, new PostPutCallback(request), null, urlVariables);
|
||||
}
|
||||
|
||||
// HEAD
|
||||
|
||||
public HttpHeaders headForHeaders(String url, String... urlVariables) {
|
||||
return execute(url, HttpMethod.HEAD, null, headersExtractor, urlVariables);
|
||||
}
|
||||
|
||||
public HttpHeaders headForHeaders(String url, Map<String, String> urlVariables) {
|
||||
return execute(url, HttpMethod.HEAD, null, headersExtractor, urlVariables);
|
||||
}
|
||||
|
||||
// DELETE
|
||||
|
||||
public void delete(String url, String... urlVariables) {
|
||||
execute(url, HttpMethod.DELETE, null, null, urlVariables);
|
||||
}
|
||||
|
||||
public void delete(String url, Map<String, String> urlVariables) {
|
||||
execute(url, HttpMethod.DELETE, null, null, urlVariables);
|
||||
}
|
||||
|
||||
// OPTIONS
|
||||
|
||||
public EnumSet<HttpMethod> optionsForAllow(String url, String... urlVariables) {
|
||||
HttpHeaders headers = execute(url, HttpMethod.OPTIONS, null, headersExtractor, urlVariables);
|
||||
return headers.getAllow();
|
||||
}
|
||||
|
||||
public EnumSet<HttpMethod> optionsForAllow(String url, Map<String, String> urlVariables) {
|
||||
HttpHeaders headers = execute(url, HttpMethod.OPTIONS, null, headersExtractor, urlVariables);
|
||||
return headers.getAllow();
|
||||
}
|
||||
|
||||
// execute
|
||||
|
||||
public <T> T execute(String url,
|
||||
HttpMethod method,
|
||||
HttpRequestCallback requestCallback,
|
||||
HttpResponseExtractor<T> responseExtractor,
|
||||
String... urlVariables) {
|
||||
UriTemplate uriTemplate = new UriTemplate(url);
|
||||
URI expanded = uriTemplate.expand(urlVariables);
|
||||
return doExecute(expanded, method, requestCallback, responseExtractor);
|
||||
}
|
||||
|
||||
public <T> T execute(String url,
|
||||
HttpMethod method,
|
||||
HttpRequestCallback requestCallback,
|
||||
HttpResponseExtractor<T> responseExtractor,
|
||||
Map<String, String> urlVariables) {
|
||||
UriTemplate uriTemplate = new UriTemplate(url);
|
||||
URI expanded = uriTemplate.expand(urlVariables);
|
||||
return doExecute(expanded, method, requestCallback, responseExtractor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given method on the provided URI. The {@link ClientHttpRequest} is processed using the {@link
|
||||
* HttpRequestCallback}; the response with the {@link HttpResponseExtractor}.
|
||||
*
|
||||
* @param url the fully-expanded URL to connect to
|
||||
* @param method the HTTP method to execute (GET, POST, etc.)
|
||||
* @param requestCallback object that prepares the request. Can be <code>null</code>.
|
||||
* @param responseExtractor object that extracts the return value from the response. Can be <code>null</code>.
|
||||
* @return an arbitrary object, as returned by the {@link HttpResponseExtractor}
|
||||
*/
|
||||
protected <T> T doExecute(URI url,
|
||||
HttpMethod method,
|
||||
HttpRequestCallback requestCallback,
|
||||
HttpResponseExtractor<T> responseExtractor) {
|
||||
Assert.notNull(url, "'url' must not be null");
|
||||
Assert.notNull(method, "'method' must not be null");
|
||||
ClientHttpResponse response = null;
|
||||
try {
|
||||
ClientHttpRequest request = createRequest(url, method);
|
||||
if (requestCallback != null) {
|
||||
requestCallback.doWithRequest(request);
|
||||
}
|
||||
response = request.execute();
|
||||
if (getErrorHandler().hasError(response)) {
|
||||
getErrorHandler().handleError(response);
|
||||
}
|
||||
if (responseExtractor != null) {
|
||||
return responseExtractor.extractData(response);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new HttpIOException("I/O error: " + ex.getMessage(), ex);
|
||||
}
|
||||
finally {
|
||||
if (response != null) {
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether any of the registered {@linkplain #setMessageConverters(HttpMessageConverter[]) message body
|
||||
* converters} can convert the given type.
|
||||
*
|
||||
* @param type the type to check for
|
||||
* @throws IllegalArgumentException if no supported entity converter can be found
|
||||
* @see HttpMessageConverter#supports(Class)
|
||||
*/
|
||||
private void checkForSupportedEntityConverter(Class type) {
|
||||
for (HttpMessageConverter<?> entityConverter : getMessageConverters()) {
|
||||
if (entityConverter.supports(type)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Could not resolve HttpMessageConverter for [" + type.getName() + "]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Request callback implementation that sets the <code>Accept</code> header based on the registered {@linkplain
|
||||
* HttpMessageConverter entity converters}.
|
||||
*/
|
||||
private class AcceptHeaderCallback implements HttpRequestCallback {
|
||||
|
||||
public void doWithRequest(ClientHttpRequest request) throws IOException {
|
||||
List<MediaType> allSupportedMediaTypes = new ArrayList<MediaType>();
|
||||
for (HttpMessageConverter<?> entityConverter : getMessageConverters()) {
|
||||
List<MediaType> supportedMediaTypes = entityConverter.getSupportedMediaTypes();
|
||||
for (MediaType supportedMediaType : supportedMediaTypes) {
|
||||
if (supportedMediaType.getCharSet() != null) {
|
||||
supportedMediaType =
|
||||
new MediaType(supportedMediaType.getType(), supportedMediaType.getSubtype());
|
||||
}
|
||||
allSupportedMediaTypes.add(supportedMediaType);
|
||||
}
|
||||
}
|
||||
Collections.sort(allSupportedMediaTypes);
|
||||
request.getHeaders().setAccept(allSupportedMediaTypes);
|
||||
}
|
||||
}
|
||||
|
||||
private class GetCallback<T> implements HttpRequestCallback {
|
||||
|
||||
private final Class<T> responseType;
|
||||
|
||||
private GetCallback(Class<T> responseType) {
|
||||
this.responseType = responseType;
|
||||
}
|
||||
|
||||
public void doWithRequest(ClientHttpRequest request) throws IOException {
|
||||
List<MediaType> allSupportedMediaTypes = new ArrayList<MediaType>();
|
||||
for (HttpMessageConverter<?> entityConverter : getSupportedMessageConverters(responseType)) {
|
||||
List<MediaType> supportedMediaTypes = entityConverter.getSupportedMediaTypes();
|
||||
for (MediaType supportedMediaType : supportedMediaTypes) {
|
||||
if (supportedMediaType.getCharSet() != null) {
|
||||
supportedMediaType =
|
||||
new MediaType(supportedMediaType.getType(), supportedMediaType.getSubtype());
|
||||
}
|
||||
allSupportedMediaTypes.add(supportedMediaType);
|
||||
}
|
||||
}
|
||||
Collections.sort(allSupportedMediaTypes);
|
||||
request.getHeaders().setAccept(allSupportedMediaTypes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension of {@link AcceptHeaderCallback} that writes the given object to the request stream.
|
||||
*/
|
||||
private class PostPutCallback implements HttpRequestCallback {
|
||||
|
||||
private final Object request;
|
||||
|
||||
private PostPutCallback(Object request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void doWithRequest(ClientHttpRequest httpRequest) throws IOException {
|
||||
for (HttpMessageConverter entityConverter : getSupportedMessageConverters(request.getClass())) {
|
||||
entityConverter.write(request, httpRequest);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Response extractor that uses the registered {@linkplain HttpMessageConverter entity converters} to convert the
|
||||
* response into a type <code>T</code>.
|
||||
*/
|
||||
private class HttpMessageConverterExtractor<T> implements HttpResponseExtractor<T> {
|
||||
|
||||
private final Class<T> responseType;
|
||||
|
||||
private HttpMessageConverterExtractor(Class<T> responseType) {
|
||||
this.responseType = responseType;
|
||||
}
|
||||
|
||||
public T extractData(ClientHttpResponse response) throws IOException {
|
||||
MediaType contentType = response.getHeaders().getContentType();
|
||||
if (contentType == null) {
|
||||
throw new HttpClientException("Cannot extract response: no Content-Type found");
|
||||
}
|
||||
for (HttpMessageConverter<T> messageConverter : getSupportedMessageConverters(responseType)) {
|
||||
for (MediaType supportedMediaType : messageConverter.getSupportedMediaTypes()) {
|
||||
if (supportedMediaType.includes(contentType)) {
|
||||
return messageConverter.read(responseType, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new HttpClientException(
|
||||
"Could not extract response: no suitable HttpMessageConverter found for " + "response type [" +
|
||||
responseType.getName() + "] and content type [" + contentType + "]");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Response extractor that extracts the response {@link HttpHeaders}.
|
||||
*/
|
||||
private static class HeadersExtractor implements HttpResponseExtractor<HttpHeaders> {
|
||||
|
||||
public HttpHeaders extractData(ClientHttpResponse response) throws IOException {
|
||||
return response.getHeaders();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.client.core;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.client.HttpClientException;
|
||||
import org.springframework.web.client.HttpServerErrorException;
|
||||
import org.springframework.web.http.HttpStatus;
|
||||
import org.springframework.web.http.client.ClientHttpResponse;
|
||||
|
||||
/**
|
||||
* Default implementation of the {@link HttpErrorHandler} interface.
|
||||
*
|
||||
* <p>This error handler checks for the status code on the {@link ClientHttpResponse}: any code with series
|
||||
* {@link HttpStatus.Series#CLIENT_ERROR} or {@link HttpStatus.Series#SERVER_ERROR} is considered to be an error.
|
||||
* This behavior can be changed by overriding the {@link #hasError(HttpStatus)} method.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see RestTemplate#setErrorHandler(HttpErrorHandler)
|
||||
* @since 3.0
|
||||
*/
|
||||
public class SimpleHttpErrorHandler implements HttpErrorHandler {
|
||||
|
||||
/**
|
||||
* Delegates to {@link #hasError(HttpStatus)} with the response status code.
|
||||
*/
|
||||
public boolean hasError(ClientHttpResponse response) throws IOException {
|
||||
return hasError(response.getStatusCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method called from {@link #hasError(ClientHttpResponse)}.
|
||||
*
|
||||
* <p>Default implementation checks if the given status code is {@link HttpStatus.Series#CLIENT_ERROR} or {@link
|
||||
* HttpStatus.Series#SERVER_ERROR}. Can be overridden in subclasses.
|
||||
*
|
||||
* @param statusCode the HTTP status code
|
||||
* @return <code>true</code> if the response has an error; <code>false</code> otherwise
|
||||
* @see HttpStatus.Series#CLIENT_ERROR
|
||||
* @see HttpStatus.Series#SERVER_ERROR
|
||||
*/
|
||||
protected boolean hasError(HttpStatus statusCode) {
|
||||
return statusCode.series() == HttpStatus.Series.CLIENT_ERROR ||
|
||||
statusCode.series() == HttpStatus.Series.SERVER_ERROR;
|
||||
}
|
||||
|
||||
public void handleError(ClientHttpResponse response) throws IOException {
|
||||
HttpStatus statusCode = response.getStatusCode();
|
||||
switch (statusCode.series()) {
|
||||
case CLIENT_ERROR:
|
||||
throw new HttpClientErrorException(statusCode, response.getStatusText());
|
||||
case SERVER_ERROR:
|
||||
throw new HttpServerErrorException(statusCode, response.getStatusText());
|
||||
default:
|
||||
throw new HttpClientException("Unknown status code [" + statusCode + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
Core package of the client-side HTTP support.
|
||||
Provides a RestTemplate class and various callback interfaces.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.client.core.support;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.client.core.RestTemplate;
|
||||
import org.springframework.web.http.client.ClientHttpRequestFactory;
|
||||
|
||||
/**
|
||||
* Convenient super class for application classes that need REST access.
|
||||
*
|
||||
* <p>Requires a {@link ClientHttpRequestFactory} or a {@link RestTemplate} instance to be set. It will create its own
|
||||
* JmsTemplate if a ConnectionFactory is passed in. A custom JmsTemplate instance can be created for a given
|
||||
* ConnectionFactory through overriding the <code>createJmsTemplate</code> method.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see #setRestTemplate(RestTemplate)
|
||||
* @see RestTemplate
|
||||
* @since 3.0
|
||||
*/
|
||||
public class RestGatewaySupport {
|
||||
|
||||
/**
|
||||
* Logger available to subclasses.
|
||||
*/
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the {@link RestGatewaySupport}, with default parameters.
|
||||
*
|
||||
* @see RestTemplate#RestTemplate()
|
||||
*/
|
||||
public RestGatewaySupport() {
|
||||
restTemplate = new RestTemplate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the {@link RestGatewaySupport}, with the given {@link ClientHttpRequestFactory}.
|
||||
*
|
||||
* @see RestTemplate#RestTemplate(ClientHttpRequestFactory
|
||||
*/
|
||||
public RestGatewaySupport(ClientHttpRequestFactory requestFactory) {
|
||||
Assert.notNull(requestFactory, "'requestFactory' must not be null");
|
||||
this.restTemplate = new RestTemplate(requestFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link RestTemplate} for the gateway.
|
||||
*/
|
||||
public RestTemplate getRestTemplate() {
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link RestTemplate} for the gateway.
|
||||
*/
|
||||
public void setRestTemplate(RestTemplate restTemplate) {
|
||||
Assert.notNull(restTemplate, "'restTemplate' must not be null");
|
||||
this.restTemplate = restTemplate;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
Classes supporting the org.springframework.web.client.core package.
|
||||
Contains a base class for RestTemplate usage.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
This package contains integration classes for client-side access of HTTP services.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.client.support;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.http.HttpMethod;
|
||||
import org.springframework.web.http.client.ClientHttpRequest;
|
||||
import org.springframework.web.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.web.http.client.SimpleClientHttpRequestFactory;
|
||||
|
||||
/**
|
||||
* Base class for {@link org.springframework.web.client.core.RestTemplate} and other HTTP accessing gateway helpers, defining
|
||||
* common properties such as the {@link ClientHttpRequestFactory} to operate on.
|
||||
* <p/>
|
||||
* Not intended to be used directly. See {@link org.springframework.web.client.core.RestTemplate}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see org.springframework.web.client.core.RestTemplate
|
||||
*/
|
||||
public abstract class HttpAccessor {
|
||||
|
||||
/**
|
||||
* Logger available to subclasses.
|
||||
*/
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
|
||||
|
||||
/**
|
||||
* Returns the request factory that this accessor uses for obtaining {@link ClientHttpRequest HttpRequests}
|
||||
*/
|
||||
public ClientHttpRequestFactory getRequestFactory() {
|
||||
return requestFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the request factory that this accessor uses for obtaining {@link ClientHttpRequest HttpRequests}
|
||||
*/
|
||||
public void setRequestFactory(ClientHttpRequestFactory requestFactory) {
|
||||
Assert.notNull(requestFactory, "'requestFactory' must not be null");
|
||||
this.requestFactory = requestFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ClientHttpRequest} via this template's {@link ClientHttpRequestFactory}.
|
||||
*
|
||||
* @param url the URL to connect to
|
||||
* @param method the HTTP method to exectute (GET, POST, etc.)
|
||||
* @return the created request
|
||||
* @throws IOException in case of I/O errors
|
||||
*/
|
||||
protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
|
||||
ClientHttpRequest request = getRequestFactory().createRequest(url, method);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Created " + method.name() + " request for \"" + url + "\"");
|
||||
}
|
||||
return request;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
This package provides generic HTTP support classes,
|
||||
to be used by higher-level classes like RestTemplate.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.client.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.EnumSet;
|
||||
import javax.servlet.GenericServlet;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.mortbay.jetty.Server;
|
||||
import org.mortbay.jetty.servlet.Context;
|
||||
import org.mortbay.jetty.servlet.ServletHolder;
|
||||
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.client.HttpServerErrorException;
|
||||
import org.springframework.web.http.HttpMethod;
|
||||
import org.springframework.web.http.client.commons.CommonsClientHttpRequestFactory;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public class RestTemplateIntegrationTests {
|
||||
|
||||
private RestTemplate template;
|
||||
|
||||
private static Server jettyServer;
|
||||
|
||||
@BeforeClass
|
||||
public static void startJettyServer() throws Exception {
|
||||
jettyServer = new Server(8889);
|
||||
Context jettyContext = new Context(jettyServer, "/");
|
||||
String s = "H\u00e9llo W\u00f6rld";
|
||||
byte[] bytes = s.getBytes("UTF-8");
|
||||
jettyContext.addServlet(new ServletHolder(new GetServlet(bytes, "text/plain;charset=utf-8")), "/get");
|
||||
jettyContext
|
||||
.addServlet(new ServletHolder(new PostServlet(s, new URI("http://localhost:8889/post/1"))), "/post");
|
||||
jettyContext.addServlet(new ServletHolder(new ErrorServlet(404)), "/errors/notfound");
|
||||
jettyContext.addServlet(new ServletHolder(new ErrorServlet(500)), "/errors/server");
|
||||
jettyServer.start();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void createTemplate() {
|
||||
// template = new RestTemplate();
|
||||
template = new RestTemplate(new CommonsClientHttpRequestFactory());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopJettyServer() throws Exception {
|
||||
if (jettyServer != null) {
|
||||
jettyServer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getString() {
|
||||
String s = template.getForObject("http://localhost:8889/{method}", String.class, "get");
|
||||
assertEquals("Invalid content", "H\u00e9llo W\u00f6rld", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postString() throws URISyntaxException {
|
||||
URI location = template.postForLocation("http://localhost:8889/{method}", "H\u00e9llo W\u00f6rld", "post");
|
||||
assertEquals("Invalid location", new URI("http://localhost:8889/post/1"), location);
|
||||
}
|
||||
|
||||
@Test(expected = HttpClientErrorException.class)
|
||||
public void notFound() {
|
||||
template.execute("http://localhost:8889/errors/notfound", HttpMethod.GET, null, null);
|
||||
}
|
||||
|
||||
@Test(expected = HttpServerErrorException.class)
|
||||
public void serverError() {
|
||||
template.execute("http://localhost:8889/errors/server", HttpMethod.GET, null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void optionsForAllow() {
|
||||
EnumSet<HttpMethod> allowed = template.optionsForAllow("http://localhost:8889/get");
|
||||
assertEquals("Invalid response",
|
||||
EnumSet.of(HttpMethod.GET, HttpMethod.OPTIONS, HttpMethod.HEAD, HttpMethod.TRACE), allowed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Servlet that returns and error message for a given status code.
|
||||
*/
|
||||
private static class ErrorServlet extends GenericServlet {
|
||||
|
||||
private final int sc;
|
||||
|
||||
private ErrorServlet(int sc) {
|
||||
this.sc = sc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
|
||||
((HttpServletResponse) response).sendError(sc);
|
||||
}
|
||||
}
|
||||
|
||||
private static class GetServlet extends HttpServlet {
|
||||
|
||||
private final byte[] buf;
|
||||
|
||||
private final String contentType;
|
||||
|
||||
private GetServlet(byte[] buf, String contentType) {
|
||||
this.buf = buf;
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
response.setContentLength(buf.length);
|
||||
response.setContentType(contentType);
|
||||
FileCopyUtils.copy(buf, response.getOutputStream());
|
||||
}
|
||||
}
|
||||
|
||||
private static class PostServlet extends HttpServlet {
|
||||
|
||||
private final String s;
|
||||
|
||||
private final URI location;
|
||||
|
||||
private PostServlet(String s, URI location) {
|
||||
this.s = s;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
assertTrue("Invalid request content-length", request.getContentLength() > 0);
|
||||
assertNotNull("No content-type", request.getContentType());
|
||||
String body = FileCopyUtils.copyToString(request.getReader());
|
||||
assertEquals("Invalid request body", s, body);
|
||||
response.setStatus(HttpServletResponse.SC_CREATED);
|
||||
response.setHeader("Location", location.toASCIIString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.client.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.easymock.EasyMock.*;
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.util.MediaType;
|
||||
import org.springframework.web.client.HttpClientException;
|
||||
import org.springframework.web.client.HttpIOException;
|
||||
import org.springframework.web.client.HttpServerErrorException;
|
||||
import org.springframework.web.converter.ByteArrayHttpMessageConverter;
|
||||
import org.springframework.web.converter.HttpMessageConverter;
|
||||
import org.springframework.web.converter.StringHttpMessageConverter;
|
||||
import org.springframework.web.http.HttpHeaders;
|
||||
import org.springframework.web.http.HttpMethod;
|
||||
import org.springframework.web.http.HttpStatus;
|
||||
import org.springframework.web.http.client.ClientHttpRequest;
|
||||
import org.springframework.web.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.web.http.client.ClientHttpResponse;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class RestTemplateTest {
|
||||
|
||||
private RestTemplate template;
|
||||
|
||||
private ClientHttpRequestFactory requestFactory;
|
||||
|
||||
private ClientHttpRequest request;
|
||||
|
||||
private ClientHttpResponse response;
|
||||
|
||||
private HttpErrorHandler errorHandler;
|
||||
|
||||
private HttpMessageConverter converter;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
requestFactory = createMock(ClientHttpRequestFactory.class);
|
||||
request = createMock(ClientHttpRequest.class);
|
||||
response = createMock(ClientHttpResponse.class);
|
||||
errorHandler = createMock(HttpErrorHandler.class);
|
||||
converter = createMock(HttpMessageConverter.class);
|
||||
template = new RestTemplate(requestFactory);
|
||||
template.setErrorHandler(errorHandler);
|
||||
template.setMessageConverters(new HttpMessageConverter<?>[]{converter});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSupportedMessageBodyConverters() {
|
||||
ByteArrayHttpMessageConverter byteArrayConverter = new ByteArrayHttpMessageConverter();
|
||||
StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
|
||||
template.setMessageConverters(new HttpMessageConverter<?>[]{byteArrayConverter, stringConverter});
|
||||
|
||||
List<HttpMessageConverter<String>> result = template.getSupportedMessageConverters(String.class);
|
||||
assertEquals("Invalid amount of String converters", 1, result.size());
|
||||
assertEquals("Invalid String converters", stringConverter, result.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void varArgsTemplateVariables() throws Exception {
|
||||
expect(requestFactory.createRequest(new URI("http://example.com/hotels/42/bookings/21"), HttpMethod.GET))
|
||||
.andReturn(request);
|
||||
expect(request.execute()).andReturn(response);
|
||||
expect(errorHandler.hasError(response)).andReturn(false);
|
||||
response.close();
|
||||
|
||||
replayMocks();
|
||||
|
||||
template.execute("http://example.com/hotels/{hotel}/bookings/{booking}", HttpMethod.GET, null, null, "42",
|
||||
"21");
|
||||
|
||||
verifyMocks();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mapTemplateVariables() throws Exception {
|
||||
expect(requestFactory.createRequest(new URI("http://example.com/hotels/42/bookings/42"), HttpMethod.GET))
|
||||
.andReturn(request);
|
||||
expect(request.execute()).andReturn(response);
|
||||
expect(errorHandler.hasError(response)).andReturn(false);
|
||||
response.close();
|
||||
|
||||
replayMocks();
|
||||
|
||||
Map<String, String> vars = Collections.singletonMap("hotel", "42");
|
||||
template.execute("http://example.com/hotels/{hotel}/bookings/{hotel}", HttpMethod.GET, null, null, vars);
|
||||
|
||||
verifyMocks();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void errorHandling() throws Exception {
|
||||
expect(requestFactory.createRequest(new URI("http://example.com"), HttpMethod.GET)).andReturn(request);
|
||||
expect(request.execute()).andReturn(response);
|
||||
expect(errorHandler.hasError(response)).andReturn(true);
|
||||
errorHandler.handleError(response);
|
||||
expectLastCall().andThrow(new HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR));
|
||||
response.close();
|
||||
|
||||
replayMocks();
|
||||
|
||||
try {
|
||||
template.execute("http://example.com", HttpMethod.GET, null, null);
|
||||
fail("HttpServerErrorException expected");
|
||||
}
|
||||
catch (HttpServerErrorException ex) {
|
||||
// expected
|
||||
}
|
||||
verifyMocks();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getForObject() throws Exception {
|
||||
expect(converter.supports(String.class)).andReturn(true).times(3);
|
||||
MediaType textPlain = new MediaType("text", "plain");
|
||||
expect(converter.getSupportedMediaTypes()).andReturn(Collections.singletonList(textPlain)).times(2);
|
||||
expect(requestFactory.createRequest(new URI("http://example.com"), HttpMethod.GET)).andReturn(request);
|
||||
HttpHeaders requestHeaders = new HttpHeaders();
|
||||
expect(request.getHeaders()).andReturn(requestHeaders);
|
||||
expect(request.execute()).andReturn(response);
|
||||
expect(errorHandler.hasError(response)).andReturn(false);
|
||||
HttpHeaders responseHeaders = new HttpHeaders();
|
||||
responseHeaders.setContentType(textPlain);
|
||||
expect(response.getHeaders()).andReturn(responseHeaders);
|
||||
String expected = "Hello World";
|
||||
expect(converter.read(String.class, response)).andReturn(expected);
|
||||
response.close();
|
||||
|
||||
replayMocks();
|
||||
|
||||
String result = template.getForObject("http://example.com", String.class);
|
||||
assertEquals("Invalid GET result", expected, result);
|
||||
|
||||
verifyMocks();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getForObjectUnsupportedClass() throws Exception {
|
||||
expect(converter.supports(String.class)).andReturn(false);
|
||||
|
||||
replayMocks();
|
||||
|
||||
try {
|
||||
template.getForObject("http://example.com/{p}", String.class, "resource");
|
||||
fail("IllegalArgumentException expected");
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
// expected
|
||||
}
|
||||
|
||||
verifyMocks();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getUnsupportedMediaType() throws Exception {
|
||||
expect(converter.supports(String.class)).andReturn(true).times(3);
|
||||
MediaType supportedMediaType = new MediaType("foo", "bar");
|
||||
expect(converter.getSupportedMediaTypes()).andReturn(Collections.singletonList(supportedMediaType)).times(2);
|
||||
expect(requestFactory.createRequest(new URI("http://example.com/resource"), HttpMethod.GET)).andReturn(request);
|
||||
HttpHeaders requestHeaders = new HttpHeaders();
|
||||
expect(request.getHeaders()).andReturn(requestHeaders);
|
||||
expect(request.execute()).andReturn(response);
|
||||
expect(errorHandler.hasError(response)).andReturn(false);
|
||||
HttpHeaders responseHeaders = new HttpHeaders();
|
||||
MediaType contentType = new MediaType("bar", "baz");
|
||||
responseHeaders.setContentType(contentType);
|
||||
expect(response.getHeaders()).andReturn(responseHeaders);
|
||||
response.close();
|
||||
|
||||
replayMocks();
|
||||
|
||||
try {
|
||||
template.getForObject("http://example.com/{p}", String.class, "resource");
|
||||
fail("UnsupportedMediaTypeException expected");
|
||||
}
|
||||
catch (HttpClientException ex) {
|
||||
// expected
|
||||
}
|
||||
verifyMocks();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headForHeaders() throws Exception {
|
||||
expect(requestFactory.createRequest(new URI("http://example.com"), HttpMethod.HEAD)).andReturn(request);
|
||||
expect(request.execute()).andReturn(response);
|
||||
expect(errorHandler.hasError(response)).andReturn(false);
|
||||
HttpHeaders responseHeaders = new HttpHeaders();
|
||||
expect(response.getHeaders()).andReturn(responseHeaders);
|
||||
response.close();
|
||||
|
||||
replayMocks();
|
||||
HttpHeaders result = template.headForHeaders("http://example.com");
|
||||
|
||||
assertSame("Invalid headers returned", responseHeaders, result);
|
||||
|
||||
verifyMocks();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postForLocation() throws Exception {
|
||||
expect(converter.supports(String.class)).andReturn(true).times(2);
|
||||
expect(requestFactory.createRequest(new URI("http://example.com"), HttpMethod.POST)).andReturn(request);
|
||||
String helloWorld = "Hello World";
|
||||
converter.write(helloWorld, request);
|
||||
expect(request.execute()).andReturn(response);
|
||||
expect(errorHandler.hasError(response)).andReturn(false);
|
||||
HttpHeaders responseHeaders = new HttpHeaders();
|
||||
URI expected = new URI("http://example.com/hotels");
|
||||
responseHeaders.setLocation(expected);
|
||||
expect(response.getHeaders()).andReturn(responseHeaders);
|
||||
response.close();
|
||||
|
||||
replayMocks();
|
||||
|
||||
URI result = template.postForLocation("http://example.com", helloWorld);
|
||||
assertEquals("Invalid POST result", expected, result);
|
||||
|
||||
verifyMocks();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postForLocationNoLocation() throws Exception {
|
||||
expect(converter.supports(String.class)).andReturn(true).times(2);
|
||||
expect(requestFactory.createRequest(new URI("http://example.com"), HttpMethod.POST)).andReturn(request);
|
||||
String helloWorld = "Hello World";
|
||||
converter.write(helloWorld, request);
|
||||
expect(request.execute()).andReturn(response);
|
||||
expect(errorHandler.hasError(response)).andReturn(false);
|
||||
HttpHeaders responseHeaders = new HttpHeaders();
|
||||
expect(response.getHeaders()).andReturn(responseHeaders);
|
||||
response.close();
|
||||
|
||||
replayMocks();
|
||||
|
||||
URI result = template.postForLocation("http://example.com", helloWorld);
|
||||
assertNull("Invalid POST result", result);
|
||||
|
||||
verifyMocks();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void put() throws Exception {
|
||||
expect(converter.supports(String.class)).andReturn(true).times(2);
|
||||
expect(requestFactory.createRequest(new URI("http://example.com"), HttpMethod.PUT)).andReturn(request);
|
||||
String helloWorld = "Hello World";
|
||||
converter.write(helloWorld, request);
|
||||
expect(request.execute()).andReturn(response);
|
||||
expect(errorHandler.hasError(response)).andReturn(false);
|
||||
response.close();
|
||||
|
||||
replayMocks();
|
||||
|
||||
template.put("http://example.com", helloWorld);
|
||||
|
||||
verifyMocks();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void delete() throws Exception {
|
||||
expect(requestFactory.createRequest(new URI("http://example.com"), HttpMethod.DELETE)).andReturn(request);
|
||||
expect(request.execute()).andReturn(response);
|
||||
expect(errorHandler.hasError(response)).andReturn(false);
|
||||
response.close();
|
||||
|
||||
replayMocks();
|
||||
|
||||
template.delete("http://example.com");
|
||||
|
||||
verifyMocks();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void optionsForAllow() throws Exception {
|
||||
expect(requestFactory.createRequest(new URI("http://example.com"), HttpMethod.OPTIONS)).andReturn(request);
|
||||
expect(request.execute()).andReturn(response);
|
||||
expect(errorHandler.hasError(response)).andReturn(false);
|
||||
HttpHeaders responseHeaders = new HttpHeaders();
|
||||
EnumSet<HttpMethod> expected = EnumSet.of(HttpMethod.GET, HttpMethod.POST);
|
||||
responseHeaders.setAllow(expected);
|
||||
expect(response.getHeaders()).andReturn(responseHeaders);
|
||||
response.close();
|
||||
|
||||
replayMocks();
|
||||
|
||||
EnumSet<HttpMethod> result = template.optionsForAllow("http://example.com");
|
||||
assertEquals("Invalid OPTIONS result", expected, result);
|
||||
|
||||
verifyMocks();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ioException() throws Exception {
|
||||
expect(converter.supports(String.class)).andReturn(true).times(2);
|
||||
MediaType mediaType = new MediaType("foo", "bar");
|
||||
expect(converter.getSupportedMediaTypes()).andReturn(Collections.singletonList(mediaType));
|
||||
expect(requestFactory.createRequest(new URI("http://example.com/resource"), HttpMethod.GET)).andReturn(request);
|
||||
expect(request.getHeaders()).andReturn(new HttpHeaders());
|
||||
expect(request.execute()).andThrow(new IOException());
|
||||
|
||||
replayMocks();
|
||||
|
||||
try {
|
||||
template.getForObject("http://example.com/resource", String.class);
|
||||
fail("RestClientException expected");
|
||||
}
|
||||
catch (HttpIOException ex) {
|
||||
// expected
|
||||
}
|
||||
|
||||
verifyMocks();
|
||||
}
|
||||
|
||||
private void replayMocks() {
|
||||
replay(requestFactory, request, response, errorHandler, converter);
|
||||
}
|
||||
|
||||
private void verifyMocks() {
|
||||
verify(requestFactory, request, response, errorHandler, converter);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user