liubao68 closed pull request #911: [SCB-215] Process @ApiParam URL: https://github.com/apache/incubator-servicecomb-java-chassis/pull/911
This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): diff --git a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/CommonModel.java b/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/CommonModel.java new file mode 100644 index 000000000..1dcebb005 --- /dev/null +++ b/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/CommonModel.java @@ -0,0 +1,29 @@ +/* + * 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.it.schema; + +public class CommonModel { + private int iValue; + + public int getiValue() { + return iValue; + } + + public void setiValue(int iValue) { + this.iValue = iValue; + } +} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/ConsumerMain.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/ConsumerMain.java index 22113d401..23ede5f01 100644 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/ConsumerMain.java +++ b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/ConsumerMain.java @@ -21,6 +21,7 @@ import org.apache.servicecomb.it.deploy.Deploys; import org.apache.servicecomb.it.junit.ITJUnitUtils; import org.apache.servicecomb.it.testcase.TestAnnotatedAttribute; +import org.apache.servicecomb.it.testcase.TestApiParam; import org.apache.servicecomb.it.testcase.TestChangeTransport; import org.apache.servicecomb.it.testcase.TestDataTypePrimitive; import org.apache.servicecomb.it.testcase.TestDefaultJsonValueJaxrsSchema; @@ -66,6 +67,7 @@ protected static void run() throws Throwable { // deploys.getZuul().ensureReady(zuul); ITJUnitUtils.run(TestIgnoreMethod.class); + ITJUnitUtils.run(TestApiParam.class); // 1.base test case // include all extension point abnormal scenes test case diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiParamJaxrsSchema.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiParamJaxrsSchema.java new file mode 100644 index 000000000..f5b814330 --- /dev/null +++ b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiParamJaxrsSchema.java @@ -0,0 +1,62 @@ +/* + * 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.it.schema; + +import javax.ws.rs.CookieParam; +import javax.ws.rs.FormParam; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.QueryParam; + +import org.apache.servicecomb.provider.rest.common.RestSchema; + +import io.swagger.annotations.ApiParam; + +@RestSchema(schemaId = "apiParamJaxrs") +@Path("/apiParamJaxrs") +public class ApiParamJaxrsSchema { + @POST + @Path("/body") + public void body(@ApiParam(value = "desc of body param") CommonModel model) { + + } + + @POST + @Path("/query") + public void query(@ApiParam(value = "desc of query param") @QueryParam("input") int input) { + + } + + @POST + @Path("/header") + public void header(@ApiParam(value = "desc of header param") @HeaderParam("input") int input) { + + } + + @POST + @Path("/cookie") + public void cookie(@ApiParam(value = "desc of cookie param") @CookieParam("input") int input) { + + } + + @POST + @Path("/form") + public void form(@ApiParam(value = "desc of form param") @FormParam("input") int input) { + + } +} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiParamPojoSchema.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiParamPojoSchema.java new file mode 100644 index 000000000..1673ba858 --- /dev/null +++ b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiParamPojoSchema.java @@ -0,0 +1,34 @@ +/* + * 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.it.schema; + +import org.apache.servicecomb.provider.pojo.RpcSchema; + +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.SwaggerDefinition; + +@RpcSchema(schemaId = "apiParamPojo") +@SwaggerDefinition(basePath = "/apiParamPojo") +public class ApiParamPojoSchema { + public void model(@ApiParam(value = "desc of model param") CommonModel model) { + + } + + public void simple(@ApiParam(value = "desc of simple param") int input) { + + } +} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiParamSpringmvcSchema.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiParamSpringmvcSchema.java new file mode 100644 index 000000000..b291692bf --- /dev/null +++ b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiParamSpringmvcSchema.java @@ -0,0 +1,69 @@ +/* + * 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.it.schema; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.CookieValue; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; + +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.Example; +import io.swagger.annotations.ExampleProperty; + +@RestSchema(schemaId = "apiParamSpringmvc") +@RequestMapping(path = "/apiParamSpringmvc") +public class ApiParamSpringmvcSchema { + @PostMapping(path = "/body") + public void body(@ApiParam(value = "desc of body param", + required = true, + name = "modelEx", + examples = @Example(value = { + @ExampleProperty(mediaType = "k1", value = "v1"), + @ExampleProperty(mediaType = "k2", value = "v2")})) @RequestBody CommonModel model) { + + } + + @PostMapping(path = "/query") + public void query(@ApiParam(value = "desc of query param", + required = true, + readOnly = true, + allowEmptyValue = true, + name = "inputEx", + example = "example", + collectionFormat = "fmt") int input) { + + } + + @PostMapping(path = "/header") + public void header(@ApiParam(value = "desc of header param") @RequestHeader("input") int input) { + + } + + @PostMapping(path = "/cookie") + public void cookie(@ApiParam(value = "desc of cookie param") @CookieValue("input") int input) { + + } + + @PostMapping(path = "/form") + public void form(@ApiParam(value = "desc of form param") @RequestAttribute("input") int input) { + + } +} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestApiParam.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestApiParam.java new file mode 100644 index 000000000..317874246 --- /dev/null +++ b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestApiParam.java @@ -0,0 +1,118 @@ +/* + * 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.it.testcase; + +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.core.definition.SchemaMeta; +import org.junit.Assert; +import org.junit.Test; + +import io.swagger.models.parameters.BodyParameter; +import io.swagger.models.parameters.Parameter; +import io.swagger.models.parameters.QueryParameter; + +public class TestApiParam { + MicroserviceMeta microserviceMeta = SCBEngine.getInstance().getProducerMicroserviceMeta(); + + Parameter parameter; + + protected void check(String schemaId, String opName) { + check(schemaId, opName, opName); + } + + protected void check(String schemaId, String opName, String paramType) { + SchemaMeta schemaMeta = microserviceMeta.findSchemaMeta(schemaId); + OperationMeta operationMeta = schemaMeta.findOperation(opName); + parameter = operationMeta.getSwaggerOperation().getParameters().get(0); + Assert.assertEquals("desc of " + opName + " param", parameter.getDescription()); + Assert.assertEquals(paramType, parameter.getIn()); + } + + @Test + public void pojoModel() { + check("apiParamPojo", "model", "body"); + } + + @Test + public void pojoSimple() { + check("apiParamPojo", "simple", "body"); + } + + @Test + public void jaxrsBody() { + check("apiParamJaxrs", "body"); + } + + @Test + public void jaxrsQuery() { + check("apiParamJaxrs", "query"); + } + + @Test + public void jaxrsHeader() { + check("apiParamJaxrs", "header"); + } + + @Test + public void jaxrsCookie() { + check("apiParamJaxrs", "cookie"); + } + + @Test + public void jaxrsForm() { + check("apiParamJaxrs", "form", "formData"); + } + + @Test + public void springmvcBody() { + check("apiParamSpringmvc", "body"); + + Assert.assertTrue(parameter.getRequired()); + Assert.assertEquals("modelEx", parameter.getName()); + Assert.assertEquals("v1", ((BodyParameter) parameter).getExamples().get("k1")); + Assert.assertEquals("v2", ((BodyParameter) parameter).getExamples().get("k2")); + } + + @Test + public void springmvcQuery() { + check("apiParamSpringmvc", "query"); + + Assert.assertTrue(parameter.getRequired()); + Assert.assertTrue(parameter.isReadOnly()); + Assert.assertTrue(parameter.getAllowEmptyValue()); + Assert.assertEquals("inputEx", parameter.getName()); + Assert.assertEquals("example", ((QueryParameter) parameter).getExample()); + Assert.assertEquals("fmt", ((QueryParameter) parameter).getCollectionFormat()); + } + + @Test + public void springmvcHeader() { + check("apiParamSpringmvc", "header"); + } + + @Test + public void springmvcCookie() { + check("apiParamSpringmvc", "cookie"); + } + + @Test + public void springmvcForm() { + check("apiParamSpringmvc", "form", "formData"); + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/OperationGenerator.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/OperationGenerator.java index 560e3aa34..8c9a83429 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/OperationGenerator.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/OperationGenerator.java @@ -31,6 +31,7 @@ import org.apache.servicecomb.swagger.SwaggerUtils; import org.apache.servicecomb.swagger.extend.parameter.ContextParameter; +import org.apache.servicecomb.swagger.generator.core.processor.annotation.AnnotationUtils; import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -292,6 +293,11 @@ protected void scanMethodParameters() { // 没有用于描述契约的标注,根据函数原型来反射生成 context.getDefaultParamProcessor().process(this, paramIdx); } + + if (!isArgumentNotProcessed(swaggerParamCount)) { + Parameter parameter = providerParameters.get(this.providerParameters.size() - 1); + AnnotationUtils.processApiParam(paramAnnotations, parameter); + } } } diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/AnnotationUtils.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/AnnotationUtils.java index def34bfcb..aebca2b29 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/AnnotationUtils.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/AnnotationUtils.java @@ -17,6 +17,7 @@ package org.apache.servicecomb.swagger.generator.core.processor.annotation; +import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.util.Arrays; import java.util.HashMap; @@ -24,21 +25,25 @@ import java.util.List; import java.util.Map; +import org.apache.commons.lang3.StringUtils; import org.apache.servicecomb.swagger.generator.core.processor.annotation.models.ResponseConfig; import org.apache.servicecomb.swagger.generator.core.processor.annotation.models.ResponseConfigBase; import org.apache.servicecomb.swagger.generator.core.processor.annotation.models.ResponseHeaderConfig; import org.springframework.util.ClassUtils; -import org.springframework.util.StringUtils; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.Example; +import io.swagger.annotations.ExampleProperty; import io.swagger.annotations.ResponseHeader; import io.swagger.converter.ModelConverters; import io.swagger.models.Model; import io.swagger.models.Operation; import io.swagger.models.Response; import io.swagger.models.Swagger; +import io.swagger.models.parameters.AbstractSerializableParameter; import io.swagger.models.parameters.BodyParameter; import io.swagger.models.parameters.CookieParameter; import io.swagger.models.parameters.FormParameter; @@ -47,6 +52,8 @@ import io.swagger.models.parameters.PathParameter; import io.swagger.models.parameters.QueryParameter; import io.swagger.models.properties.ArrayProperty; +import io.swagger.models.properties.FileProperty; +import io.swagger.models.properties.LongProperty; import io.swagger.models.properties.MapProperty; import io.swagger.models.properties.Property; import io.swagger.util.ParameterProcessor; @@ -218,4 +225,91 @@ private static Parameter createParameterInstance(ApiImplicitParam paramAnnotatio throw new Error("not support paramType " + paramAnnotation.paramType()); } } + + @SuppressWarnings("unchecked") + public static <T> T findAnnotation(Annotation[] annotations, Class<T> annotationType) { + for (Annotation annotation : annotations) { + if (annotation.annotationType().equals(annotationType)) { + return (T) annotation; + } + } + + return null; + } + + public static void processApiParam(Annotation[] paramAnnotations, Parameter parameter) { + ApiParam param = findAnnotation(paramAnnotations, ApiParam.class); + if (param == null) { + return; + } + + if (parameter instanceof AbstractSerializableParameter) { + processApiParam(param, (AbstractSerializableParameter<?>) parameter); + return; + } + + processApiParam(param, (BodyParameter) parameter); + } + + protected static void processApiParam(ApiParam param, BodyParameter p) { + if (param.required()) { + p.setRequired(true); + } + if (StringUtils.isNotEmpty(param.name())) { + p.setName(param.name()); + } + if (StringUtils.isNotEmpty(param.value())) { + p.setDescription(param.value()); + } + if (StringUtils.isNotEmpty(param.access())) { + p.setAccess(param.access()); + } + + Example example = param.examples(); + if (example != null && example.value() != null) { + for (ExampleProperty ex : example.value()) { + String mediaType = ex.mediaType(); + String value = ex.value(); + if (!mediaType.isEmpty() && !value.isEmpty()) { + p.example(mediaType.trim(), value.trim()); + } + } + } + } + + protected static void processApiParam(ApiParam param, AbstractSerializableParameter<?> p) { + if (param.required()) { + p.setRequired(true); + } + if (param.readOnly()) { + p.setReadOnly(true); + } + if (param.allowEmptyValue()) { + p.setAllowEmptyValue(true); + } + if (StringUtils.isNotEmpty(param.name())) { + p.setName(param.name()); + } + if (StringUtils.isNotEmpty(param.value())) { + p.setDescription(param.value()); + } + if (StringUtils.isNotEmpty(param.example())) { + p.setExample(param.example()); + } + if (StringUtils.isNotEmpty(param.access())) { + p.setAccess(param.access()); + } + if (StringUtils.isNoneEmpty(param.collectionFormat())) { + p.setCollectionFormat(param.collectionFormat()); + } + if (StringUtils.isNotEmpty(param.type())) { + if ("java.io.File".equalsIgnoreCase(param.type())) { + p.setProperty(new FileProperty()); + } else if ("long".equalsIgnoreCase(param.type())) { + p.setProperty(new LongProperty()); + } else { + p.setType(param.type()); + } + } + } } diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/extend/parameter/PendingBodyParameter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/extend/parameter/PendingBodyParameter.java index 487b574ec..065b6122d 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/extend/parameter/PendingBodyParameter.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/extend/parameter/PendingBodyParameter.java @@ -17,18 +17,22 @@ package org.apache.servicecomb.swagger.generator.pojo.extend.parameter; +import java.io.IOException; import java.lang.reflect.Method; import java.lang.reflect.Type; import org.apache.servicecomb.swagger.generator.core.OperationGenerator; import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils; +import com.fasterxml.jackson.annotation.JsonIgnore; + import io.swagger.models.ModelImpl; import io.swagger.models.RefModel; import io.swagger.models.parameters.BodyParameter; import io.swagger.models.properties.Property; import io.swagger.models.properties.PropertyBuilder; import io.swagger.models.properties.RefProperty; +import io.swagger.util.Json; // // 备选body @@ -39,10 +43,13 @@ // jaxrs、springmvc这种模式,要求符合模式本身的定义场景,不允许随意组合 // public class PendingBodyParameter extends BodyParameter { + @JsonIgnore private OperationGenerator operationGenerator; + @JsonIgnore private Property property; + @JsonIgnore private Type type; public void setOperationGenerator(OperationGenerator operationGenerator) { @@ -65,6 +72,7 @@ public void setType(Type type) { this.type = type; } + @JsonIgnore public Method getMethod() { return operationGenerator.getProviderMethod(); } @@ -73,11 +81,14 @@ public BodyParameter createBodyParameter(String paramName) { String modelType = ParamUtils.generateBodyParameterName(operationGenerator.getProviderMethod()); RefModel model = toRefModel(modelType); - BodyParameter bodyParameter = new BodyParameter(); - bodyParameter.setName(paramName); - bodyParameter.setSchema(model); + setName(paramName); + setSchema(model); - return bodyParameter; + try { + return Json.mapper().readValue(Json.mapper().writeValueAsString(this), BodyParameter.class); + } catch (IOException e) { + throw new IllegalStateException("failed to createBodyParameter.", e); + } } // swagger中的body只能是ref,不能是简单类型 ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: [email protected] With regards, Apache Git Services
