Re-use get, post, put etc. in overloaded methods
This commit is contained in:
@@ -77,8 +77,8 @@ import org.springframework.web.util.AbstractUriTemplateHandler;
|
|||||||
* <pre>
|
* <pre>
|
||||||
* @GetMapping("/proxy/{id}")
|
* @GetMapping("/proxy/{id}")
|
||||||
* public ResponseEntity<?> proxy(@PathVariable Integer id, ProxyExchange<?> proxy)
|
* public ResponseEntity<?> proxy(@PathVariable Integer id, ProxyExchange<?> proxy)
|
||||||
* throws Exception {
|
* throws Exception {
|
||||||
* return proxy.uri("http://localhost:9000/foos/" + id).get();
|
* return proxy.uri("http://localhost:9000/foos/" + id).get();
|
||||||
* }
|
* }
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
@@ -100,19 +100,16 @@ import org.springframework.web.util.AbstractUriTemplateHandler;
|
|||||||
* to the type you declare.
|
* to the type you declare.
|
||||||
* </p>
|
* </p>
|
||||||
* <p>
|
* <p>
|
||||||
* To manipulate the response use the overloaded HTTP methods
|
* To manipulate the response use the overloaded HTTP methods with a <code>Function</code>
|
||||||
* with a <code>Function</code> argument and pass in code to transform the response. E.g.
|
* argument and pass in code to transform the response. E.g.
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* @PostMapping("/proxy")
|
* @PostMapping("/proxy")
|
||||||
* public ResponseEntity<Foo> proxy(ProxyExchange<Foo> proxy)
|
* public ResponseEntity<Foo> proxy(ProxyExchange<Foo> proxy) throws Exception {
|
||||||
* throws Exception {
|
* return proxy.uri("http://localhost:9000/foos/")
|
||||||
* return proxy.uri("http://localhost:9000/foos/").post(response ->
|
* .post(response -> ResponseEntity.status(response.getStatusCode())
|
||||||
* ResponseEntity.status(response.getStatusCode())
|
* .headers(response.getHeaders())
|
||||||
* .headers(response.getHeaders())
|
* .header("X-Custom", "MyCustomHeader").body(response.getBody()));
|
||||||
* .header("X-Custom", "MyCustomHeader")
|
|
||||||
* .body(response.getBody())
|
|
||||||
* );
|
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* </pre>
|
* </pre>
|
||||||
@@ -136,410 +133,396 @@ import org.springframework.web.util.AbstractUriTemplateHandler;
|
|||||||
*/
|
*/
|
||||||
public class ProxyExchange<T> {
|
public class ProxyExchange<T> {
|
||||||
|
|
||||||
public static Set<String> DEFAULT_SENSITIVE = new HashSet<>(
|
public static Set<String> DEFAULT_SENSITIVE = new HashSet<>(
|
||||||
Arrays.asList("cookie", "authorization"));
|
Arrays.asList("cookie", "authorization"));
|
||||||
|
|
||||||
private URI uri;
|
private URI uri;
|
||||||
|
|
||||||
private NestedTemplate rest;
|
private NestedTemplate rest;
|
||||||
|
|
||||||
private Object body;
|
private Object body;
|
||||||
|
|
||||||
private RequestResponseBodyMethodProcessor delegate;
|
private RequestResponseBodyMethodProcessor delegate;
|
||||||
|
|
||||||
private NativeWebRequest webRequest;
|
private NativeWebRequest webRequest;
|
||||||
|
|
||||||
private ModelAndViewContainer mavContainer;
|
private ModelAndViewContainer mavContainer;
|
||||||
|
|
||||||
private WebDataBinderFactory binderFactory;
|
private WebDataBinderFactory binderFactory;
|
||||||
|
|
||||||
private Set<String> sensitive;
|
private Set<String> sensitive;
|
||||||
|
|
||||||
private HttpHeaders headers = new HttpHeaders();
|
private HttpHeaders headers = new HttpHeaders();
|
||||||
|
|
||||||
private Type responseType;
|
private Type responseType;
|
||||||
|
|
||||||
public ProxyExchange(RestTemplate rest, NativeWebRequest webRequest,
|
public ProxyExchange(RestTemplate rest, NativeWebRequest webRequest,
|
||||||
ModelAndViewContainer mavContainer, WebDataBinderFactory binderFactory,
|
ModelAndViewContainer mavContainer, WebDataBinderFactory binderFactory,
|
||||||
Type type) {
|
Type type) {
|
||||||
this.responseType = type;
|
this.responseType = type;
|
||||||
this.rest = createTemplate(rest);
|
this.rest = createTemplate(rest);
|
||||||
this.webRequest = webRequest;
|
this.webRequest = webRequest;
|
||||||
this.mavContainer = mavContainer;
|
this.mavContainer = mavContainer;
|
||||||
this.binderFactory = binderFactory;
|
this.binderFactory = binderFactory;
|
||||||
this.delegate = new RequestResponseBodyMethodProcessor(
|
this.delegate = new RequestResponseBodyMethodProcessor(
|
||||||
rest.getMessageConverters());
|
rest.getMessageConverters());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the body for the downstream request (if using {@link #post()}, {@link #put()}
|
* Sets the body for the downstream request (if using {@link #post()}, {@link #put()}
|
||||||
* or {@link #patch()}). The body can be omitted if you just want to pass the incoming
|
* or {@link #patch()}). The body can be omitted if you just want to pass the incoming
|
||||||
* request downstream without changing it. If you want to transform the incoming
|
* request downstream without changing it. If you want to transform the incoming
|
||||||
* request you can declare it as a <code>@RequestBody</code> in your
|
* request you can declare it as a <code>@RequestBody</code> in your
|
||||||
* <code>@RequestMapping</code> in the usual Spring MVC way.
|
* <code>@RequestMapping</code> in the usual Spring MVC way.
|
||||||
*
|
*
|
||||||
* @param body the request body to send downstream
|
* @param body the request body to send downstream
|
||||||
* @return this for convenience
|
* @return this for convenience
|
||||||
*/
|
*/
|
||||||
public ProxyExchange<T> body(Object body) {
|
public ProxyExchange<T> body(Object body) {
|
||||||
this.body = body;
|
this.body = body;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a header for the downstream call.
|
* Sets a header for the downstream call.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name
|
||||||
* @param value
|
* @param value
|
||||||
* @return this for convenience
|
* @return this for convenience
|
||||||
*/
|
*/
|
||||||
public ProxyExchange<T> header(String name, String... value) {
|
public ProxyExchange<T> header(String name, String... value) {
|
||||||
this.headers.put(name, Arrays.asList(value));
|
this.headers.put(name, Arrays.asList(value));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Additional headers, or overrides of the incoming ones, to be used in the downstream
|
* Additional headers, or overrides of the incoming ones, to be used in the downstream
|
||||||
* call.
|
* call.
|
||||||
*
|
*
|
||||||
* @param headers the http headers to use in the downstream call
|
* @param headers the http headers to use in the downstream call
|
||||||
* @return this for convenience
|
* @return this for convenience
|
||||||
*/
|
*/
|
||||||
public ProxyExchange<T> headers(HttpHeaders headers) {
|
public ProxyExchange<T> headers(HttpHeaders headers) {
|
||||||
this.headers.putAll(headers);
|
this.headers.putAll(headers);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the names of sensitive headers that are not passed downstream to the backend
|
* Sets the names of sensitive headers that are not passed downstream to the backend
|
||||||
* service.
|
* service.
|
||||||
*
|
*
|
||||||
* @param names the names of sensitive headers
|
* @param names the names of sensitive headers
|
||||||
* @return this for convenience
|
* @return this for convenience
|
||||||
*/
|
*/
|
||||||
public ProxyExchange<T> sensitive(String... names) {
|
public ProxyExchange<T> sensitive(String... names) {
|
||||||
if (this.sensitive == null) {
|
if (this.sensitive == null) {
|
||||||
this.sensitive = new HashSet<>();
|
this.sensitive = new HashSet<>();
|
||||||
}
|
}
|
||||||
for (String name : names) {
|
for (String name : names) {
|
||||||
this.sensitive.add(name.toLowerCase());
|
this.sensitive.add(name.toLowerCase());
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the uri for the backend call when triggered by the HTTP methods.
|
* Sets the uri for the backend call when triggered by the HTTP methods.
|
||||||
*
|
*
|
||||||
* @param uri the backend uri to send the request to
|
* @param uri the backend uri to send the request to
|
||||||
* @return this for convenience
|
* @return this for convenience
|
||||||
*/
|
*/
|
||||||
public ProxyExchange<T> uri(String uri) {
|
public ProxyExchange<T> uri(String uri) {
|
||||||
try {
|
try {
|
||||||
this.uri = new URI(uri);
|
this.uri = new URI(uri);
|
||||||
}
|
}
|
||||||
catch (URISyntaxException e) {
|
catch (URISyntaxException e) {
|
||||||
throw new IllegalStateException("Cannot create URI", e);
|
throw new IllegalStateException("Cannot create URI", e);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String path() {
|
public String path() {
|
||||||
return (String) this.webRequest.getAttribute(
|
return (String) this.webRequest.getAttribute(
|
||||||
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE,
|
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE,
|
||||||
WebRequest.SCOPE_REQUEST);
|
WebRequest.SCOPE_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String path(String prefix) {
|
public String path(String prefix) {
|
||||||
String path = path();
|
String path = path();
|
||||||
if (!path.startsWith(prefix)) {
|
if (!path.startsWith(prefix)) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Path does not start with prefix (" + prefix + "): " + path);
|
"Path does not start with prefix (" + prefix + "): " + path);
|
||||||
}
|
}
|
||||||
return path.substring(prefix.length());
|
return path.substring(prefix.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void forward(String path) {
|
public void forward(String path) {
|
||||||
HttpServletRequest request = this.webRequest
|
HttpServletRequest request = this.webRequest
|
||||||
.getNativeRequest(HttpServletRequest.class);
|
.getNativeRequest(HttpServletRequest.class);
|
||||||
HttpServletResponse response = this.webRequest
|
HttpServletResponse response = this.webRequest
|
||||||
.getNativeResponse(HttpServletResponse.class);
|
.getNativeResponse(HttpServletResponse.class);
|
||||||
try {
|
try {
|
||||||
request.getRequestDispatcher(path).forward(
|
request.getRequestDispatcher(path).forward(
|
||||||
new BodyForwardingHttpServletRequest(request, response), response);
|
new BodyForwardingHttpServletRequest(request, response), response);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
throw new IllegalStateException("Cannot forward request", e);
|
throw new IllegalStateException("Cannot forward request", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResponseEntity<T> get() {
|
public ResponseEntity<T> get() {
|
||||||
RequestEntity<?> requestEntity = headers((BodyBuilder) RequestEntity.get(uri))
|
RequestEntity<?> requestEntity = headers((BodyBuilder) RequestEntity.get(uri))
|
||||||
.build();
|
.build();
|
||||||
return exchange(requestEntity);
|
return exchange(requestEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <S> ResponseEntity<S> get(
|
public <S> ResponseEntity<S> get(
|
||||||
Function<ResponseEntity<T>, ResponseEntity<S>> converter) {
|
Function<ResponseEntity<T>, ResponseEntity<S>> converter) {
|
||||||
RequestEntity<?> requestEntity = headers((BodyBuilder) RequestEntity.get(uri))
|
return converter.apply(get());
|
||||||
.build();
|
}
|
||||||
return converter.apply(exchange(requestEntity));
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResponseEntity<T> head() {
|
public ResponseEntity<T> head() {
|
||||||
RequestEntity<?> requestEntity = headers((BodyBuilder) RequestEntity.head(uri))
|
RequestEntity<?> requestEntity = headers((BodyBuilder) RequestEntity.head(uri))
|
||||||
.build();
|
.build();
|
||||||
return exchange(requestEntity);
|
return exchange(requestEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <S> ResponseEntity<S> head(
|
public <S> ResponseEntity<S> head(
|
||||||
Function<ResponseEntity<T>, ResponseEntity<S>> converter) {
|
Function<ResponseEntity<T>, ResponseEntity<S>> converter) {
|
||||||
RequestEntity<?> requestEntity = headers((BodyBuilder) RequestEntity.head(uri))
|
return converter.apply(head());
|
||||||
.build();
|
}
|
||||||
return converter.apply(exchange(requestEntity));
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResponseEntity<T> options() {
|
public ResponseEntity<T> options() {
|
||||||
RequestEntity<?> requestEntity = headers((BodyBuilder) RequestEntity.options(uri))
|
RequestEntity<?> requestEntity = headers((BodyBuilder) RequestEntity.options(uri))
|
||||||
.build();
|
.build();
|
||||||
return exchange(requestEntity);
|
return exchange(requestEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <S> ResponseEntity<S> options(
|
public <S> ResponseEntity<S> options(
|
||||||
Function<ResponseEntity<T>, ResponseEntity<S>> converter) {
|
Function<ResponseEntity<T>, ResponseEntity<S>> converter) {
|
||||||
RequestEntity<?> requestEntity = headers((BodyBuilder) RequestEntity.options(uri))
|
return converter.apply(options());
|
||||||
.build();
|
}
|
||||||
return converter.apply(exchange(requestEntity));
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResponseEntity<T> post() {
|
public ResponseEntity<T> post() {
|
||||||
RequestEntity<Object> requestEntity = headers(RequestEntity.post(uri))
|
RequestEntity<Object> requestEntity = headers(RequestEntity.post(uri))
|
||||||
.body(body());
|
.body(body());
|
||||||
return exchange(requestEntity);
|
return exchange(requestEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <S> ResponseEntity<S> post(
|
public <S> ResponseEntity<S> post(
|
||||||
Function<ResponseEntity<T>, ResponseEntity<S>> converter) {
|
Function<ResponseEntity<T>, ResponseEntity<S>> converter) {
|
||||||
RequestEntity<Object> requestEntity = headers(RequestEntity.post(uri))
|
return converter.apply(post());
|
||||||
.body(body());
|
}
|
||||||
return converter.apply(exchange(requestEntity));
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResponseEntity<T> delete() {
|
public ResponseEntity<T> delete() {
|
||||||
RequestEntity<Void> requestEntity = headers(
|
RequestEntity<Void> requestEntity = headers(
|
||||||
(BodyBuilder) RequestEntity.delete(uri)).build();
|
(BodyBuilder) RequestEntity.delete(uri)).build();
|
||||||
return exchange(requestEntity);
|
return exchange(requestEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <S> ResponseEntity<S> delete(
|
public <S> ResponseEntity<S> delete(
|
||||||
Function<ResponseEntity<T>, ResponseEntity<S>> converter) {
|
Function<ResponseEntity<T>, ResponseEntity<S>> converter) {
|
||||||
RequestEntity<Void> requestEntity = headers(
|
return converter.apply(delete());
|
||||||
(BodyBuilder) RequestEntity.delete(uri)).build();
|
}
|
||||||
return converter.apply(exchange(requestEntity));
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResponseEntity<T> put() {
|
public ResponseEntity<T> put() {
|
||||||
RequestEntity<Object> requestEntity = headers(RequestEntity.put(uri))
|
RequestEntity<Object> requestEntity = headers(RequestEntity.put(uri))
|
||||||
.body(body());
|
.body(body());
|
||||||
return exchange(requestEntity);
|
return exchange(requestEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <S> ResponseEntity<S> put(
|
public <S> ResponseEntity<S> put(
|
||||||
Function<ResponseEntity<T>, ResponseEntity<S>> converter) {
|
Function<ResponseEntity<T>, ResponseEntity<S>> converter) {
|
||||||
RequestEntity<Object> requestEntity = headers(RequestEntity.put(uri))
|
return converter.apply(put());
|
||||||
.body(body());
|
}
|
||||||
return converter.apply(exchange(requestEntity));
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResponseEntity<T> patch() {
|
public ResponseEntity<T> patch() {
|
||||||
RequestEntity<Object> requestEntity = headers(RequestEntity.patch(uri))
|
RequestEntity<Object> requestEntity = headers(RequestEntity.patch(uri))
|
||||||
.body(body());
|
.body(body());
|
||||||
return exchange(requestEntity);
|
return exchange(requestEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <S> ResponseEntity<S> patch(
|
public <S> ResponseEntity<S> patch(
|
||||||
Function<ResponseEntity<T>, ResponseEntity<S>> converter) {
|
Function<ResponseEntity<T>, ResponseEntity<S>> converter) {
|
||||||
RequestEntity<Object> requestEntity = headers(RequestEntity.patch(uri))
|
return converter.apply(patch());
|
||||||
.body(body());
|
}
|
||||||
return converter.apply(exchange(requestEntity));
|
|
||||||
}
|
|
||||||
|
|
||||||
private ResponseEntity<T> exchange(RequestEntity<?> requestEntity) {
|
private ResponseEntity<T> exchange(RequestEntity<?> requestEntity) {
|
||||||
Type type = this.responseType;
|
Type type = this.responseType;
|
||||||
if (type instanceof TypeVariable || type instanceof WildcardType) {
|
if (type instanceof TypeVariable || type instanceof WildcardType) {
|
||||||
type = Object.class;
|
type = Object.class;
|
||||||
}
|
}
|
||||||
RequestCallback requestCallback = rest.httpEntityCallback((Object) requestEntity,
|
RequestCallback requestCallback = rest.httpEntityCallback((Object) requestEntity,
|
||||||
type);
|
type);
|
||||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = rest
|
ResponseExtractor<ResponseEntity<T>> responseExtractor = rest
|
||||||
.responseEntityExtractor(type);
|
.responseEntityExtractor(type);
|
||||||
return rest.execute(requestEntity.getUrl(), requestEntity.getMethod(),
|
return rest.execute(requestEntity.getUrl(), requestEntity.getMethod(),
|
||||||
requestCallback, responseExtractor);
|
requestCallback, responseExtractor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BodyBuilder headers(BodyBuilder builder) {
|
private BodyBuilder headers(BodyBuilder builder) {
|
||||||
Set<String> sensitive = this.sensitive;
|
Set<String> sensitive = this.sensitive;
|
||||||
if (sensitive == null) {
|
if (sensitive == null) {
|
||||||
sensitive = DEFAULT_SENSITIVE;
|
sensitive = DEFAULT_SENSITIVE;
|
||||||
}
|
}
|
||||||
for (String name : headers.keySet()) {
|
for (String name : headers.keySet()) {
|
||||||
if (sensitive.contains(name.toLowerCase())) {
|
if (sensitive.contains(name.toLowerCase())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
builder.header(name, headers.get(name).toArray(new String[0]));
|
builder.header(name, headers.get(name).toArray(new String[0]));
|
||||||
}
|
}
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object body() {
|
private Object body() {
|
||||||
if (body != null) {
|
if (body != null) {
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
body = getRequestBody();
|
body = getRequestBody();
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search for the request body if it was already deserialized using
|
* Search for the request body if it was already deserialized using
|
||||||
* <code>@RequestBody</code>. If it is not found then deserialize it in the same way
|
* <code>@RequestBody</code>. If it is not found then deserialize it in the same way
|
||||||
* that it would have been for a <code>@RequestBody</code>.
|
* that it would have been for a <code>@RequestBody</code>.
|
||||||
*
|
*
|
||||||
* @return the request body
|
* @return the request body
|
||||||
*/
|
*/
|
||||||
private Object getRequestBody() {
|
private Object getRequestBody() {
|
||||||
for (String key : mavContainer.getModel().keySet()) {
|
for (String key : mavContainer.getModel().keySet()) {
|
||||||
if (key.startsWith(BindingResult.MODEL_KEY_PREFIX)) {
|
if (key.startsWith(BindingResult.MODEL_KEY_PREFIX)) {
|
||||||
BindingResult result = (BindingResult) mavContainer.getModel().get(key);
|
BindingResult result = (BindingResult) mavContainer.getModel().get(key);
|
||||||
return result.getTarget();
|
return result.getTarget();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MethodParameter input = new MethodParameter(
|
MethodParameter input = new MethodParameter(
|
||||||
ClassUtils.getMethod(BodyGrabber.class, "body", Object.class), 0);
|
ClassUtils.getMethod(BodyGrabber.class, "body", Object.class), 0);
|
||||||
try {
|
try {
|
||||||
delegate.resolveArgument(input, mavContainer, webRequest, binderFactory);
|
delegate.resolveArgument(input, mavContainer, webRequest, binderFactory);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
throw new IllegalStateException("Cannot resolve body", e);
|
throw new IllegalStateException("Cannot resolve body", e);
|
||||||
}
|
}
|
||||||
String name = Conventions.getVariableNameForParameter(input);
|
String name = Conventions.getVariableNameForParameter(input);
|
||||||
BindingResult result = (BindingResult) mavContainer.getModel()
|
BindingResult result = (BindingResult) mavContainer.getModel()
|
||||||
.get(BindingResult.MODEL_KEY_PREFIX + name);
|
.get(BindingResult.MODEL_KEY_PREFIX + name);
|
||||||
return result.getTarget();
|
return result.getTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
private NestedTemplate createTemplate(RestTemplate input) {
|
private NestedTemplate createTemplate(RestTemplate input) {
|
||||||
NestedTemplate rest = new NestedTemplate();
|
NestedTemplate rest = new NestedTemplate();
|
||||||
rest.setMessageConverters(input.getMessageConverters());
|
rest.setMessageConverters(input.getMessageConverters());
|
||||||
rest.setErrorHandler(input.getErrorHandler());
|
rest.setErrorHandler(input.getErrorHandler());
|
||||||
rest.setDefaultUriVariables(
|
rest.setDefaultUriVariables(
|
||||||
((AbstractUriTemplateHandler) input.getUriTemplateHandler())
|
((AbstractUriTemplateHandler) input.getUriTemplateHandler())
|
||||||
.getDefaultUriVariables());
|
.getDefaultUriVariables());
|
||||||
rest.setRequestFactory(input.getRequestFactory());
|
rest.setRequestFactory(input.getRequestFactory());
|
||||||
rest.setInterceptors(input.getInterceptors());
|
rest.setInterceptors(input.getInterceptors());
|
||||||
return rest;
|
return rest;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A special {@link RestTemplate} that knows about the {@link Type} of its response
|
* A special {@link RestTemplate} that knows about the {@link Type} of its response
|
||||||
* body explicitly (rather than through a {@link ParameterizedTypeReference}, which is
|
* body explicitly (rather than through a {@link ParameterizedTypeReference}, which is
|
||||||
* the only way to access this feature in a regular template).
|
* the only way to access this feature in a regular template).
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class NestedTemplate extends RestTemplate {
|
class NestedTemplate extends RestTemplate {
|
||||||
@Override
|
@Override
|
||||||
protected <S> RequestCallback httpEntityCallback(Object requestBody,
|
protected <S> RequestCallback httpEntityCallback(Object requestBody,
|
||||||
Type responseType) {
|
Type responseType) {
|
||||||
return super.httpEntityCallback(requestBody, responseType);
|
return super.httpEntityCallback(requestBody, responseType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected <S> ResponseExtractor<ResponseEntity<S>> responseEntityExtractor(
|
protected <S> ResponseExtractor<ResponseEntity<S>> responseEntityExtractor(
|
||||||
Type responseType) {
|
Type responseType) {
|
||||||
return super.responseEntityExtractor(responseType);
|
return super.responseEntityExtractor(responseType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A servlet request wrapper that can be safely passed downstream to an internal
|
* A servlet request wrapper that can be safely passed downstream to an internal
|
||||||
* forward dispatch, caching its body, and making it available in converted form using
|
* forward dispatch, caching its body, and making it available in converted form using
|
||||||
* Spring message converters.
|
* Spring message converters.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class BodyForwardingHttpServletRequest extends HttpServletRequestWrapper {
|
class BodyForwardingHttpServletRequest extends HttpServletRequestWrapper {
|
||||||
private HttpServletRequest request;
|
private HttpServletRequest request;
|
||||||
private HttpServletResponse response;
|
private HttpServletResponse response;
|
||||||
|
|
||||||
BodyForwardingHttpServletRequest(HttpServletRequest request,
|
BodyForwardingHttpServletRequest(HttpServletRequest request,
|
||||||
HttpServletResponse response) {
|
HttpServletResponse response) {
|
||||||
super(request);
|
super(request);
|
||||||
this.request = request;
|
this.request = request;
|
||||||
this.response = response;
|
this.response = response;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> header(String name) {
|
private List<String> header(String name) {
|
||||||
List<String> list = headers.get(name);
|
List<String> list = headers.get(name);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ServletInputStream getInputStream() throws IOException {
|
public ServletInputStream getInputStream() throws IOException {
|
||||||
Object body = body();
|
Object body = body();
|
||||||
MethodParameter output = new MethodParameter(
|
MethodParameter output = new MethodParameter(
|
||||||
ClassUtils.getMethod(BodySender.class, "body"), -1);
|
ClassUtils.getMethod(BodySender.class, "body"), -1);
|
||||||
ServletOutputToInputConverter response = new ServletOutputToInputConverter(
|
ServletOutputToInputConverter response = new ServletOutputToInputConverter(
|
||||||
this.response);
|
this.response);
|
||||||
ServletWebRequest webRequest = new ServletWebRequest(this.request, response);
|
ServletWebRequest webRequest = new ServletWebRequest(this.request, response);
|
||||||
try {
|
try {
|
||||||
delegate.handleReturnValue(body, output, mavContainer, webRequest);
|
delegate.handleReturnValue(body, output, mavContainer, webRequest);
|
||||||
}
|
}
|
||||||
catch (HttpMessageNotWritableException
|
catch (HttpMessageNotWritableException
|
||||||
| HttpMediaTypeNotAcceptableException e) {
|
| HttpMediaTypeNotAcceptableException e) {
|
||||||
throw new IllegalStateException("Cannot convert body");
|
throw new IllegalStateException("Cannot convert body");
|
||||||
}
|
}
|
||||||
return response.getInputStream();
|
return response.getInputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Enumeration<String> getHeaderNames() {
|
public Enumeration<String> getHeaderNames() {
|
||||||
Set<String> names = headers.keySet();
|
Set<String> names = headers.keySet();
|
||||||
if (names.isEmpty()) {
|
if (names.isEmpty()) {
|
||||||
return super.getHeaderNames();
|
return super.getHeaderNames();
|
||||||
}
|
}
|
||||||
Set<String> result = new LinkedHashSet<>(names);
|
Set<String> result = new LinkedHashSet<>(names);
|
||||||
result.addAll(Collections.list(super.getHeaderNames()));
|
result.addAll(Collections.list(super.getHeaderNames()));
|
||||||
return new Vector<String>(result).elements();
|
return new Vector<String>(result).elements();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Enumeration<String> getHeaders(String name) {
|
public Enumeration<String> getHeaders(String name) {
|
||||||
List<String> list = header(name);
|
List<String> list = header(name);
|
||||||
if (list != null) {
|
if (list != null) {
|
||||||
return new Vector<String>(list).elements();
|
return new Vector<String>(list).elements();
|
||||||
}
|
}
|
||||||
return super.getHeaders(name);
|
return super.getHeaders(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getHeader(String name) {
|
public String getHeader(String name) {
|
||||||
List<String> list = header(name);
|
List<String> list = header(name);
|
||||||
if (list != null && !list.isEmpty()) {
|
if (list != null && !list.isEmpty()) {
|
||||||
return list.iterator().next();
|
return list.iterator().next();
|
||||||
}
|
}
|
||||||
return super.getHeader(name);
|
return super.getHeader(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class BodyGrabber {
|
protected static class BodyGrabber {
|
||||||
public Object body(@RequestBody Object body) {
|
public Object body(@RequestBody Object body) {
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class BodySender {
|
protected static class BodySender {
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public Object body() {
|
public Object body() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -556,56 +539,56 @@ public class ProxyExchange<T> {
|
|||||||
*/
|
*/
|
||||||
class ServletOutputToInputConverter extends HttpServletResponseWrapper {
|
class ServletOutputToInputConverter extends HttpServletResponseWrapper {
|
||||||
|
|
||||||
private StringBuilder builder = new StringBuilder();
|
private StringBuilder builder = new StringBuilder();
|
||||||
|
|
||||||
public ServletOutputToInputConverter(HttpServletResponse response) {
|
public ServletOutputToInputConverter(HttpServletResponse response) {
|
||||||
super(response);
|
super(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ServletOutputStream getOutputStream() throws IOException {
|
public ServletOutputStream getOutputStream() throws IOException {
|
||||||
return new ServletOutputStream() {
|
return new ServletOutputStream() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(int b) throws IOException {
|
public void write(int b) throws IOException {
|
||||||
builder.append(new Character((char) b));
|
builder.append(new Character((char) b));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setWriteListener(WriteListener listener) {
|
public void setWriteListener(WriteListener listener) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isReady() {
|
public boolean isReady() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServletInputStream getInputStream() {
|
public ServletInputStream getInputStream() {
|
||||||
ByteArrayInputStream body = new ByteArrayInputStream(
|
ByteArrayInputStream body = new ByteArrayInputStream(
|
||||||
builder.toString().getBytes());
|
builder.toString().getBytes());
|
||||||
return new ServletInputStream() {
|
return new ServletInputStream() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read() throws IOException {
|
public int read() throws IOException {
|
||||||
return body.read();
|
return body.read();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setReadListener(ReadListener listener) {
|
public void setReadListener(ReadListener listener) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isReady() {
|
public boolean isReady() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFinished() {
|
public boolean isFinished() {
|
||||||
return body.available() <= 0;
|
return body.available() <= 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user