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 2018/08/29 02:56:27 UTC

[incubator-servicecomb-java-chassis] 01/03: [SCB-206] Support setting produces and consumes by @Api

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/incubator-servicecomb-java-chassis.git

commit 0cd340c535ece1cb82252367651b3b23df7457db
Author: yaohaishi <ya...@huawei.com>
AuthorDate: Wed Aug 22 15:54:38 2018 +0800

    [SCB-206] Support setting produces and consumes by @Api
---
 .../core/processor/annotation/ApiProcessor.java    | 51 +++++++++++
 .../processor/annotation/ApiProcessorTest.java     | 64 +++++++++++++-
 ...RequestMappingClassAnnotationProcessorTest.java | 98 ++++++++++++++++++++++
 3 files changed, 209 insertions(+), 4 deletions(-)

diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiProcessor.java
index 57b4dbf..f882e34 100644
--- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiProcessor.java
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiProcessor.java
@@ -17,11 +17,16 @@
 
 package org.apache.servicecomb.swagger.generator.core.processor.annotation;
 
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
 import org.apache.servicecomb.swagger.generator.core.ClassAnnotationProcessor;
 import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator;
 import org.springframework.util.StringUtils;
 
 import io.swagger.annotations.Api;
+import io.swagger.models.Swagger;
 
 public class ApiProcessor implements ClassAnnotationProcessor {
   @Override
@@ -29,6 +34,52 @@ public class ApiProcessor implements ClassAnnotationProcessor {
     Api api = (Api) annotation;
 
     setTags(api, swaggerGenerator);
+    // except for @Api, @RequestMapping can also set consumes and produces
+    // @RequestMapping takes HIGHER priority than @Api for legacy reason
+    processConsumes(api, swaggerGenerator.getSwagger());
+    processProduces(api, swaggerGenerator.getSwagger());
+  }
+
+  private void processProduces(Api api, Swagger swagger) {
+    List<String> validProducesList = getValidStringList(api.produces());
+    if (isBlank(swagger.getProduces()) && !validProducesList.isEmpty()) {
+      swagger.setProduces(validProducesList);
+    }
+  }
+
+  private void processConsumes(Api api, Swagger swagger) {
+    List<String> validConsumesList = getValidStringList(api.consumes());
+    if (isBlank(swagger.getConsumes()) && !validConsumesList.isEmpty()) {
+      swagger.setConsumes(validConsumesList);
+    }
+  }
+
+  /**
+   * Split {@link Api#consumes} and {@link Api#produces}, and filter empty items.
+   */
+  private List<String> getValidStringList(String rawString) {
+    return Stream.of(rawString.split(","))
+        .filter(s -> !StringUtils.isEmpty(s))
+        .map(String::trim)
+        .collect(Collectors.toList());
+  }
+
+  /**
+   * @return true if {@code stringList} is empty or each element of {@code stringList} is empty;
+   * otherwise false.
+   */
+  private boolean isBlank(List<String> stringList) {
+    boolean isEmpty = null == stringList || stringList.isEmpty();
+    if (isEmpty) {
+      return true;
+    }
+
+    for (String s : stringList) {
+      if (StringUtils.isEmpty(s)) {
+        return true;
+      }
+    }
+    return false;
   }
 
   private void setTags(Api api, SwaggerGenerator swaggerGenerator) {
diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiProcessorTest.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiProcessorTest.java
index 62f5a3e..047daac 100644
--- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiProcessorTest.java
+++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiProcessorTest.java
@@ -19,12 +19,19 @@ package org.apache.servicecomb.swagger.generator.core.processor.annotation;
 
 import static org.hamcrest.Matchers.contains;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertThat;
 
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 import java.util.Set;
 
+import javax.ws.rs.core.MediaType;
+
 import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator;
 import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext;
+import org.hamcrest.Matchers;
 import org.junit.Test;
 import org.mockito.Mockito;
 
@@ -35,22 +42,66 @@ public class ApiProcessorTest {
 
   @Test
   public void process() {
-    SwaggerGenerator swaggerGenerator = new SwaggerGenerator(Mockito.mock(SwaggerGeneratorContext.class),
-        null);
+    SwaggerGenerator swaggerGenerator = getSwaggerGenerator();
     apiProcessor.process(SwaggerTestTarget.class.getAnnotation(Api.class),
         swaggerGenerator);
 
     assertThat(swaggerGenerator.getDefaultTags(), contains("tag1", "tag2"));
+    assertNull(swaggerGenerator.getSwagger().getConsumes());
+    assertNull(swaggerGenerator.getSwagger().getProduces());
   }
 
   @Test
   public void processOnNoTag() {
-    SwaggerGenerator swaggerGenerator = new SwaggerGenerator(Mockito.mock(SwaggerGeneratorContext.class),
-        null);
+    SwaggerGenerator swaggerGenerator = getSwaggerGenerator();
     apiProcessor.process(SwaggerTestTargetWithNoTag.class.getAnnotation(Api.class), swaggerGenerator);
 
     Set<String> tags = swaggerGenerator.getDefaultTags();
     assertEquals(0, tags.size());
+    assertNull(swaggerGenerator.getSwagger().getConsumes());
+    assertNull(swaggerGenerator.getSwagger().getProduces());
+  }
+
+  @Test
+  public void processOverWriteEmptyConsumesAndProduces() {
+    SwaggerGenerator swaggerGenerator = getSwaggerGenerator();
+    swaggerGenerator.getSwagger().setConsumes(Arrays.asList("", "  "));
+    swaggerGenerator.getSwagger().setProduces(Arrays.asList("", "  "));
+    apiProcessor.process(SwaggerTestTargetWithConsumesAndProduces.class.getAnnotation(Api.class), swaggerGenerator);
+
+    List<String> consumes = swaggerGenerator.getSwagger().getConsumes();
+    assertThat(consumes, Matchers.contains(MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON));
+    List<String> produces = swaggerGenerator.getSwagger().getProduces();
+    assertThat(produces, Matchers.contains(MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON));
+  }
+
+  @Test
+  public void processNotOverWriteValidConsumesAndProduces() {
+    SwaggerGenerator swaggerGenerator = getSwaggerGenerator();
+    swaggerGenerator.getSwagger().setConsumes(Collections.singletonList(MediaType.MULTIPART_FORM_DATA));
+    swaggerGenerator.getSwagger().setProduces(Collections.singletonList(MediaType.MULTIPART_FORM_DATA));
+    apiProcessor.process(SwaggerTestTargetWithConsumesAndProduces.class.getAnnotation(Api.class), swaggerGenerator);
+
+    List<String> consumes = swaggerGenerator.getSwagger().getConsumes();
+    assertThat(consumes, Matchers.contains(MediaType.MULTIPART_FORM_DATA));
+    List<String> produces = swaggerGenerator.getSwagger().getProduces();
+    assertThat(produces, Matchers.contains(MediaType.MULTIPART_FORM_DATA));
+  }
+
+  @Test
+  public void processWithConsumesAndProduces() {
+    SwaggerGenerator swaggerGenerator = getSwaggerGenerator();
+    apiProcessor.process(SwaggerTestTargetWithConsumesAndProduces.class.getAnnotation(Api.class), swaggerGenerator);
+
+    List<String> consumes = swaggerGenerator.getSwagger().getConsumes();
+    assertThat(consumes, Matchers.contains(MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON));
+    List<String> produces = swaggerGenerator.getSwagger().getProduces();
+    assertThat(produces, Matchers.contains(MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON));
+  }
+
+  private SwaggerGenerator getSwaggerGenerator() {
+    return new SwaggerGenerator(Mockito.mock(SwaggerGeneratorContext.class),
+        null);
   }
 
   @Api(tags = {"tag1", "tag2", "", "tag1"})
@@ -60,4 +111,9 @@ public class ApiProcessorTest {
   @Api
   private class SwaggerTestTargetWithNoTag {
   }
+
+  @Api(consumes = MediaType.TEXT_PLAIN + " , " + MediaType.APPLICATION_JSON,
+      produces = MediaType.APPLICATION_XML + "," + MediaType.APPLICATION_JSON)
+  private class SwaggerTestTargetWithConsumesAndProduces {
+  }
 }
diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestMappingClassAnnotationProcessorTest.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestMappingClassAnnotationProcessorTest.java
new file mode 100644
index 0000000..35d829a
--- /dev/null
+++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestMappingClassAnnotationProcessorTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.generator.springmvc.processor.annotation;
+
+import javax.ws.rs.core.MediaType;
+
+import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator;
+import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext;
+import org.hamcrest.Matchers;
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import io.swagger.annotations.Api;
+import mockit.Mock;
+import mockit.MockUp;
+
+public class RequestMappingClassAnnotationProcessorTest {
+
+  private RequestMappingClassAnnotationProcessor processor = new RequestMappingClassAnnotationProcessor();
+
+  @Test
+  public void process() {
+    SwaggerGenerator swaggerGenerator = getSwaggerGenerator();
+    processor.process(SwaggerTestTarget.class.getAnnotation(RequestMapping.class), swaggerGenerator);
+
+    Assert.assertEquals("/test", swaggerGenerator.getSwagger().getBasePath());
+    Assert.assertEquals("post", swaggerGenerator.getHttpMethod());
+    Assert.assertThat(swaggerGenerator.getSwagger().getConsumes(),
+        Matchers.contains(MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON));
+    Assert.assertThat(swaggerGenerator.getSwagger().getProduces(),
+        Matchers.contains(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN));
+  }
+
+  /**
+   * {@link RequestMapping#value()} takes higher priority than {@link RequestMapping#path()}
+   */
+  @Test
+  public void process_ValueOverWritePath() {
+    SwaggerGenerator swaggerGenerator = getSwaggerGenerator();
+    processor.process(SwaggerTestTarget_ValueOverWritePath.class.getAnnotation(RequestMapping.class), swaggerGenerator);
+
+    Assert.assertEquals("/testValue", swaggerGenerator.getSwagger().getBasePath());
+  }
+
+  /**
+   * {@link RequestMapping} takes higher priority than {@link Api} on setting {@code consumes} and {@code produces}
+   */
+  @Test
+  public void process_OverWriteConsumesAndProduces() {
+    SwaggerGenerator swaggerGenerator = getSwaggerGenerator();
+    swaggerGenerator.getSwagger().addConsumes(MediaType.APPLICATION_XML);
+    swaggerGenerator.getSwagger().addProduces(MediaType.APPLICATION_XML);
+    processor.process(SwaggerTestTarget.class.getAnnotation(RequestMapping.class), swaggerGenerator);
+
+    Assert.assertThat(swaggerGenerator.getSwagger().getConsumes(),
+        Matchers.contains(MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON));
+    Assert.assertThat(swaggerGenerator.getSwagger().getProduces(),
+        Matchers.contains(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN));
+  }
+
+  private SwaggerGenerator getSwaggerGenerator() {
+    SwaggerGeneratorContext swaggerGeneratorContext = new MockUp<SwaggerGeneratorContext>() {
+      @Mock
+      String resolveStringValue(String strVal) {
+        return strVal;
+      }
+    }.getMockInstance();
+
+    return new SwaggerGenerator(swaggerGeneratorContext, null);
+  }
+
+  @RequestMapping(path = "/test", method = RequestMethod.POST,
+      consumes = {MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON},
+      produces = {MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN})
+  private class SwaggerTestTarget {
+  }
+
+  @RequestMapping(value = "/testValue", path = "/testPath")
+  private class SwaggerTestTarget_ValueOverWritePath {
+  }
+}