You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2020/08/04 06:21:39 UTC

[servicecomb-java-chassis] branch master updated: [SCB-1754]accessor problem fix: CseHttpMessageConverter response access

This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git


The following commit(s) were added to refs/heads/master by this push:
     new ad9516d  [SCB-1754]accessor problem fix: CseHttpMessageConverter response access
ad9516d is described below

commit ad9516dfad410a4162a7180336306200f410c0c1
Author: liubao <bi...@qq.com>
AuthorDate: Mon Aug 3 14:55:43 2020 +0800

    [SCB-1754]accessor problem fix: CseHttpMessageConverter response access
---
 .../springmvc/reference/CseClientHttpResponse.java |   1 -
 .../reference}/CseHttpMessageConverter.java        |  30 +----
 .../CseHttpMessageConverterExtractor.java          |  31 +++++
 .../CseResponseEntityResponseExtractor.java        |  49 ++++++++
 .../springmvc/reference/CseRestTemplate.java       | 126 ++++++++++++++++++++-
 .../reference/async/CseAsyncRestTemplate.java      |  23 +++-
 .../web/client/TestCseHttpMessageConverter.java    |  52 ---------
 7 files changed, 231 insertions(+), 81 deletions(-)

diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseClientHttpResponse.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseClientHttpResponse.java
index 52092c9..a06160a 100644
--- a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseClientHttpResponse.java
+++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseClientHttpResponse.java
@@ -90,7 +90,6 @@ public class CseClientHttpResponse implements ClientHttpResponse {
 
   @Override
   public HttpStatus getStatusCode() throws IOException {
-    // TODO:springmvc不允许自定义http错误码
     return HttpStatus.valueOf(response.getStatusCode());
   }
 
diff --git a/providers/provider-springmvc/src/main/java/org/springframework/web/client/CseHttpMessageConverter.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseHttpMessageConverter.java
similarity index 75%
rename from providers/provider-springmvc/src/main/java/org/springframework/web/client/CseHttpMessageConverter.java
rename to providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseHttpMessageConverter.java
index 5693f35..35c37b9 100644
--- a/providers/provider-springmvc/src/main/java/org/springframework/web/client/CseHttpMessageConverter.java
+++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseHttpMessageConverter.java
@@ -15,16 +15,13 @@
  * limitations under the License.
  */
 
-package org.springframework.web.client;
+package org.apache.servicecomb.provider.springmvc.reference;
 
 import java.io.IOException;
-import java.lang.reflect.Field;
 import java.lang.reflect.Type;
 import java.util.Arrays;
 import java.util.List;
 
-import org.apache.servicecomb.provider.springmvc.reference.CseClientHttpRequest;
-import org.apache.servicecomb.provider.springmvc.reference.CseClientHttpResponse;
 import org.springframework.http.HttpInputMessage;
 import org.springframework.http.HttpOutputMessage;
 import org.springframework.http.MediaType;
@@ -32,26 +29,14 @@ import org.springframework.http.converter.GenericHttpMessageConverter;
 import org.springframework.http.converter.HttpMessageNotReadableException;
 import org.springframework.http.converter.HttpMessageNotWritableException;
 import org.springframework.lang.Nullable;
-import org.springframework.util.ReflectionUtils;
 
-/**
- * 需要访问MessageBodyClientHttpResponseWrapper
- * 这是一个package级别的类,只好放在特殊的包内了
- */
 public class CseHttpMessageConverter implements GenericHttpMessageConverter<Object> {
 
   private static final List<MediaType> ALL_MEDIA_TYPE = Arrays.asList(MediaType.ALL);
 
-  private static final Field RESPONSE_FIELD =
-      ReflectionUtils.findField(MessageBodyClientHttpResponseWrapper.class, "response");
-
-  static {
-    RESPONSE_FIELD.setAccessible(true);
-  }
-
   @Override
   public boolean canRead(Class<?> clazz, MediaType mediaType) {
-    return true;
+    return false;
   }
 
   @Override
@@ -67,14 +52,11 @@ public class CseHttpMessageConverter implements GenericHttpMessageConverter<Obje
   @Override
   public Object read(Class<? extends Object> clazz,
       HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
-    return read(inputMessage);
+    throw new IllegalStateException("not supported");
   }
 
   private Object read(HttpInputMessage inputMessage) {
-    MessageBodyClientHttpResponseWrapper respWrapper = (MessageBodyClientHttpResponseWrapper) inputMessage;
-    CseClientHttpResponse resp =
-        (CseClientHttpResponse) ReflectionUtils.getField(RESPONSE_FIELD, respWrapper);
-    return resp.getResult();
+    throw new IllegalStateException("not supported");
   }
 
   @Override
@@ -90,13 +72,13 @@ public class CseHttpMessageConverter implements GenericHttpMessageConverter<Obje
 
   @Override
   public boolean canRead(Type type, @Nullable Class<?> contextClass, @Nullable MediaType mediaType) {
-    return true;
+    return false;
   }
 
   @Override
   public Object read(Type type, @Nullable Class<?> contextClass, HttpInputMessage inputMessage)
       throws IOException, HttpMessageNotReadableException {
-    return read(inputMessage);
+    throw new IllegalStateException("not supported");
   }
 
   @Override
diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseHttpMessageConverterExtractor.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseHttpMessageConverterExtractor.java
new file mode 100644
index 0000000..402c714
--- /dev/null
+++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseHttpMessageConverterExtractor.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.servicecomb.provider.springmvc.reference;
+
+import java.io.IOException;
+
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.web.client.ResponseExtractor;
+
+public class CseHttpMessageConverterExtractor<T> implements ResponseExtractor<T> {
+  @Override
+  @SuppressWarnings("unchecked")
+  public T extractData(ClientHttpResponse response) throws IOException {
+    return (T) ((CseClientHttpResponse) response).getResult();
+  }
+}
diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseResponseEntityResponseExtractor.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseResponseEntityResponseExtractor.java
new file mode 100644
index 0000000..7c8f4ad
--- /dev/null
+++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseResponseEntityResponseExtractor.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.servicecomb.provider.springmvc.reference;
+
+import java.io.IOException;
+import java.lang.reflect.Type;
+
+import org.springframework.http.ResponseEntity;
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.lang.Nullable;
+import org.springframework.web.client.ResponseExtractor;
+
+public class CseResponseEntityResponseExtractor<T> implements ResponseExtractor<ResponseEntity<T>> {
+  @Nullable
+  private final CseHttpMessageConverterExtractor<T> delegate;
+
+  public CseResponseEntityResponseExtractor(@Nullable Type responseType) {
+    if (responseType != null && Void.class != responseType) {
+      this.delegate = new CseHttpMessageConverterExtractor<>();
+    } else {
+      this.delegate = null;
+    }
+  }
+
+  @Override
+  public ResponseEntity<T> extractData(ClientHttpResponse response) throws IOException {
+    if (this.delegate != null) {
+      T body = this.delegate.extractData(response);
+      return ResponseEntity.status(response.getRawStatusCode()).headers(response.getHeaders()).body(body);
+    } else {
+      return ResponseEntity.status(response.getRawStatusCode()).headers(response.getHeaders()).build();
+    }
+  }
+}
diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseRestTemplate.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseRestTemplate.java
index 251182e..8f25d4e 100644
--- a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseRestTemplate.java
+++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseRestTemplate.java
@@ -20,10 +20,15 @@ package org.apache.servicecomb.provider.springmvc.reference;
 import java.lang.reflect.Type;
 import java.net.URI;
 import java.util.Arrays;
+import java.util.Map;
 
 import org.apache.servicecomb.common.rest.RestConst;
-import org.springframework.web.client.CseHttpMessageConverter;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
+import org.springframework.lang.Nullable;
 import org.springframework.web.client.RequestCallback;
+import org.springframework.web.client.ResponseExtractor;
+import org.springframework.web.client.RestClientException;
 
 public class CseRestTemplate extends AcceptableRestTemplate {
   public CseRestTemplate() {
@@ -32,6 +37,125 @@ public class CseRestTemplate extends AcceptableRestTemplate {
     setUriTemplateHandler(new CseUriTemplateHandler());
   }
 
+  // GET
+
+  @Override
+  @Nullable
+  public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException {
+    RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
+    CseHttpMessageConverterExtractor<T> responseExtractor =
+        new CseHttpMessageConverterExtractor<>();
+    return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
+  }
+
+  @Override
+  @Nullable
+  public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException {
+    RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
+    CseHttpMessageConverterExtractor<T> responseExtractor =
+        new CseHttpMessageConverterExtractor<>();
+    return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
+  }
+
+  @Override
+  @Nullable
+  public <T> T getForObject(URI url, Class<T> responseType) throws RestClientException {
+    RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
+    CseHttpMessageConverterExtractor<T> responseExtractor =
+        new CseHttpMessageConverterExtractor<>();
+    return execute(url, HttpMethod.GET, requestCallback, responseExtractor);
+  }
+
+  // HEAD
+  // no override
+
+  // POST
+
+  @Override
+  @Nullable
+  public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType,
+      Object... uriVariables) throws RestClientException {
+
+    RequestCallback requestCallback = httpEntityCallback(request, responseType);
+    CseHttpMessageConverterExtractor<T> responseExtractor =
+        new CseHttpMessageConverterExtractor<>();
+    return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
+  }
+
+  @Override
+  @Nullable
+  public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType,
+      Map<String, ?> uriVariables) throws RestClientException {
+
+    RequestCallback requestCallback = httpEntityCallback(request, responseType);
+    CseHttpMessageConverterExtractor<T> responseExtractor =
+        new CseHttpMessageConverterExtractor<>();
+    return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
+  }
+
+  @Override
+  @Nullable
+  public <T> T postForObject(URI url, @Nullable Object request, Class<T> responseType)
+      throws RestClientException {
+
+    RequestCallback requestCallback = httpEntityCallback(request, responseType);
+    CseHttpMessageConverterExtractor<T> responseExtractor =
+        new CseHttpMessageConverterExtractor<>();
+    return execute(url, HttpMethod.POST, requestCallback, responseExtractor);
+  }
+
+  // PUT
+  // no override
+
+  // PATCH
+
+  @Override
+  @Nullable
+  public <T> T patchForObject(String url, @Nullable Object request, Class<T> responseType,
+      Object... uriVariables) throws RestClientException {
+
+    RequestCallback requestCallback = httpEntityCallback(request, responseType);
+    CseHttpMessageConverterExtractor<T> responseExtractor =
+        new CseHttpMessageConverterExtractor<>();
+    return execute(url, HttpMethod.PATCH, requestCallback, responseExtractor, uriVariables);
+  }
+
+  @Override
+  @Nullable
+  public <T> T patchForObject(String url, @Nullable Object request, Class<T> responseType,
+      Map<String, ?> uriVariables) throws RestClientException {
+
+    RequestCallback requestCallback = httpEntityCallback(request, responseType);
+    CseHttpMessageConverterExtractor<T> responseExtractor =
+        new CseHttpMessageConverterExtractor<>();
+    return execute(url, HttpMethod.PATCH, requestCallback, responseExtractor, uriVariables);
+  }
+
+  @Override
+  @Nullable
+  public <T> T patchForObject(URI url, @Nullable Object request, Class<T> responseType)
+      throws RestClientException {
+
+    RequestCallback requestCallback = httpEntityCallback(request, responseType);
+    CseHttpMessageConverterExtractor<T> responseExtractor =
+        new CseHttpMessageConverterExtractor<>();
+    return execute(url, HttpMethod.PATCH, requestCallback, responseExtractor);
+  }
+
+  // DELETE
+  // no override
+
+  // OPTIONS
+  // no override
+
+  // exchange
+  // no override
+
+  @Override
+  public <T> ResponseExtractor<ResponseEntity<T>> responseEntityExtractor(Type responseType) {
+    return new CseResponseEntityResponseExtractor<>(responseType);
+  }
+
   @Override
   public <T> RequestCallback httpEntityCallback(Object requestBody) {
     RequestCallback callback = super.httpEntityCallback(requestBody);
diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRestTemplate.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRestTemplate.java
index 0f25b6e..683c1b4 100644
--- a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRestTemplate.java
+++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRestTemplate.java
@@ -20,26 +20,43 @@ package org.apache.servicecomb.provider.springmvc.reference.async;
 import java.lang.reflect.Type;
 import java.util.Arrays;
 
+import org.apache.servicecomb.provider.springmvc.reference.CseHttpMessageConverter;
+import org.apache.servicecomb.provider.springmvc.reference.CseRestTemplate;
 import org.apache.servicecomb.provider.springmvc.reference.CseUriTemplateHandler;
+import org.springframework.core.task.SimpleAsyncTaskExecutor;
 import org.springframework.http.HttpEntity;
-import org.springframework.web.client.CseHttpMessageConverter;
+import org.springframework.http.client.SimpleClientHttpRequestFactory;
+import org.springframework.web.client.RestTemplate;
 
 @SuppressWarnings("deprecation")
-// TODO : upgrade to spring 5 will having warning's , we'll fix it later
+// AsyncRestTemplate is deprecated by spring 5, using RPC with CompletableFuture instead.
+// Keep this function is only for compatibility, and maybe removed in future.
 public class CseAsyncRestTemplate extends org.springframework.web.client.AsyncRestTemplate {
   public CseAsyncRestTemplate() {
+    super(createSimpleClientHttpRequestFactory(), createRestTemplate());
     setMessageConverters(Arrays.asList(new CseHttpMessageConverter()));
     setAsyncRequestFactory(new CseAsyncClientHttpRequestFactory());
     setUriTemplateHandler(new CseUriTemplateHandler());
   }
 
+  private static SimpleClientHttpRequestFactory createSimpleClientHttpRequestFactory() {
+    SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
+    requestFactory.setTaskExecutor(new SimpleAsyncTaskExecutor());
+    return requestFactory;
+  }
+
+  private static RestTemplate createRestTemplate() {
+    return new CseRestTemplate();
+  }
+
   @Override
   protected <T> org.springframework.web.client.AsyncRequestCallback httpEntityCallback(HttpEntity<T> requestBody) {
     return new CseAsyncRequestCallback<T>(requestBody);
   }
 
   @Override
-  protected <T> org.springframework.web.client.AsyncRequestCallback httpEntityCallback(HttpEntity<T> requestBody, Type responseType) {
+  protected <T> org.springframework.web.client.AsyncRequestCallback httpEntityCallback(HttpEntity<T> requestBody,
+      Type responseType) {
     return new CseAsyncRequestCallback<T>(requestBody);
   }
 }
\ No newline at end of file
diff --git a/providers/provider-springmvc/src/test/java/org/springframework/web/client/TestCseHttpMessageConverter.java b/providers/provider-springmvc/src/test/java/org/springframework/web/client/TestCseHttpMessageConverter.java
deleted file mode 100644
index 23ee30d..0000000
--- a/providers/provider-springmvc/src/test/java/org/springframework/web/client/TestCseHttpMessageConverter.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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;
-
-import org.apache.servicecomb.provider.common.MockUtil;
-import org.apache.servicecomb.provider.springmvc.reference.CseClientHttpRequest;
-import org.junit.Assert;
-import org.junit.Test;
-import org.mockito.Mockito;
-import org.springframework.http.HttpOutputMessage;
-import org.springframework.http.converter.HttpMessageNotReadableException;
-import org.springframework.http.converter.HttpMessageNotWritableException;
-
-public class TestCseHttpMessageConverter {
-
-  @Test
-  public void testAll() {
-    MockUtil.getInstance().mockReflectionUtils();
-    MockUtil.getInstance().mockCseClientHttpRequest();
-    CseHttpMessageConverter lCseHttpMessageConverter = new CseHttpMessageConverter();
-    lCseHttpMessageConverter.canWrite(null, null);
-    lCseHttpMessageConverter.getSupportedMediaTypes();
-    try {
-      lCseHttpMessageConverter.read(this.getClass(), null);
-    } catch (HttpMessageNotReadableException | IOException ignored) {
-    }
-    try {
-      HttpOutputMessage httpOutputMessage = Mockito.mock(CseClientHttpRequest.class);
-      lCseHttpMessageConverter.write(null, null, httpOutputMessage);
-    } catch (HttpMessageNotWritableException | IOException ignored) {
-    }
-
-    Assert.assertEquals(true, lCseHttpMessageConverter.canRead(null, null));
-  }
-}