You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by zr...@apache.org on 2018/04/05 11:42:11 UTC

[camel] 02/02: CAMEL-12420: Swagger enums for array types

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

zregvart pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 6c260ab0510ab3485c6d8e68b56a6b75b1ff27e8
Author: Zoran Regvart <zr...@apache.org>
AuthorDate: Thu Apr 5 13:24:04 2018 +0200

    CAMEL-12420: Swagger enums for array types
    
    When specifying the parameter of an `array` type, the `enum` property
    needs to be set on the `items` property. So instead of:
    
    ```json
    {
      "name": "...",
      "type": "array",
      "items": {
        "type": "..."
      },
      "enum": [...]
    
    ```
    
    We should define as:
    
    ```json
    {
      "name": "...",
      "type": "array",
      "items": {
        "type": "...",
        "enum": [...]
      }
    
    ```
---
 components/camel-swagger-java/pom.xml              |   6 ++
 .../apache/camel/swagger/RestSwaggerReader.java    |  64 ++++++++++--
 .../org/apache/camel/swagger/ParameterAssert.java  | 114 +++++++++++++++++++++
 .../camel/swagger/RestSwaggerArrayEnumTest.java    |  91 ++++++++++++++++
 4 files changed, 266 insertions(+), 9 deletions(-)

diff --git a/components/camel-swagger-java/pom.xml b/components/camel-swagger-java/pom.xml
index 4437637..98454f5 100644
--- a/components/camel-swagger-java/pom.xml
+++ b/components/camel-swagger-java/pom.xml
@@ -154,6 +154,12 @@
       <artifactId>log4j-slf4j-impl</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.assertj</groupId>
+      <artifactId>assertj-core</artifactId>
+      <version>${assertj-version}</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
 </project>
diff --git a/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerReader.java b/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerReader.java
index 0cabb1c..b7aa89e 100644
--- a/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerReader.java
+++ b/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerReader.java
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.swagger;
 
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodType;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -25,6 +27,9 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
+import java.util.stream.Collectors;
+
+import static java.lang.invoke.MethodHandles.publicLookup;
 
 import io.swagger.jaxrs.config.BeanConfig;
 import io.swagger.models.ArrayModel;
@@ -260,30 +265,33 @@ public class RestSwaggerReader {
                     if (parameter instanceof SerializableParameter) {
                         SerializableParameter serializableParameter = (SerializableParameter) parameter;
 
+                        final boolean isArray = param.getDataType().equalsIgnoreCase("array");
+                        final List<String> allowableValues = param.getAllowableValues();
+                        final boolean hasAllowableValues = allowableValues != null && !allowableValues.isEmpty();
                         if (param.getDataType() != null) {
                             serializableParameter.setType(param.getDataType());
                             if (param.getDataFormat() != null) {
                                 serializableParameter.setFormat(param.getDataFormat());
                             }
-                            if (param.getDataType().equalsIgnoreCase("array")) {
+                            if (isArray) {
                                 if (param.getArrayType() != null) {
                                     if (param.getArrayType().equalsIgnoreCase("string")) {
-                                        serializableParameter.setItems(new StringProperty());
+                                        defineItems(serializableParameter, allowableValues, new StringProperty(), String.class);
                                     }
                                     if (param.getArrayType().equalsIgnoreCase("int") || param.getArrayType().equalsIgnoreCase("integer")) {
-                                        serializableParameter.setItems(new IntegerProperty());
+                                        defineItems(serializableParameter, allowableValues, new IntegerProperty(), Integer.class);
                                     }
                                     if (param.getArrayType().equalsIgnoreCase("long")) {
-                                        serializableParameter.setItems(new LongProperty());
+                                        defineItems(serializableParameter, allowableValues, new LongProperty(), Long.class);
                                     }
                                     if (param.getArrayType().equalsIgnoreCase("float")) {
-                                        serializableParameter.setItems(new FloatProperty());
+                                        defineItems(serializableParameter, allowableValues, new FloatProperty(), Float.class);
                                     }
                                     if (param.getArrayType().equalsIgnoreCase("double")) {
-                                        serializableParameter.setItems(new DoubleProperty());
+                                        defineItems(serializableParameter, allowableValues, new DoubleProperty(), Double.class);
                                     }
                                     if (param.getArrayType().equalsIgnoreCase("boolean")) {
-                                        serializableParameter.setItems(new BooleanProperty());
+                                        defineItems(serializableParameter, allowableValues, new BooleanProperty(), Boolean.class);
                                     }
                                 }
                             }
@@ -291,8 +299,8 @@ public class RestSwaggerReader {
                         if (param.getCollectionFormat() != null) {
                             serializableParameter.setCollectionFormat(param.getCollectionFormat().name());
                         }
-                        if (param.getAllowableValues() != null && !param.getAllowableValues().isEmpty()) {
-                            serializableParameter.setEnum(param.getAllowableValues());
+                        if (hasAllowableValues && !isArray) {
+                            serializableParameter.setEnum(allowableValues);
                         }
                     }
 
@@ -372,6 +380,44 @@ public class RestSwaggerReader {
         }
     }
 
+    private static void defineItems(final SerializableParameter serializableParameter,
+        final List<String> allowableValues, final Property items, final Class<?> type) {
+        serializableParameter.setItems(items);
+        if (allowableValues != null && !allowableValues.isEmpty()) {
+            if (String.class.equals(type)) {
+                ((StringProperty) items).setEnum(allowableValues);
+            } else {
+                convertAndSetItemsEnum(items, allowableValues, type);
+            }
+        }
+    }
+
+    private static void convertAndSetItemsEnum(final Property items, final List<String> allowableValues, final Class<?> type) {
+        try {
+            final MethodHandle valueOf = publicLookup().findStatic(type, "valueOf", MethodType.methodType(type, String.class));
+            final MethodHandle setEnum = publicLookup().bind(items, "setEnum",
+                MethodType.methodType(void.class, List.class));
+            final List<?> values = allowableValues.stream().map(v -> {
+                try {
+                    return valueOf.invoke(v);
+                } catch (Throwable e) {
+                    if (e instanceof RuntimeException) {
+                        throw (RuntimeException) e;
+                    }
+
+                    throw new IllegalStateException(e);
+                }
+            }).collect(Collectors.toList());
+            setEnum.invoke(values);
+        } catch (Throwable e) {
+            if (e instanceof RuntimeException) {
+                throw (RuntimeException) e;
+            }
+
+            throw new IllegalStateException(e);
+        }
+    }
+
     private void doParseResponseMessages(Swagger swagger, VerbDefinition verb, Operation op) {
         for (RestOperationResponseMsgDefinition msg : verb.getResponseMsgs()) {
             Response response = null;
diff --git a/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/ParameterAssert.java b/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/ParameterAssert.java
new file mode 100644
index 0000000..6c9cdb4
--- /dev/null
+++ b/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/ParameterAssert.java
@@ -0,0 +1,114 @@
+/**
+ * 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.camel.swagger;
+
+import java.lang.invoke.MethodType;
+import java.util.List;
+
+import static java.lang.invoke.MethodHandles.publicLookup;
+
+import io.swagger.models.parameters.Parameter;
+import io.swagger.models.parameters.SerializableParameter;
+import io.swagger.models.properties.Property;
+
+import org.assertj.core.api.Assertions;
+import org.assertj.core.api.ObjectAssert;
+
+public final class ParameterAssert extends ObjectAssert<Parameter> {
+
+    private ParameterAssert(final Parameter actual) {
+        super(actual);
+    }
+
+    public <T> ParameterAssert hasArrayEnumSpecifiedWith(@SuppressWarnings("unchecked") final T... values) {
+        isSerializable();
+
+        final SerializableParameter serializableParameter = (SerializableParameter) actual;
+        final Property items = serializableParameter.getItems();
+        final List<T> arrayItems = fetchEnums(items);
+        Assertions.assertThat(arrayItems).containsOnly(values);
+
+        return this;
+    }
+
+    public ParameterAssert hasEnumSpecifiedWith(final String... values) {
+        isSerializable();
+
+        final SerializableParameter serializableParameter = (SerializableParameter) actual;
+        final List<String> actualEnum = serializableParameter.getEnum();
+
+        Assertions.assertThat(actualEnum).containsOnly(values);
+
+        return this;
+    }
+
+    public ParameterAssert hasName(final String name) {
+        final String actualName = actual.getName();
+        Assertions.assertThat(actualName).as("Parameter name should equal %s, but it's %s", name, actualName);
+
+        return this;
+    }
+
+    public ParameterAssert isGivenIn(final String in) {
+        final String actualIn = actual.getIn();
+        Assertions.assertThat(actualIn).as("Parameter should be specified in %s, but it's in %s", in, actualIn)
+            .isEqualTo(in);
+
+        return this;
+    }
+
+    public ParameterAssert isOfArrayType(final String type) {
+        isSerializable();
+
+        final SerializableParameter serializableParameter = (SerializableParameter) actual;
+        final Property items = serializableParameter.getItems();
+        Assertions.assertThat(items).isNotNull();
+        final String actualArrayType = items.getType();
+        Assertions.assertThat(actualArrayType).as("Parameter array should be of %s type, but it's of %s", type,
+            actualArrayType);
+
+        return this;
+    }
+
+    public ParameterAssert isOfType(final String type) {
+        isSerializable();
+
+        final SerializableParameter serializableParameter = (SerializableParameter) actual;
+        final String actualType = serializableParameter.getType();
+        Assertions.assertThat(actualType).as("Parameter should be of %s type, but it's of %s", type, actualType);
+
+        return this;
+    }
+
+    public ParameterAssert isSerializable() {
+        isInstanceOf(SerializableParameter.class);
+
+        return this;
+    }
+
+    public static ParameterAssert assertThat(final Parameter actual) {
+        return new ParameterAssert(actual);
+    }
+
+    private static <T> List<T> fetchEnums(final Property items) {
+        try {
+            return (List<T>) publicLookup().bind(items, "getEnum", MethodType.methodType(List.class)).invoke();
+        } catch (final Throwable e) {
+            throw new AssertionError(e);
+        }
+    }
+}
\ No newline at end of file
diff --git a/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/RestSwaggerArrayEnumTest.java b/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/RestSwaggerArrayEnumTest.java
new file mode 100644
index 0000000..e3276a0
--- /dev/null
+++ b/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/RestSwaggerArrayEnumTest.java
@@ -0,0 +1,91 @@
+/**
+ * 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.camel.swagger;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import io.swagger.jaxrs.config.BeanConfig;
+import io.swagger.models.Operation;
+import io.swagger.models.Path;
+import io.swagger.models.Swagger;
+import io.swagger.models.parameters.Parameter;
+
+import org.apache.camel.impl.DefaultClassResolver;
+import org.apache.camel.model.rest.RestDefinition;
+import org.apache.camel.model.rest.RestParamType;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class RestSwaggerArrayEnumTest {
+
+    @Test
+    public void shouldGenerateEnumValuesForArraysAndNonArrays() {
+        final RestSwaggerReader reader = new RestSwaggerReader();
+
+        final RestDefinition restDefinition = new RestDefinition();
+        restDefinition.get("/operation").param().name("pathParam").type(RestParamType.path).dataType("string")
+            .allowableValues("a", "b", "c").endParam()
+
+            .param().name("queryParam").type(RestParamType.query).dataType("int").allowableValues("1", "2", "3")
+            .endParam()
+
+            .param().name("headerParam").type(RestParamType.header).dataType("float")
+            .allowableValues("1.1", "2.2", "3.3").endParam()
+
+            .param().name("pathArrayParam").type(RestParamType.path).dataType("array").arrayType("string")
+            .allowableValues("a", "b", "c").endParam()
+
+            .param().name("queryArrayParam").type(RestParamType.query).dataType("array").arrayType("int")
+            .allowableValues("1", "2", "3").endParam()
+
+            .param().name("headerArrayParam").type(RestParamType.header).dataType("array").arrayType("float")
+            .allowableValues("1.1", "2.2", "3.3").endParam();
+
+        final Swagger swagger = reader.read(Collections.singletonList(restDefinition), null, new BeanConfig(),
+            "camel-1", new DefaultClassResolver());
+
+        assertThat(swagger).isNotNull();
+        final Map<String, Path> paths = swagger.getPaths();
+        assertThat(paths).containsKey("/operation");
+        final Operation getOperation = paths.get("/operation").getGet();
+        assertThat(getOperation).isNotNull();
+        final List<Parameter> parameters = getOperation.getParameters();
+        assertThat(parameters).hasSize(6);
+
+        ParameterAssert.assertThat(parameters.get(0)).hasName("pathParam").isGivenIn("path").isOfType("string")
+            .hasEnumSpecifiedWith("a", "b", "c");
+
+        ParameterAssert.assertThat(parameters.get(1)).hasName("queryParam").isGivenIn("query").isOfType("string")
+            .hasEnumSpecifiedWith("1", "2", "3");
+
+        ParameterAssert.assertThat(parameters.get(2)).hasName("headerParam").isGivenIn("header").isOfType("string")
+            .hasEnumSpecifiedWith("1.1", "2.2", "3.3");
+
+        ParameterAssert.assertThat(parameters.get(3)).hasName("pathArrayParam").isGivenIn("path").isOfType("array")
+            .isOfArrayType("string").hasArrayEnumSpecifiedWith("a", "b", "c");
+
+        ParameterAssert.assertThat(parameters.get(4)).hasName("queryParam").isGivenIn("query").isOfType("array")
+            .isOfArrayType("int").hasArrayEnumSpecifiedWith(1, 2, 3);
+
+        ParameterAssert.assertThat(parameters.get(5)).hasName("headerParam").isGivenIn("header").isOfType("array")
+            .isOfArrayType("float").hasArrayEnumSpecifiedWith(1.1f, 2.2f, 3.3f);
+    }
+
+}

-- 
To stop receiving notification emails like this one, please contact
zregvart@apache.org.