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 <zregv...@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 zregv...@apache.org.