This is an automated email from the ASF dual-hosted git repository. liubao pushed a commit to branch weak-contract-type in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git
commit e1d1c7db7b3f684a4c783d743da0c28a6871a9b1 Author: wujimin <[email protected]> AuthorDate: Wed Jul 3 21:37:57 2019 +0800 [SCB-1212[WIP][WEAK] response mapper not depend on swagger class generation --- .../invocation/response/ResponseMapperFactory.java | 10 +-- .../response/ResponseMapperFactorys.java | 19 +---- .../swagger/invocation/response/ResponseMeta.java | 63 -------------- .../invocation/response/ResponseMetaMapper.java | 4 +- .../swagger/invocation/response/ResponsesMeta.java | 96 +++++++++++++--------- .../response/TestResponseMapperFactorys.java | 89 -------------------- .../invocation/response/TestResponsesMeta.java | 37 ++++----- 7 files changed, 83 insertions(+), 235 deletions(-) diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMapperFactory.java index 70d8871..73a2f1a 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMapperFactory.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMapperFactory.java @@ -18,18 +18,12 @@ package org.apache.servicecomb.swagger.invocation.response; import java.lang.reflect.Type; -import org.apache.servicecomb.swagger.invocation.converter.ConverterMgr; - public interface ResponseMapperFactory<MAPPER> { default int getOrder() { return 0; } - default void setConverterMgr(ConverterMgr converterMgr) { - } - - boolean isMatch(Type swaggerType, Type providerType); + boolean isMatch(Type providerType); - MAPPER createResponseMapper(ResponseMapperFactorys<MAPPER> factorys, Type swaggerType, - Type providerType); + MAPPER createResponseMapper(ResponseMapperFactorys<MAPPER> factorys, Type providerType); } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMapperFactorys.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMapperFactorys.java index 92e95c6..9a37037 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMapperFactorys.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMapperFactorys.java @@ -20,37 +20,26 @@ import java.lang.reflect.Type; import java.util.List; import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.swagger.invocation.converter.ConverterMgr; public class ResponseMapperFactorys<MAPPER> { private List<ResponseMapperFactory<MAPPER>> factorys; - public ResponseMapperFactorys(Class<? extends ResponseMapperFactory<MAPPER>> factoryCls, ConverterMgr converterMgr) { - this(factoryCls); - this.setConverterMgr(converterMgr); - } - @SuppressWarnings("unchecked") public ResponseMapperFactorys(Class<? extends ResponseMapperFactory<MAPPER>> factoryCls) { factorys = (List<ResponseMapperFactory<MAPPER>>) SPIServiceUtils.getSortedService(factoryCls); } - public void setConverterMgr(ConverterMgr converterMgr) { - factorys.forEach(factory -> factory.setConverterMgr(converterMgr)); - } - - public MAPPER createResponseMapper(Type swaggerType, Type providerType) { + public MAPPER createResponseMapper(Type providerType) { for (ResponseMapperFactory<MAPPER> factory : factorys) { - if (!factory.isMatch(swaggerType, providerType)) { + if (!factory.isMatch(providerType)) { continue; } - return factory.createResponseMapper(this, swaggerType, providerType); + return factory.createResponseMapper(this, providerType); } throw new IllegalStateException( - String.format("can not find response mapper for %s and %s, this should never happened.", - swaggerType.getTypeName(), + String.format("can not find response mapper for %s, this should never happened.", providerType.getTypeName())); } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMeta.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMeta.java deleted file mode 100644 index 3aade01..0000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMeta.java +++ /dev/null @@ -1,63 +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.apache.servicecomb.swagger.invocation.response; - -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; - -import com.fasterxml.jackson.databind.JavaType; - -import io.swagger.models.Response; -import io.swagger.models.properties.Property; - -public class ResponseMeta { - /** - * swagger中定义的statusCode与java类型的映射,方便consumer端transport将码流转换为具体的类型 - */ - private JavaType javaType; - - private Map<String, JavaType> headers = new HashMap<>(); - - public void init(SwaggerToClassGenerator swaggerToClassGenerator, Response response) { - if (javaType == null) { - javaType = swaggerToClassGenerator.convert(response.getResponseSchema()); - } - - if (response.getHeaders() == null) { - return; - } - for (Entry<String, Property> entry : response.getHeaders().entrySet()) { - JavaType headerJavaType = swaggerToClassGenerator.convert(entry.getValue()); - headers.put(entry.getKey(), headerJavaType); - } - } - - public JavaType getJavaType() { - return javaType; - } - - public void setJavaType(JavaType javaType) { - this.javaType = javaType; - } - - public Map<String, JavaType> getHeaders() { - return headers; - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMetaMapper.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMetaMapper.java index e357711..8de01af 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMetaMapper.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMetaMapper.java @@ -19,10 +19,12 @@ package org.apache.servicecomb.swagger.invocation.response; import java.util.Map; +import com.fasterxml.jackson.databind.JavaType; + public interface ResponseMetaMapper { default int getOrder() { return 0; } - Map<Integer, ResponseMeta> getMapper(); + Map<Integer, JavaType> getMapper(); } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponsesMeta.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponsesMeta.java index 881cb81..2321eb3 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponsesMeta.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponsesMeta.java @@ -16,7 +16,8 @@ */ package org.apache.servicecomb.swagger.invocation.response; -import java.lang.reflect.Type; +import static io.swagger.util.ReflectionUtils.isVoid; + import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; @@ -24,18 +25,43 @@ import java.util.Map.Entry; import javax.ws.rs.core.Response.Status; import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; +import org.apache.servicecomb.swagger.converter.ConverterMgr; import org.apache.servicecomb.swagger.invocation.context.HttpStatus; import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.type.SimpleType; -import com.fasterxml.jackson.databind.type.TypeFactory; import io.swagger.models.Operation; import io.swagger.models.Response; - +import io.swagger.models.Swagger; + +/** + * <pre> + * two Scenes: + * 1.consumer interface + swagger + * interface declare success response type + * and can declare exceptions response type by annotations + * consumer interface meta never changed and has high priority + * + * so, merge them to be one ResponsesMeta + * + * 2.restTemplate + swagger + * can only declare success response type + * and not stable + * + * so, will wrap swagger meta + * + * note: + * old version support: List<User> users = restTemplate.postForObject(...., List.class) + * in fact, in this time, type is determined by swagger meta + * new version: + * 1) if request response type is List/Set/Map, and there is element type defined, then use swagger type, + * 2) other times use request response type + * 3) compare to old version, add support of ParameterizedTypeReference + * </pre> + */ public class ResponsesMeta { private static final JavaType COMMON_EXCEPTION_JAVA_TYPE = SimpleType.constructUnsafe(CommonExceptionData.class); @@ -44,65 +70,61 @@ public class ResponsesMeta { private static final ResponseMetaMapper GLOBAL_DEFAULT_MAPPER = SPIServiceUtils .getPriorityHighestService(ResponseMetaMapper.class); - private Map<Integer, ResponseMeta> responseMap = new HashMap<>(); + private Map<Integer, JavaType> responseMap = new HashMap<>(); - private ResponseMeta defaultResponse; + private JavaType defaultResponse; - // 最后一个参数returnType用于兼容场景 - // 历史版本中swagger中定义的return可能没定义class名,此时consumer与swagger接口是一致的 - // 如果不传return类型进来,完全以swagger为标准,会导致生成的class不等于return - public void init(SwaggerToClassGenerator swaggerToClassGenerator, Operation operation, Type returnType) { - initSuccessResponse(returnType); - initGlobalDefaultMapper(); + public void init(Swagger swagger, Operation operation) { + if (responseMap.isEmpty()) { + responseMap.put(Status.OK.getStatusCode(), OBJECT_JAVA_TYPE); + initGlobalDefaultMapper(); + } for (Entry<String, Response> entry : operation.getResponses().entrySet()) { + JavaType javaType = ConverterMgr.findJavaType(swagger, entry.getValue().getResponseSchema()); + if ("default".equals(entry.getKey())) { - defaultResponse = new ResponseMeta(); - defaultResponse.init(swaggerToClassGenerator, entry.getValue()); + defaultResponse = javaType; continue; } Integer statusCode = Integer.parseInt(entry.getKey()); - ResponseMeta responseMeta = responseMap.computeIfAbsent(statusCode, k -> new ResponseMeta()); - responseMeta.init(swaggerToClassGenerator, entry.getValue()); + JavaType existing = responseMap.get(statusCode); + if (existing == null || !isVoid(javaType)) { + responseMap.put(statusCode, javaType); + } } - initInternalErrorResponse(); + responseMap.putIfAbsent(ExceptionFactory.CONSUMER_INNER_STATUS_CODE, COMMON_EXCEPTION_JAVA_TYPE); + responseMap.putIfAbsent(ExceptionFactory.PRODUCER_INNER_STATUS_CODE, COMMON_EXCEPTION_JAVA_TYPE); if (defaultResponse == null) { // swagger中没有定义default,加上default专用于处理exception - ResponseMeta responseMeta = new ResponseMeta(); - responseMeta.setJavaType(OBJECT_JAVA_TYPE); - - defaultResponse = responseMeta; + defaultResponse = OBJECT_JAVA_TYPE; } } - protected void initSuccessResponse(Type returnType) { - ResponseMeta successResponse = new ResponseMeta(); - successResponse.setJavaType(TypeFactory.defaultInstance().constructType(returnType)); - responseMap.put(Status.OK.getStatusCode(), successResponse); - } - - protected void initInternalErrorResponse() { - ResponseMeta internalErrorResponse = new ResponseMeta(); - internalErrorResponse.setJavaType(COMMON_EXCEPTION_JAVA_TYPE); - responseMap.putIfAbsent(ExceptionFactory.CONSUMER_INNER_STATUS_CODE, internalErrorResponse); - responseMap.putIfAbsent(ExceptionFactory.PRODUCER_INNER_STATUS_CODE, internalErrorResponse); + public void cloneTo(ResponsesMeta target) { + target.defaultResponse = defaultResponse; + target.responseMap.putAll(responseMap); } protected void initGlobalDefaultMapper() { if (GLOBAL_DEFAULT_MAPPER != null) { - Map<Integer, ResponseMeta> mappers = GLOBAL_DEFAULT_MAPPER.getMapper(); + Map<Integer, JavaType> mappers = GLOBAL_DEFAULT_MAPPER.getMapper(); if (mappers != null) { responseMap.putAll(mappers); } } } - public ResponseMeta findResponseMeta(int statusCode) { - ResponseMeta responseMeta = responseMap.get(statusCode); - if (responseMeta == null) { + public Map<Integer, JavaType> getResponseMap() { + return responseMap; + } + + public JavaType findResponseType(int statusCode) { + JavaType responseType = responseMap.get(statusCode); + if (responseType == null) { if (HttpStatus.isSuccess(statusCode)) { return responseMap.get(Status.OK.getStatusCode()); } @@ -110,6 +132,6 @@ public class ResponsesMeta { return defaultResponse; } - return responseMeta; + return responseType; } } diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/TestResponseMapperFactorys.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/TestResponseMapperFactorys.java deleted file mode 100644 index bd6f61d..0000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/TestResponseMapperFactorys.java +++ /dev/null @@ -1,89 +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.apache.servicecomb.swagger.invocation.response; - -import java.util.List; - -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.converter.Converter; -import org.apache.servicecomb.swagger.invocation.converter.ConverterMgr; -import org.apache.servicecomb.swagger.invocation.converter.impl.ConverterSame; -import org.apache.servicecomb.swagger.invocation.response.consumer.CompletableFutureConsumerResponseMapperFactory; -import org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapper; -import org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapperFactory; -import org.apache.servicecomb.swagger.invocation.response.consumer.CseResponseConsumerResponseMapperFactory; -import org.apache.servicecomb.swagger.invocation.response.consumer.DefaultConsumerResponseMapper; -import org.apache.servicecomb.swagger.invocation.response.consumer.DefaultConsumerResponseMapperFactory; -import org.apache.servicecomb.swagger.invocation.response.consumer.OptionalConsumerResponseMapperFactory; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import mockit.Deencapsulation; - -public class TestResponseMapperFactorys { - ResponseMapperFactorys<ConsumerResponseMapper> consumerResponseMapperFactorys = - new ResponseMapperFactorys<>(ConsumerResponseMapperFactory.class); - - List<ResponseMapperFactory<ConsumerResponseMapper>> factorys = - Deencapsulation.getField(consumerResponseMapperFactorys, "factorys"); - - ConverterMgr converterMgr = new ConverterMgr(); - - @Before - public void setup() { - consumerResponseMapperFactorys.setConverterMgr(converterMgr); - } - - @SuppressWarnings("unchecked") - @Test - public void construct() { - Assert.assertThat(factorys, - Matchers.containsInAnyOrder(Matchers.instanceOf(CseResponseConsumerResponseMapperFactory.class), - Matchers.instanceOf(CompletableFutureConsumerResponseMapperFactory.class), - Matchers.instanceOf(DefaultConsumerResponseMapperFactory.class), - Matchers.instanceOf(OptionalConsumerResponseMapperFactory.class))); - } - - @Test - public void setConverterMgr() { - DefaultConsumerResponseMapperFactory mapper = (DefaultConsumerResponseMapperFactory) factorys.stream() - .filter(m -> m instanceof DefaultConsumerResponseMapperFactory) - .findFirst() - .get(); - Assert.assertSame(converterMgr, Deencapsulation.getField(mapper, "converterMgr")); - } - - @Test - public void createResponseMapper_default() { - ConsumerResponseMapper mapper = consumerResponseMapperFactorys.createResponseMapper(String.class, String.class); - Assert.assertThat(mapper, Matchers.instanceOf(DefaultConsumerResponseMapper.class)); - - Converter converter = Deencapsulation.getField(mapper, "converter"); - Assert.assertSame(ConverterSame.getInstance(), converter); - } - - @Test - public void createResponseMapper_cseResponse() { - ConsumerResponseMapper mapper = consumerResponseMapperFactorys.createResponseMapper(String.class, Response.class); - - Response response = Response.ok(null); - Object result = mapper.mapResponse(response); - Assert.assertSame(response, result); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/TestResponsesMeta.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/TestResponsesMeta.java index f6077ce..219bb0c 100644 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/TestResponsesMeta.java +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/TestResponsesMeta.java @@ -16,12 +16,12 @@ */ package org.apache.servicecomb.swagger.invocation.response; -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.apache.servicecomb.swagger.generator.core.unittest.UnitTestSwaggerUtils; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; import org.junit.Assert; import org.junit.Test; +import com.fasterxml.jackson.databind.JavaType; + import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; import io.swagger.annotations.ResponseHeader; @@ -44,33 +44,26 @@ public class TestResponsesMeta { @Test public void test() { - SwaggerGenerator generator = UnitTestSwaggerUtils.generateSwagger(ResponseMetaImpl.class); - Swagger swagger = generator.getSwagger(); + Swagger swagger = SwaggerGenerator.generate(ResponseMetaImpl.class); Operation operation = swagger.getPath("/add").getPost(); - SwaggerToClassGenerator swaggerToClassGenerator = new SwaggerToClassGenerator(new ClassLoader() { - }, swagger, "ms.sid"); ResponsesMeta meta = new ResponsesMeta(); - meta.init(swaggerToClassGenerator, operation, int.class); + meta.init(swagger, operation); - ResponseMeta resp = meta.findResponseMeta(200); - // Response currently is based on return type not swagger type - Assert.assertEquals(int.class, resp.getJavaType().getRawClass()); + JavaType resp = meta.findResponseType(200); + Assert.assertEquals(Integer.class, resp.getRawClass()); - resp = meta.findResponseMeta(201); - // Response currently is based on return type not swagger type. For this test case there is one problem need to discuss. - // If SUCCESS family, do we should use OK response type? - Assert.assertEquals(int.class, resp.getJavaType().getRawClass()); + resp = meta.findResponseType(201); + Assert.assertEquals(Integer.class, resp.getRawClass()); - resp = meta.findResponseMeta(400); - Assert.assertEquals(String.class, resp.getJavaType().getRawClass()); + resp = meta.findResponseType(400); + Assert.assertEquals(String.class, resp.getRawClass()); - resp = meta.findResponseMeta(401); - Assert.assertEquals(Long.class, resp.getJavaType().getRawClass()); - Assert.assertEquals(Integer.class, resp.getHeaders().get("h1").getRawClass()); + resp = meta.findResponseType(401); + Assert.assertEquals(Long.class, resp.getRawClass()); - resp = meta.findResponseMeta(500); + resp = meta.findResponseType(500); // changed to Object for new version to keep user defined error data not lose and can be parsed. - Assert.assertEquals(Object.class, resp.getJavaType().getRawClass()); + Assert.assertEquals(Object.class, resp.getRawClass()); } }
