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 2023/08/23 00:55:09 UTC
[servicecomb-java-chassis] 04/06: [SCB-2803]add response proto-buffer codec
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
commit 2607f03314d7fb6e18e0d2f4188783bd56142220
Author: liubao <bi...@qq.com>
AuthorDate: Tue Aug 22 17:33:45 2023 +0800
[SCB-2803]add response proto-buffer codec
---
.../common/rest/HttpTransportContext.java | 11 +-
.../common/rest/RestProducerInvocationCreator.java | 17 --
.../rest/RestVertxProducerInvocationCreator.java | 3 +-
.../common/rest/VertxHttpTransportContext.java | 5 +-
.../rest/codec/param/BodyProcessorCreator.java | 10 +-
.../codec/produce/ProduceProcessorManager.java | 90 +++++-----
.../codec/produce/ProduceProtoBufferProcessor.java | 107 +++++++++++
.../codec/produce/ProduceTextPlainProcessor.java | 23 +--
.../common/rest/definition/RestOperationMeta.java | 124 -------------
.../rest/filter/inner/RestServerCodecFilter.java | 8 +-
.../rest/RestProducerInvocationCreatorTest.java | 39 +----
.../common/rest/codec/TestRestCodec.java | 3 +-
.../produce/TestProduceTextPlainProcessor.java | 4 +-
.../rest/definition/TestRestOperationMeta.java | 195 ---------------------
.../filter/inner/RestServerCodecFilterTest.java | 33 ++--
.../transport/rest/client/RestClientDecoder.java | 7 +-
.../RestServletProducerInvocationCreator.java | 2 +-
17 files changed, 226 insertions(+), 455 deletions(-)
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/HttpTransportContext.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/HttpTransportContext.java
index b9c8ea20a..d9b0df27c 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/HttpTransportContext.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/HttpTransportContext.java
@@ -16,7 +16,6 @@
*/
package org.apache.servicecomb.common.rest;
-import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor;
import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx;
import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx;
import org.apache.servicecomb.swagger.invocation.context.TransportContext;
@@ -26,13 +25,9 @@ public class HttpTransportContext implements TransportContext {
private final HttpServletResponseEx responseEx;
- private final ProduceProcessor produceProcessor;
-
- public HttpTransportContext(HttpServletRequestEx requestEx, HttpServletResponseEx responseEx,
- ProduceProcessor produceProcessor) {
+ public HttpTransportContext(HttpServletRequestEx requestEx, HttpServletResponseEx responseEx) {
this.requestEx = requestEx;
this.responseEx = responseEx;
- this.produceProcessor = produceProcessor;
}
public HttpServletRequestEx getRequestEx() {
@@ -42,8 +37,4 @@ public class HttpTransportContext implements TransportContext {
public HttpServletResponseEx getResponseEx() {
return responseEx;
}
-
- public ProduceProcessor getProduceProcessor() {
- return produceProcessor;
- }
}
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreator.java
index e38f228c7..778f3de4c 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreator.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreator.java
@@ -16,9 +16,7 @@
*/
package org.apache.servicecomb.common.rest;
-import static jakarta.ws.rs.core.Response.Status.NOT_ACCEPTABLE;
import static jakarta.ws.rs.core.Response.Status.NOT_FOUND;
-import static org.apache.servicecomb.core.exception.ExceptionCodes.GENERIC_CLIENT;
import static org.apache.servicecomb.core.exception.ExceptionCodes.NOT_DEFINED_ANY_SCHEMA;
import java.util.HashMap;
@@ -26,7 +24,6 @@ import java.util.Map;
import java.util.concurrent.CompletableFuture;
import javax.annotation.Nonnull;
-import jakarta.ws.rs.core.HttpHeaders;
import org.apache.commons.lang3.StringUtils;
import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor;
@@ -46,7 +43,6 @@ import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.annotations.VisibleForTesting;
import com.netflix.config.DynamicPropertyFactory;
import io.vertx.core.json.Json;
@@ -81,7 +77,6 @@ public abstract class RestProducerInvocationCreator implements InvocationCreator
Invocation invocation = createInstance();
initInvocationContext(invocation);
addParameterContext(invocation);
- initProduceProcessor();
initTransportContext(invocation);
invocation.addLocalContext(RestConst.REST_REQUEST, requestEx);
@@ -158,16 +153,4 @@ public abstract class RestProducerInvocationCreator implements InvocationCreator
protected OperationLocator locateOperation(ServicePathManager servicePathManager) {
return servicePathManager.producerLocateOperation(requestEx.getRequestURI(), requestEx.getMethod());
}
-
- @VisibleForTesting
- void initProduceProcessor() {
- produceProcessor = restOperationMeta.ensureFindProduceProcessor(requestEx);
- if (produceProcessor == null) {
- LOGGER.error("Accept {} is not supported, operation={}.", requestEx.getHeader(HttpHeaders.ACCEPT),
- restOperationMeta.getOperationMeta().getMicroserviceQualifiedName());
-
- String msg = String.format("Accept %s is not supported", requestEx.getHeader(HttpHeaders.ACCEPT));
- throw Exceptions.create(NOT_ACCEPTABLE, GENERIC_CLIENT, msg);
- }
- }
}
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestVertxProducerInvocationCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestVertxProducerInvocationCreator.java
index fcae4c7ab..a809f0968 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestVertxProducerInvocationCreator.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestVertxProducerInvocationCreator.java
@@ -38,8 +38,7 @@ public class RestVertxProducerInvocationCreator extends RestProducerInvocationCr
@Override
protected void initTransportContext(Invocation invocation) {
- VertxHttpTransportContext transportContext = new VertxHttpTransportContext(routingContext, requestEx, responseEx,
- produceProcessor);
+ VertxHttpTransportContext transportContext = new VertxHttpTransportContext(routingContext, requestEx, responseEx);
invocation.setTransportContext(transportContext);
routingContext.put(RestConst.REST_INVOCATION_CONTEXT, invocation);
}
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/VertxHttpTransportContext.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/VertxHttpTransportContext.java
index b88c1a12b..55576022e 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/VertxHttpTransportContext.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/VertxHttpTransportContext.java
@@ -16,7 +16,6 @@
*/
package org.apache.servicecomb.common.rest;
-import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor;
import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx;
import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx;
import org.apache.servicecomb.swagger.invocation.context.VertxTransportContext;
@@ -31,8 +30,8 @@ public class VertxHttpTransportContext extends HttpTransportContext implements V
private final Context vertxContext;
public VertxHttpTransportContext(RoutingContext routingContext, HttpServletRequestEx requestEx,
- HttpServletResponseEx responseEx, ProduceProcessor produceProcessor) {
- super(requestEx, responseEx, produceProcessor);
+ HttpServletResponseEx responseEx) {
+ super(requestEx, responseEx);
this.routingContext = routingContext;
this.vertxContext = Vertx.currentContext();
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java
index 736b8a060..b231f854c 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java
@@ -194,6 +194,10 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
// For application/json and text/plain
try {
+ if (MediaType.TEXT_PLAIN.equals(contentType) &&
+ targetType != null && String.class.equals(targetType.getRawClass())) {
+ return IOUtils.toString(inputStream, StandardCharsets.UTF_8);
+ }
ObjectReader reader = serialViewClass != null
? RestObjectMapperFactory.getRestObjectMapper().readerWithView(serialViewClass)
: RestObjectMapperFactory.getRestObjectMapper().reader();
@@ -257,7 +261,11 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
// For application/json and text/plain
try (BufferOutputStream output = new BufferOutputStream()) {
- RestObjectMapperFactory.getConsumerWriterMapper().writeValue(output, arg);
+ if (MediaType.TEXT_PLAIN.equals(contentType) && (arg instanceof String)) {
+ output.write(((String) arg).getBytes(StandardCharsets.UTF_8));
+ } else {
+ RestObjectMapperFactory.getConsumerWriterMapper().writeValue(output, arg);
+ }
return output.getBuffer();
}
}
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProcessorManager.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProcessorManager.java
index c883fa4c1..81302d576 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProcessorManager.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProcessorManager.java
@@ -21,13 +21,17 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import jakarta.ws.rs.core.MediaType;
-
+import org.apache.http.entity.ContentType;
+import org.apache.servicecomb.core.definition.OperationMeta;
import org.apache.servicecomb.foundation.common.RegisterManager;
import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
+import org.apache.servicecomb.swagger.generator.SwaggerConst;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.util.CollectionUtils;
+
+import io.swagger.v3.oas.models.responses.ApiResponse;
+import io.swagger.v3.oas.models.responses.ApiResponses;
+import jakarta.ws.rs.core.MediaType;
public final class ProduceProcessorManager extends RegisterManager<String, Map<String, ProduceProcessor>> {
private static final Logger LOGGER = LoggerFactory.getLogger(ProduceProcessorManager.class);
@@ -37,14 +41,10 @@ public final class ProduceProcessorManager extends RegisterManager<String, Map<S
private static final String NAME = "produce processor mgr";
- public static final String DEFAULT_TYPE = MediaType.APPLICATION_JSON;
-
public static final String DEFAULT_SERIAL_CLASS = "servicecomb_default_class";
public static final ProduceProcessorManager INSTANCE = new ProduceProcessorManager();
- private final Map<String, ProduceProcessor> nonSerialViewMap = new HashMap<>();
-
private final Map<String, ProduceProcessor> jsonProcessorMap;
private final Map<String, ProduceProcessor> plainProcessorMap;
@@ -54,7 +54,6 @@ public final class ProduceProcessorManager extends RegisterManager<String, Map<S
private ProduceProcessorManager() {
super(NAME);
produceProcessor.forEach(processor -> {
- nonSerialViewMap.put(processor.getName(), processor);
Map<String, ProduceProcessor> prodProcessorMap = getObjMap()
.computeIfAbsent(processor.getName(), key -> new HashMap<>());
prodProcessorMap.putIfAbsent(processor.getSerializationView(), processor);
@@ -78,32 +77,6 @@ public final class ProduceProcessorManager extends RegisterManager<String, Map<S
return produceViewMap.get(DEFAULT_SERIAL_CLASS);
}
- // key -> accept type
- public Map<String, ProduceProcessor> getOrCreateAcceptMap(Class<?> serialViewClass) {
- if (serialViewClass == null) {
- return nonSerialViewMap;
- }
- Map<String, ProduceProcessor> result = new HashMap<>();
- getObjMap().forEach((acceptKey, viewMap) -> {
- ProduceProcessor produceProcessor = viewMap.computeIfAbsent(serialViewClass.getName(),
- viewKey -> cloneNewProduceProcessor(serialViewClass, viewMap));
- result.put(acceptKey, produceProcessor);
- });
- return result;
- }
-
- public ProduceProcessor findProcessor(String acceptType, Class<?> serialViewClass) {
- Map<String, ProduceProcessor> viewMap = findValue(acceptType);
- if (CollectionUtils.isEmpty(viewMap)) {
- return null;
- }
- if (serialViewClass == null) {
- return viewMap.get(DEFAULT_SERIAL_CLASS);
- }
- return viewMap.computeIfAbsent(serialViewClass.getName(),
- viewKey -> cloneNewProduceProcessor(serialViewClass, viewMap));
- }
-
public ProduceProcessor findJsonProcessorByViewClass(Class<?> serialViewClass) {
if (serialViewClass == null) {
return jsonProcessorMap.get(DEFAULT_SERIAL_CLASS);
@@ -112,14 +85,6 @@ public final class ProduceProcessorManager extends RegisterManager<String, Map<S
viewKey -> cloneNewProduceProcessor(serialViewClass, jsonProcessorMap));
}
- public ProduceProcessor findDefaultProcessorByViewClass(Class<?> serialViewClass) {
- if (serialViewClass == null) {
- return defaultProcessorMap.get(DEFAULT_SERIAL_CLASS);
- }
- return defaultProcessorMap.computeIfAbsent(serialViewClass.getName(),
- viewKey -> cloneNewProduceProcessor(serialViewClass, defaultProcessorMap));
- }
-
public ProduceProcessor findPlainProcessorByViewClass(Class<?> serialViewClass) {
if (serialViewClass == null) {
return plainProcessorMap.get(DEFAULT_SERIAL_CLASS);
@@ -139,4 +104,45 @@ public final class ProduceProcessorManager extends RegisterManager<String, Map<S
public ProduceProcessor findDefaultPlainProcessor() {
return plainProcessorMap.get(DEFAULT_SERIAL_CLASS);
}
+
+ public ProduceProcessor createProduceProcessor(OperationMeta operationMeta,
+ int statusCode, String accept, Class<?> serialViewClass) {
+ ApiResponses responses = operationMeta.getSwaggerOperation().getResponses();
+ ApiResponse response = responses.get(String.valueOf(statusCode));
+ if (response == null || response.getContent() == null ||
+ response.getContent().size() == 0) {
+ return findDefaultProcessor();
+ }
+ String actualAccept = accept;
+ if (actualAccept == null) {
+ if (response.getContent().get(MediaType.APPLICATION_JSON) != null) {
+ actualAccept = MediaType.APPLICATION_JSON;
+ } else {
+ actualAccept = response.getContent().keySet().iterator().next();
+ }
+ }
+ ContentType contentType = ContentType.parse(actualAccept);
+ actualAccept = contentType.getMimeType();
+ if (MediaType.WILDCARD.equals(contentType.getMimeType()) ||
+ MediaType.MEDIA_TYPE_WILDCARD.equals(contentType.getMimeType())) {
+ if (response.getContent().get(MediaType.APPLICATION_JSON) != null) {
+ actualAccept = MediaType.APPLICATION_JSON;
+ } else {
+ actualAccept = response.getContent().keySet().iterator().next();
+ }
+ }
+ if (response.getContent().get(actualAccept) == null) {
+ LOGGER.warn("Operation do not support accept type {}/{}", accept, actualAccept);
+ return findDefaultProcessor();
+ }
+ if (SwaggerConst.PROTOBUF_TYPE.equals(actualAccept)) {
+ return new ProduceProtoBufferProcessor(operationMeta,
+ operationMeta.getSchemaMeta().getSwagger(), response.getContent().get(accept).getSchema());
+ }
+ if (MediaType.TEXT_PLAIN.equals(actualAccept)) {
+ return findPlainProcessorByViewClass(serialViewClass);
+ }
+ // json
+ return findJsonProcessorByViewClass(serialViewClass);
+ }
}
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProtoBufferProcessor.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProtoBufferProcessor.java
new file mode 100644
index 000000000..f1c8bc105
--- /dev/null
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProtoBufferProcessor.java
@@ -0,0 +1,107 @@
+/*
+ * 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.common.rest.codec.produce;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.servicecomb.codec.protobuf.utils.ScopedProtobufSchemaManager;
+import org.apache.servicecomb.core.definition.MicroserviceMeta;
+import org.apache.servicecomb.core.definition.OperationMeta;
+import org.apache.servicecomb.foundation.protobuf.ProtoMapper;
+import org.apache.servicecomb.foundation.protobuf.RootDeserializer;
+import org.apache.servicecomb.foundation.protobuf.RootSerializer;
+import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyWrapper;
+import org.apache.servicecomb.swagger.generator.SwaggerConst;
+
+import com.fasterxml.jackson.databind.JavaType;
+
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.media.Schema;
+
+public class ProduceProtoBufferProcessor implements ProduceProcessor {
+ public static final String RESPONSE_MESSAGE_NAME = "response";
+
+ public static final String EXT_ID = "protobuf";
+
+ private static final Object LOCK = new Object();
+
+ private final OperationMeta operationMeta;
+
+ private final OpenAPI openAPI;
+
+ private final Schema<?> schema;
+
+ private final ScopedProtobufSchemaManager scopedProtobufSchemaManager;
+
+ public ProduceProtoBufferProcessor(OperationMeta operationMeta, OpenAPI openAPI, Schema<?> schema) {
+ this.operationMeta = operationMeta;
+ this.openAPI = openAPI;
+ this.schema = schema;
+ this.scopedProtobufSchemaManager = getOrCreateScopedProtobufSchemaManager(operationMeta.getMicroserviceMeta());
+ }
+
+ private ScopedProtobufSchemaManager getOrCreateScopedProtobufSchemaManager(MicroserviceMeta microserviceMeta) {
+ ScopedProtobufSchemaManager scopedProtobufSchemaManager = microserviceMeta.getExtData(EXT_ID);
+ if (scopedProtobufSchemaManager == null) {
+ synchronized (LOCK) {
+ scopedProtobufSchemaManager = microserviceMeta.getExtData(EXT_ID);
+ if (scopedProtobufSchemaManager == null) {
+ scopedProtobufSchemaManager = new ScopedProtobufSchemaManager();
+ microserviceMeta.putExtData(EXT_ID, scopedProtobufSchemaManager);
+ }
+ }
+ }
+ return scopedProtobufSchemaManager;
+ }
+
+ @Override
+ public String getName() {
+ return SwaggerConst.PROTOBUF_TYPE;
+ }
+
+ @Override
+ public int getOrder() {
+ return 0;
+ }
+
+ @Override
+ public void doEncodeResponse(OutputStream output, Object result) throws Exception {
+ ProtoMapper protoMapper = scopedProtobufSchemaManager
+ .getOrCreateProtoMapper(openAPI, operationMeta.getSchemaId(),
+ RESPONSE_MESSAGE_NAME, schema);
+ RootSerializer serializer = protoMapper.getSerializerSchemaManager()
+ .createRootSerializer(protoMapper.getProto().getMessage(RESPONSE_MESSAGE_NAME),
+ Object.class);
+ Map<String, Object> bodyArg = new HashMap<>(1);
+ bodyArg.put("value", result);
+ output.write(serializer.serialize(bodyArg));
+ }
+
+ @Override
+ public Object doDecodeResponse(InputStream input, JavaType type) throws Exception {
+ ProtoMapper protoMapper = scopedProtobufSchemaManager
+ .getOrCreateProtoMapper(openAPI, operationMeta.getSchemaId(),
+ RESPONSE_MESSAGE_NAME, schema);
+ RootDeserializer<PropertyWrapper<Object>> deserializer = protoMapper.getDeserializerSchemaManager()
+ .createRootDeserializer(protoMapper.getProto().getMessage(RESPONSE_MESSAGE_NAME), type);
+ PropertyWrapper<Object> result = deserializer.deserialize(input.readAllBytes());
+ return result.getValue();
+ }
+}
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceTextPlainProcessor.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceTextPlainProcessor.java
index d5739be48..21d73688d 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceTextPlainProcessor.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceTextPlainProcessor.java
@@ -21,13 +21,13 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
-import jakarta.ws.rs.core.MediaType;
-
import org.apache.commons.io.IOUtils;
import com.fasterxml.jackson.databind.JavaType;
-public class ProduceTextPlainProcessor implements ProduceProcessor {
+import jakarta.ws.rs.core.MediaType;
+
+public class ProduceTextPlainProcessor extends ProduceJsonProcessor {
@Override
public String getName() {
return MediaType.TEXT_PLAIN;
@@ -35,17 +35,18 @@ public class ProduceTextPlainProcessor implements ProduceProcessor {
@Override
public void doEncodeResponse(OutputStream output, Object result) throws Exception {
- output.write(String.valueOf(result).getBytes(StandardCharsets.UTF_8));
+ if (result instanceof String) {
+ output.write(((String) result).getBytes(StandardCharsets.UTF_8));
+ return;
+ }
+ super.doEncodeResponse(output, result);
}
@Override
public Object doDecodeResponse(InputStream input, JavaType type) throws Exception {
- // plainText类型,肯定是返回string的,想不出有其他类型的场景
- return IOUtils.toString(input, StandardCharsets.UTF_8);
- }
-
- @Override
- public int getOrder() {
- return 0;
+ if (String.class.equals(type.getRawClass())) {
+ return IOUtils.toString(input, StandardCharsets.UTF_8);
+ }
+ return super.doDecodeResponse(input, type);
}
}
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestOperationMeta.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestOperationMeta.java
index 764160100..48bb32a8b 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestOperationMeta.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestOperationMeta.java
@@ -17,32 +17,23 @@
package org.apache.servicecomb.common.rest.definition;
-import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
-import java.util.Locale;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory;
import org.apache.servicecomb.common.rest.codec.param.FormProcessorCreator.PartProcessor;
-import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor;
-import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessorManager;
import org.apache.servicecomb.common.rest.definition.path.PathRegExp;
import org.apache.servicecomb.common.rest.definition.path.URLPathBuilder;
-import org.apache.servicecomb.core.Const;
import org.apache.servicecomb.core.definition.OperationMeta;
-import org.apache.servicecomb.foundation.common.utils.MimeTypesUtils;
-import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx;
import org.apache.servicecomb.swagger.SwaggerUtils;
-import org.apache.servicecomb.swagger.engine.SwaggerProducerOperation;
import org.apache.servicecomb.swagger.generator.SwaggerConst;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.type.TypeFactory;
@@ -54,7 +45,6 @@ import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.parameters.RequestBody;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.responses.ApiResponses;
-import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType;
@SuppressWarnings("rawtypes")
@@ -63,8 +53,6 @@ public class RestOperationMeta {
protected OperationMeta operationMeta;
- protected List<String> produces;
-
protected boolean formData;
// make sure if response is file
@@ -77,12 +65,6 @@ public class RestOperationMeta {
protected List<String> fileKeys = new ArrayList<>();
- // key为数据类型,比如json之类
- private final Map<String, ProduceProcessor> produceProcessorMap = new LinkedHashMap<>();
-
- // 不一定等于mgr中的default,因为本operation可能不支持mgr中的default
- private ProduceProcessor defaultProcessor;
-
protected String absolutePath;
protected PathRegExp absolutePathRegExp;
@@ -95,13 +77,8 @@ public class RestOperationMeta {
OpenAPI swagger = operationMeta.getSchemaMeta().getSwagger();
Operation operation = operationMeta.getSwaggerOperation();
- this.produces =
- (operation.getResponses().get(SwaggerConst.SUCCESS_KEY) == null ||
- operation.getResponses().get(SwaggerConst.SUCCESS_KEY).getContent() == null) ?
- null : operation.getResponses().get(SwaggerConst.SUCCESS_KEY).getContent().keySet().stream().toList();
this.downloadFile = checkDownloadFileFlag();
- this.createProduceProcessors();
if (operation.getParameters() != null) {
for (int swaggerParameterIdx = 0; swaggerParameterIdx < operation.getParameters().size(); swaggerParameterIdx++) {
@@ -259,76 +236,10 @@ public class RestOperationMeta {
return paramMap.get(name);
}
- public RestParam getParamByIndex(int index) {
- return paramList.get(index);
- }
-
public OperationMeta getOperationMeta() {
return operationMeta;
}
- protected void createProduceProcessors() {
- SwaggerProducerOperation producerOperation = operationMeta.getExtData(Const.PRODUCER_OPERATION);
- if (producerOperation != null && producerOperation.getProducerMethod() != null) {
- createProduceProcessors(producerOperation.getProducerMethod().getDeclaredAnnotations());
- return;
- }
- createProduceProcessors(null);
- }
-
- // serialViewClass is deterministic for each operation
- protected void createProduceProcessors(Annotation[] annotations) {
- if (annotations == null || annotations.length < 1) {
- doCreateProduceProcessors(null);
- return;
- }
- for (Annotation annotation : annotations) {
- if (annotation.annotationType() == JsonView.class) {
- Class<?>[] value = ((JsonView) annotation).value();
- if (value.length != 1) {
- throw new IllegalArgumentException(
- "@JsonView only supported for exactly 1 class argument ");
- }
- doCreateProduceProcessors(value[0]);
- return;
- }
- }
- doCreateProduceProcessors(null);
- }
-
- // 为operation创建支持的多种produce processor
- protected void doCreateProduceProcessors(Class<?> serialViewClass) {
- if (null == produces || produces.isEmpty()) {
- produceProcessorMap.putAll(
- ProduceProcessorManager.INSTANCE.getOrCreateAcceptMap(serialViewClass));
- } else {
- for (String produce : produces) {
- if (produce.contains(";")) {
- produce = produce.substring(0, produce.indexOf(";"));
- }
- ProduceProcessor processor = ProduceProcessorManager.INSTANCE.findProcessor(produce, serialViewClass);
- if (processor == null) {
- LOGGER.error("produce {} is not supported, operation={}.", produce,
- operationMeta.getMicroserviceQualifiedName());
- continue;
- }
- this.produceProcessorMap.put(produce, processor);
- }
-
- if (produceProcessorMap.isEmpty()) {
- produceProcessorMap.put(ProduceProcessorManager.DEFAULT_TYPE,
- ProduceProcessorManager.INSTANCE.findDefaultProcessorByViewClass(serialViewClass));
- }
- }
-
- if (produceProcessorMap.get(ProduceProcessorManager.DEFAULT_TYPE) != null) {
- defaultProcessor = produceProcessorMap.get(ProduceProcessorManager.DEFAULT_TYPE);
- } else {
- defaultProcessor = produceProcessorMap.values().stream().findFirst().get();
- }
- produceProcessorMap.putIfAbsent(MediaType.WILDCARD, defaultProcessor);
- }
-
public URLPathBuilder getPathBuilder() {
return this.pathBuilder;
}
@@ -345,37 +256,6 @@ public class RestOperationMeta {
paramMap.put(param.getParamName(), param);
}
- public ProduceProcessor findProduceProcessor(String type) {
- return this.produceProcessorMap.get(type);
- }
-
- // 选择与accept匹配的produce processor或者缺省的
- public ProduceProcessor ensureFindProduceProcessor(HttpServletRequestEx requestEx) {
- String acceptType = requestEx.getHeader(HttpHeaders.ACCEPT);
- return ensureFindProduceProcessor(acceptType);
- }
-
- public ProduceProcessor ensureFindProduceProcessor(String acceptType) {
- if (downloadFile) {
- //do not check accept type, when the produces of provider is text/plain there will return text/plain processor
- //when the produces of provider is application/json there will return the application/json processor
- //so do not care what accept type the consumer will set.
- return this.produceProcessorMap.get(MediaType.WILDCARD);
- }
- if (StringUtils.isEmpty(acceptType)) {
- return defaultProcessor;
- }
- List<String> mimeTypes = MimeTypesUtils.getSortedAcceptableMimeTypes(acceptType.toLowerCase(Locale.US));
- for (String mime : mimeTypes) {
- ProduceProcessor processor = this.produceProcessorMap.get(mime);
- if (null != processor) {
- return processor;
- }
- }
-
- return null;
- }
-
public String getHttpMethod() {
return operationMeta.getHttpMethod();
}
@@ -383,8 +263,4 @@ public class RestOperationMeta {
public List<String> getFileKeys() {
return fileKeys;
}
-
- public List<String> getProduces() {
- return produces;
- }
}
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilter.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilter.java
index 392112ec6..a40c7cb55 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilter.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilter.java
@@ -31,6 +31,7 @@ import org.apache.servicecomb.common.rest.HttpTransportContext;
import org.apache.servicecomb.common.rest.RestConst;
import org.apache.servicecomb.common.rest.codec.RestCodec;
import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor;
+import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessorManager;
import org.apache.servicecomb.common.rest.definition.RestOperationMeta;
import org.apache.servicecomb.core.Const;
import org.apache.servicecomb.core.Invocation;
@@ -51,6 +52,7 @@ import org.slf4j.LoggerFactory;
import io.netty.buffer.Unpooled;
import io.vertx.core.MultiMap;
import jakarta.servlet.http.Part;
+import jakarta.ws.rs.core.HttpHeaders;
public class RestServerCodecFilter implements ProviderFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(RestServerCodecFilter.class);
@@ -100,7 +102,11 @@ public class RestServerCodecFilter implements ProviderFilter {
invocation.onEncodeResponseStart(response);
HttpTransportContext transportContext = invocation.getTransportContext();
- ProduceProcessor produceProcessor = transportContext.getProduceProcessor();
+
+ // TODO: response support JsonView
+ ProduceProcessor produceProcessor = ProduceProcessorManager.INSTANCE
+ .createProduceProcessor(invocation.getOperationMeta(), response.getStatusCode(),
+ invocation.getRequestEx().getHeader(HttpHeaders.ACCEPT), null);
HttpServletResponseEx responseEx = transportContext.getResponseEx();
boolean download = isDownloadFileResponseType(invocation, response);
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreatorTest.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreatorTest.java
index 730aa22bf..108fb8722 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreatorTest.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreatorTest.java
@@ -22,8 +22,6 @@ import static jakarta.ws.rs.core.Response.Status.NOT_FOUND;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
-import jakarta.ws.rs.core.HttpHeaders;
-
import org.apache.servicecomb.common.rest.definition.RestOperationMeta;
import org.apache.servicecomb.common.rest.locator.OperationLocator;
import org.apache.servicecomb.common.rest.locator.ServicePathManager;
@@ -52,6 +50,7 @@ import org.mockito.Mockito;
import io.vertx.core.json.Json;
import io.vertx.ext.web.RoutingContext;
+import jakarta.ws.rs.core.HttpHeaders;
public class RestProducerInvocationCreatorTest {
@@ -113,43 +112,21 @@ public class RestProducerInvocationCreatorTest {
assertThat(throwable.getStatusCode()).isEqualTo(NOT_FOUND.getStatusCode());
assertThat(Json.encode(data)).isIn("{\"code\":\"SCB.00000002\",\"message\":\"Not Found\"}",
- "{\"message\":\"Not Found\",\"code\":\"SCB.00000002\"}");
- }
- }
-
- @Test
- public void should_failed_when_accept_is_not_support() {
- try (MockedStatic<ServicePathManager> mockedStatic = Mockito.mockStatic(ServicePathManager.class)) {
- mockedStatic.when(() -> ServicePathManager.getServicePathManager(microserviceMeta)).thenReturn(servicePathManager);
- Mockito.when(requestEx.getHeader(HttpHeaders.ACCEPT)).thenReturn("test-type");
- Mockito.when(restOperationMeta.ensureFindProduceProcessor(requestEx)).thenReturn(null);
- Mockito.when(creator.locateOperation(microserviceMeta)).thenReturn(locator);
- Mockito.when(locator.getOperation()).thenReturn(restOperationMeta);
- Mockito.when(restOperationMeta.getOperationMeta()).thenReturn(operationMeta);
- Mockito.when(operationMeta.buildBaseProviderRuntimeType()).thenReturn(invocationRuntimeType);
- Mockito.when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta);
- Mockito.when(schemaMeta.getMicroserviceMeta()).thenReturn(microserviceMeta);
-
- InvocationException throwable = (InvocationException) catchThrowable(() -> creator.createAsync().join());
- CommonExceptionData data = (CommonExceptionData) throwable.getErrorData();
-
- assertThat(throwable.getStatusCode()).isEqualTo(NOT_ACCEPTABLE.getStatusCode());
- assertThat(Json.encode(data)).isIn("{\"code\":\"SCB.00000000\",\"message\":\"Accept test-type is not supported\"}",
- "{\"message\":\"Accept test-type is not supported\",\"code\":\"SCB.00000000\"}");
+ "{\"message\":\"Not Found\",\"code\":\"SCB.00000002\"}");
}
}
@Test
public void should_save_requestEx_in_invocation_context() {
try (MockedStatic<ServicePathManager> mockedStatic = Mockito.mockStatic(ServicePathManager.class)) {
- mockedStatic.when(() -> ServicePathManager.getServicePathManager(microserviceMeta)).thenReturn(servicePathManager);
+ mockedStatic.when(() -> ServicePathManager.getServicePathManager(microserviceMeta))
+ .thenReturn(servicePathManager);
Mockito.when(creator.locateOperation(microserviceMeta)).thenReturn(locator);
Mockito.when(locator.getOperation()).thenReturn(restOperationMeta);
Mockito.when(restOperationMeta.getOperationMeta()).thenReturn(operationMeta);
Mockito.when(operationMeta.buildBaseProviderRuntimeType()).thenReturn(invocationRuntimeType);
Mockito.when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta);
Mockito.when(schemaMeta.getMicroserviceMeta()).thenReturn(microserviceMeta);
- Mockito.doNothing().when(creator).initProduceProcessor();
Invocation invocation = creator.createAsync().join();
@@ -161,14 +138,14 @@ public class RestProducerInvocationCreatorTest {
@Test
public void should_save_path_var_map_in_requestEx() {
try (MockedStatic<ServicePathManager> mockedStatic = Mockito.mockStatic(ServicePathManager.class)) {
- mockedStatic.when(() -> ServicePathManager.getServicePathManager(microserviceMeta)).thenReturn(servicePathManager);
+ mockedStatic.when(() -> ServicePathManager.getServicePathManager(microserviceMeta))
+ .thenReturn(servicePathManager);
Mockito.when(creator.locateOperation(microserviceMeta)).thenReturn(locator);
Mockito.when(locator.getOperation()).thenReturn(restOperationMeta);
Mockito.when(restOperationMeta.getOperationMeta()).thenReturn(operationMeta);
Mockito.when(operationMeta.buildBaseProviderRuntimeType()).thenReturn(invocationRuntimeType);
Mockito.when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta);
Mockito.when(schemaMeta.getMicroserviceMeta()).thenReturn(microserviceMeta);
- Mockito.doNothing().when(creator).initProduceProcessor();
creator.createAsync().join();
@@ -179,14 +156,14 @@ public class RestProducerInvocationCreatorTest {
@Test
public void should_merge_invocation_context_from_request() {
try (MockedStatic<ServicePathManager> mockedStatic = Mockito.mockStatic(ServicePathManager.class)) {
- mockedStatic.when(() -> ServicePathManager.getServicePathManager(microserviceMeta)).thenReturn(servicePathManager);
+ mockedStatic.when(() -> ServicePathManager.getServicePathManager(microserviceMeta))
+ .thenReturn(servicePathManager);
Mockito.when(creator.locateOperation(microserviceMeta)).thenReturn(locator);
Mockito.when(locator.getOperation()).thenReturn(restOperationMeta);
Mockito.when(restOperationMeta.getOperationMeta()).thenReturn(operationMeta);
Mockito.when(operationMeta.buildBaseProviderRuntimeType()).thenReturn(invocationRuntimeType);
Mockito.when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta);
Mockito.when(schemaMeta.getMicroserviceMeta()).thenReturn(microserviceMeta);
- Mockito.doNothing().when(creator).initProduceProcessor();
Mockito.when(requestEx.getHeader(Const.CSE_CONTEXT)).thenReturn("{\"k\":\"v\"}");
Invocation invocation = creator.createAsync().join();
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestCodec.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestCodec.java
index ebbe2975a..5e7270a6e 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestCodec.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestCodec.java
@@ -27,7 +27,6 @@ import org.apache.servicecomb.common.rest.codec.param.RestClientRequestImpl;
import org.apache.servicecomb.common.rest.definition.RestOperationMeta;
import org.apache.servicecomb.common.rest.definition.RestParam;
import org.apache.servicecomb.core.definition.OperationMeta;
-import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData;
import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
@@ -160,7 +159,7 @@ public class TestRestCodec {
success = true;
} catch (InvocationException e) {
Assertions.assertEquals(e.getStatusCode(), Status.BAD_REQUEST.getStatusCode());
- Assertions.assertTrue(((CommonExceptionData) e.getErrorData()).getMessage()
+ Assertions.assertTrue(((String) e.getErrorData())
.contains("Parameter is not valid for operation"));
}
Assertions.assertFalse(success);
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/produce/TestProduceTextPlainProcessor.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/produce/TestProduceTextPlainProcessor.java
index d7413d938..d717072a2 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/produce/TestProduceTextPlainProcessor.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/produce/TestProduceTextPlainProcessor.java
@@ -52,7 +52,7 @@ public class TestProduceTextPlainProcessor {
Object result = pp.decodeResponse(Buffer.buffer(), resultType);
Assertions.assertNull(result);
- ByteArrayInputStream is = new ByteArrayInputStream(new byte[] {});
+ ByteArrayInputStream is = new ByteArrayInputStream("\"\"".getBytes(StandardCharsets.UTF_8));
result = pp.decodeResponse(is, resultType);
Assertions.assertEquals(result, "");
}
@@ -91,6 +91,6 @@ public class TestProduceTextPlainProcessor {
Assertions.assertEquals(DEFAULT_SERIAL_CLASS, pp.getSerializationView());
pp.setSerializationView(Object.class);
- Assertions.assertEquals(DEFAULT_SERIAL_CLASS, pp.getSerializationView());
+ Assertions.assertEquals("java.lang.Object", pp.getSerializationView());
}
}
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestRestOperationMeta.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestRestOperationMeta.java
index 27d70d4e7..911bf2c6f 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestRestOperationMeta.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestRestOperationMeta.java
@@ -25,8 +25,6 @@ import java.util.Arrays;
import java.util.List;
import org.apache.servicecomb.common.rest.RestEngineSchemaListener;
-import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor;
-import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessorManager;
import org.apache.servicecomb.config.ConfigUtil;
import org.apache.servicecomb.core.BootListener;
import org.apache.servicecomb.core.SCBEngine;
@@ -36,7 +34,6 @@ import org.apache.servicecomb.core.definition.SchemaMeta;
import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils;
import org.hamcrest.MatcherAssert;
import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
@@ -191,198 +188,6 @@ public class TestRestOperationMeta {
Mockito.when(schemaMeta.getSwagger()).thenReturn(swagger);
}
- @Test
- public void testCreateProduceProcessorsNull() {
- findOperation("emptyProduces");
- operationMeta.produces = null;
- operationMeta.createProduceProcessors();
-
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
- operationMeta.ensureFindProduceProcessor((String) null));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
- operationMeta.ensureFindProduceProcessor("*/*"));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
- operationMeta.ensureFindProduceProcessor(ProduceProcessorManager.DEFAULT_TYPE));
- for (String produce : ProduceProcessorManager.INSTANCE.keys()) {
- ProduceProcessor expected = ProduceProcessorManager.INSTANCE.findProcessor(produce, null);
- Assertions.assertSame(expected, operationMeta.findProduceProcessor(produce));
- }
- }
-
- @Test
- public void testCreateProduceProcessorsNullWithView() {
- findOperation("emptyProducesWithView");
- operationMeta.produces = null;
- operationMeta.createProduceProcessors();
-
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessorByViewClass(Object.class),
- operationMeta.ensureFindProduceProcessor((String) null));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessorByViewClass(Object.class),
- operationMeta.ensureFindProduceProcessor("*/*"));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessorByViewClass(Object.class),
- operationMeta.ensureFindProduceProcessor(ProduceProcessorManager.DEFAULT_TYPE));
- for (String produce : ProduceProcessorManager.INSTANCE.keys()) {
- ProduceProcessor expected = ProduceProcessorManager.INSTANCE.findProcessor(produce, Object.class);
- Assertions.assertSame(expected, operationMeta.findProduceProcessor(produce));
- }
- }
-
- @Test
- public void testCreateProduceProcessorsEmpty() {
- findOperation("emptyProduces");
- operationMeta.produces = Arrays.asList();
- operationMeta.createProduceProcessors();
-
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
- operationMeta.ensureFindProduceProcessor((String) null));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
- operationMeta.ensureFindProduceProcessor("*/*"));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
- operationMeta.ensureFindProduceProcessor(ProduceProcessorManager.DEFAULT_TYPE));
- for (String produce : ProduceProcessorManager.INSTANCE.keys()) {
- ProduceProcessor expected = ProduceProcessorManager.INSTANCE.findProcessor(produce, null);
- Assertions.assertSame(expected, operationMeta.findProduceProcessor(produce));
- }
- }
-
- @Test
- public void testCreateProduceProcessorsEmptyWithView() {
- findOperation("emptyProducesWithView");
- operationMeta.produces = Arrays.asList();
- operationMeta.createProduceProcessors();
-
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessorByViewClass(Object.class),
- operationMeta.ensureFindProduceProcessor((String) null));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessorByViewClass(Object.class),
- operationMeta.ensureFindProduceProcessor("*/*"));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessorByViewClass(Object.class),
- operationMeta.ensureFindProduceProcessor(ProduceProcessorManager.DEFAULT_TYPE));
- for (String produce : ProduceProcessorManager.INSTANCE.keys()) {
- ProduceProcessor expected = ProduceProcessorManager.INSTANCE.findProcessor(produce, Object.class);
- Assertions.assertSame(expected, operationMeta.findProduceProcessor(produce));
- }
- }
-
- @Test
- public void testCreateProduceProcessorsNormal() {
- findOperation("json");
-
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
- operationMeta.ensureFindProduceProcessor((String) null));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
- operationMeta.ensureFindProduceProcessor("*/*"));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
- operationMeta.ensureFindProduceProcessor(ProduceProcessorManager.DEFAULT_TYPE));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultJsonProcessor(),
- operationMeta.findProduceProcessor(MediaType.APPLICATION_JSON));
- Assertions.assertNull(operationMeta.findProduceProcessor(MediaType.TEXT_PLAIN));
- }
-
- @Test
- public void testCreateProduceProcessorsNormalWithView() {
- findOperation("jsonWithView");
-
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findJsonProcessorByViewClass(Object.class),
- operationMeta.ensureFindProduceProcessor((String) null));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findJsonProcessorByViewClass(Object.class),
- operationMeta.ensureFindProduceProcessor("*/*"));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findJsonProcessorByViewClass(Object.class),
- operationMeta.ensureFindProduceProcessor(ProduceProcessorManager.DEFAULT_TYPE));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findJsonProcessorByViewClass(Object.class),
- operationMeta.findProduceProcessor(MediaType.APPLICATION_JSON));
- Assertions.assertNull(operationMeta.findProduceProcessor(MediaType.TEXT_PLAIN));
- }
-
- @Test
- public void testCreateProduceProcessorsNotSupported() {
- findOperation("notSupport");
-
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
- operationMeta.ensureFindProduceProcessor((String) null));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
- operationMeta.ensureFindProduceProcessor("*/*"));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
- operationMeta.ensureFindProduceProcessor(ProduceProcessorManager.DEFAULT_TYPE));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultJsonProcessor(),
- operationMeta.findProduceProcessor(MediaType.APPLICATION_JSON));
- Assertions.assertNotNull(operationMeta.findProduceProcessor(MediaType.TEXT_PLAIN));
- }
-
- @Test
- public void testCreateProduceProcessorsNotSupportedWithView() {
- findOperation("notSupportWithView");
-
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessorByViewClass(Object.class),
- operationMeta.ensureFindProduceProcessor((String) null));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessorByViewClass(Object.class),
- operationMeta.ensureFindProduceProcessor("*/*"));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessorByViewClass(Object.class),
- operationMeta.ensureFindProduceProcessor(ProduceProcessorManager.DEFAULT_TYPE));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessorByViewClass(Object.class),
- operationMeta.findProduceProcessor(MediaType.APPLICATION_JSON));
- Assertions.assertNotNull(operationMeta.findProduceProcessor(MediaType.TEXT_PLAIN));
- }
-
- @Test
- public void testCreateProduceProcessorsTextAndWildcard() {
- findOperation("textPlain");
-
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultPlainProcessor(),
- operationMeta.ensureFindProduceProcessor(MediaType.WILDCARD));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultPlainProcessor(),
- operationMeta.ensureFindProduceProcessor(MediaType.TEXT_PLAIN));
- Assertions.assertNull(operationMeta.ensureFindProduceProcessor(MediaType.APPLICATION_JSON));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultPlainProcessor(),
- operationMeta.ensureFindProduceProcessor(
- MediaType.APPLICATION_JSON + "," + MediaType.APPLICATION_XML + "," + MediaType.WILDCARD));
- }
-
- @Test
- public void testCreateProduceProcessorsTextAndWildcardWithView() {
- findOperation("textPlainWithView");
-
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findPlainProcessorByViewClass(Object.class),
- operationMeta.ensureFindProduceProcessor(MediaType.WILDCARD));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findPlainProcessorByViewClass(Object.class),
- operationMeta.ensureFindProduceProcessor(MediaType.TEXT_PLAIN));
- Assertions.assertNull(operationMeta.ensureFindProduceProcessor(MediaType.APPLICATION_JSON));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findPlainProcessorByViewClass(Object.class),
- operationMeta.ensureFindProduceProcessor(
- MediaType.APPLICATION_JSON + "," + MediaType.APPLICATION_XML + "," + MediaType.WILDCARD));
- }
-
- @Test
- public void testCreateProduceProcessorsWithSemicolon() {
- findOperation("textCharJsonChar");
-
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultPlainProcessor(),
- operationMeta.ensureFindProduceProcessor(MediaType.TEXT_PLAIN));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultJsonProcessor(),
- operationMeta.ensureFindProduceProcessor(MediaType.APPLICATION_JSON));
- }
-
- @Test
- public void testCreateProduceProcessorsWithSemicolonWithView() {
- findOperation("textCharJsonCharWithView");
-
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findPlainProcessorByViewClass(Object.class),
- operationMeta.ensureFindProduceProcessor(MediaType.TEXT_PLAIN));
- Assertions.assertSame(ProduceProcessorManager.INSTANCE.findJsonProcessorByViewClass(Object.class),
- operationMeta.ensureFindProduceProcessor(MediaType.APPLICATION_JSON));
- }
-
- @Test
- public void testEnsureFindProduceProcessorAcceptNotFound() {
- findOperation("textCharJsonChar");
- Assertions.assertNull(operationMeta.ensureFindProduceProcessor("notSupport"));
- }
-
- @Test
- public void testEnsureFindProduceProcessorAcceptNotFoundWithView() {
- findOperation("textCharJsonCharWithView");
- Assertions.assertNull(operationMeta.ensureFindProduceProcessor("notSupport"));
- }
-
@Test
public void generatesAbsolutePathWithRootBasePath() {
findOperation("textCharJsonChar");
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilterTest.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilterTest.java
index 0a88c3c2b..ab982a409 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilterTest.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilterTest.java
@@ -20,14 +20,12 @@ package org.apache.servicecomb.common.rest.filter.inner;
import static com.google.common.net.HttpHeaders.CONTENT_LENGTH;
import static com.google.common.net.HttpHeaders.TRANSFER_ENCODING;
import static jakarta.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
-import static org.assertj.core.api.Assertions.assertThat;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import org.apache.servicecomb.common.rest.HttpTransportContext;
import org.apache.servicecomb.common.rest.RestConst;
-import org.apache.servicecomb.common.rest.codec.produce.ProduceJsonProcessor;
import org.apache.servicecomb.common.rest.definition.RestOperationMeta;
import org.apache.servicecomb.config.ConfigUtil;
import org.apache.servicecomb.core.Endpoint;
@@ -43,9 +41,11 @@ import org.apache.servicecomb.core.filter.FilterNode;
import org.apache.servicecomb.core.invocation.InvocationFactory;
import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils;
import org.apache.servicecomb.foundation.test.scaffolding.exception.RuntimeExceptionWithoutStackTrace;
+import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx;
import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx;
import org.apache.servicecomb.swagger.invocation.Response;
import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -54,9 +54,14 @@ import org.mockito.Mockito;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.type.TypeFactory;
+import io.swagger.v3.oas.models.Operation;
+import io.swagger.v3.oas.models.media.Content;
+import io.swagger.v3.oas.models.media.StringSchema;
+import io.swagger.v3.oas.models.responses.ApiResponse;
+import io.swagger.v3.oas.models.responses.ApiResponses;
import io.vertx.core.MultiMap;
-import io.vertx.core.json.Json;
import jakarta.servlet.http.Part;
+import jakarta.ws.rs.core.MediaType;
public class RestServerCodecFilterTest {
final RestServerCodecFilter codecFilter = new RestServerCodecFilter();
@@ -109,7 +114,6 @@ public class RestServerCodecFilterTest {
Mockito.when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta);
Mockito.when(schemaMeta.getMicroserviceMeta()).thenReturn(microserviceMeta);
Mockito.when(operationMeta.buildBaseProviderRuntimeType()).thenReturn(invocationRuntimeType);
- Mockito.when(transportContext.getProduceProcessor()).thenReturn(Mockito.mock(ProduceJsonProcessor.class));
invocation = Mockito.spy(InvocationFactory.forProvider(endpoint, operationMeta, null));
}
@@ -137,16 +141,25 @@ public class RestServerCodecFilterTest {
Mockito.when(invocation.findResponseType(INTERNAL_SERVER_ERROR.getStatusCode()))
.thenReturn(TypeFactory.defaultInstance().constructType(String.class));
- Response response = codecFilter.onFilter(invocation, nextNode).get();
-
- assertThat(response.getStatus()).isEqualTo(INTERNAL_SERVER_ERROR);
- assertThat(Json.encode(response.getResult())).
- isIn("{\"code\":\"SCB.50000000\",\"message\":\"Unexpected "
- + "exception when processing null. mock encode request failed\"}");
+ Assertions.assertThrows(ExecutionException.class,
+ () -> codecFilter.onFilter(invocation, nextNode).get());
}
private void success_invocation() throws InterruptedException, ExecutionException {
Mockito.when(invocation.getTransportContext()).thenReturn(transportContext);
+ HttpServletRequestEx requestExt = Mockito.mock(HttpServletRequestEx.class);
+ Mockito.when(invocation.getRequestEx()).thenReturn(requestExt);
+ Mockito.when(invocation.getOperationMeta()).thenReturn(operationMeta);
+ Operation swaggerOperation = Mockito.mock(Operation.class);
+ Mockito.when(operationMeta.getSwaggerOperation()).thenReturn(swaggerOperation);
+ ApiResponses apiResponses = Mockito.mock(ApiResponses.class);
+ Mockito.when(swaggerOperation.getResponses()).thenReturn(apiResponses);
+ ApiResponse apiResponse = Mockito.mock(ApiResponse.class);
+ Mockito.when(apiResponses.get("200")).thenReturn(apiResponse);
+ Content content = new Content();
+ content.addMediaType(MediaType.APPLICATION_JSON, new io.swagger.v3.oas.models.media.MediaType());
+ content.get(MediaType.APPLICATION_JSON).setSchema(new StringSchema());
+ Mockito.when(apiResponse.getContent()).thenReturn(content);
Mockito.when(operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION)).thenReturn(restOperationMeta);
Mockito.when(invocation.findResponseType(INTERNAL_SERVER_ERROR.getStatusCode()))
.thenReturn(TypeFactory.defaultInstance().constructType(String.class));
diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientDecoder.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientDecoder.java
index db277b68e..cd3c4e89e 100644
--- a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientDecoder.java
+++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientDecoder.java
@@ -62,14 +62,15 @@ public class RestClientDecoder {
}
private ProduceProcessor safeFindProduceProcessor(Invocation invocation, Response response) {
- RestClientTransportContext transportContext = invocation.getTransportContext();
-
String contentType = extractContentType(response);
- ProduceProcessor produceProcessor = transportContext.getRestOperationMeta().findProduceProcessor(contentType);
+ ProduceProcessor produceProcessor =
+ ProduceProcessorManager.INSTANCE.createProduceProcessor(invocation.getOperationMeta(), response.getStatusCode(),
+ contentType, null);
if (produceProcessor != null) {
return produceProcessor;
}
+ RestClientTransportContext transportContext = invocation.getTransportContext();
HttpClientRequest httpClientRequest = transportContext.getHttpClientRequest();
LOGGER.warn(
"operation={}, method={}, endpoint={}, uri={}, statusCode={}, reasonPhrase={}, response content-type={} is not supported in operation.",
diff --git a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServletProducerInvocationCreator.java b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServletProducerInvocationCreator.java
index 97cf131c5..a12ee8cc0 100644
--- a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServletProducerInvocationCreator.java
+++ b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServletProducerInvocationCreator.java
@@ -34,7 +34,7 @@ public class RestServletProducerInvocationCreator extends RestProducerInvocation
@Override
protected void initTransportContext(Invocation invocation) {
- HttpTransportContext transportContext = new HttpTransportContext(requestEx, responseEx, produceProcessor);
+ HttpTransportContext transportContext = new HttpTransportContext(requestEx, responseEx);
invocation.setTransportContext(transportContext);
}
}