You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2017/11/30 15:25:46 UTC
[cxf] branch master updated: [CXF-7525] Starting with Swagger to
OpenApi JSON conversion
This is an automated email from the ASF dual-hosted git repository.
sergeyb pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cxf.git
The following commit(s) were added to refs/heads/master by this push:
new 5f35c09 [CXF-7525] Starting with Swagger to OpenApi JSON conversion
5f35c09 is described below
commit 5f35c090e1a66c9ccbbd096d8c6423a35696b5eb
Author: Sergey Beryozkin <sb...@gmail.com>
AuthorDate: Thu Nov 30 15:25:27 2017 +0000
[CXF-7525] Starting with Swagger to OpenApi JSON conversion
---
.../jaxrs/swagger/parse/SwaggerOpenApiUtils.java | 259 +++++++++++++++++++++
.../swagger/parse/SwaggerOpenApiUtilsTest.java | 139 +++++++++++
.../apache/cxf/jaxrs/json/basic/JsonMapObject.java | 29 +++
3 files changed, 427 insertions(+)
diff --git a/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/parse/SwaggerOpenApiUtils.java b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/parse/SwaggerOpenApiUtils.java
new file mode 100644
index 0000000..7c2b8c3
--- /dev/null
+++ b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/parse/SwaggerOpenApiUtils.java
@@ -0,0 +1,259 @@
+/**
+ * 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.cxf.jaxrs.swagger.parse;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.helpers.CastUtils;
+import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.jaxrs.json.basic.JsonMapObject;
+import org.apache.cxf.jaxrs.json.basic.JsonMapObjectReaderWriter;
+import org.apache.cxf.jaxrs.utils.ResourceUtils;
+
+public final class SwaggerOpenApiUtils {
+ private static final Logger LOG = LogUtils.getL7dLogger(SwaggerOpenApiUtils.class);
+ private SwaggerOpenApiUtils() {
+
+ }
+
+ public static String getOpenApiFromSwaggerLoc(String loc) {
+ return getOpenApiFromSwaggerLoc(loc, BusFactory.getThreadDefaultBus());
+ }
+ public static String getOpenApiFromSwaggerLoc(String loc, Bus bus) {
+ try {
+ InputStream is = ResourceUtils.getResourceStream(loc, bus);
+ if (is == null) {
+ return null;
+ }
+ return getOpenApiFromSwaggerStream(is);
+ } catch (Exception ex) {
+ LOG.warning("Problem with processing a user model at " + loc);
+ }
+ return null;
+ }
+
+ public static String getOpenApiFromSwaggerStream(InputStream is) throws IOException {
+ return getOpenApiFromSwaggerJson(IOUtils.readStringFromStream(is));
+ }
+
+ public static String getOpenApiFromSwaggerJson(String json) throws IOException {
+ JsonMapObjectReaderWriter readerWriter = new JsonMapObjectReaderWriter();
+ JsonMapObject sw2 = readerWriter.fromJsonToJsonObject(json);
+ JsonMapObject sw3 = new JsonMapObject();
+
+ // "openapi"
+ sw3.setProperty("openapi", "3.0.0");
+
+ // "servers"
+ setServersProperty(sw2, sw3);
+
+ // "info"
+ JsonMapObject infoObject = sw2.getJsonMapProperty("info");
+ if (infoObject != null) {
+ sw3.setProperty("info", infoObject);
+ }
+
+ // "tags"
+ List<JsonMapObject> tagsObject = sw2.getListJsonMapProperty("tags");
+ if (tagsObject != null) {
+ sw3.setProperty("tags", tagsObject);
+ }
+
+ // paths
+ setPathsProperty(sw2, sw3);
+
+ // components
+ setComponentsProperty(sw2, sw3);
+
+ // externalDocs
+ Object externalDocsObject = sw2.getProperty("externalDocs");
+ if (externalDocsObject != null) {
+ sw3.setProperty("externalDocs", externalDocsObject);
+ }
+
+ return readerWriter.toJson(sw3);
+ }
+
+ private static void setComponentsProperty(JsonMapObject sw2, JsonMapObject sw3) {
+ JsonMapObject comps = new JsonMapObject();
+ comps.setProperty("requestBodies", Collections.emptyMap());
+ Object s2Defs = sw2.getProperty("definitions");
+ if (s2Defs != null) {
+ comps.setProperty("schemas", s2Defs);
+ }
+ Object s2SecurityDefs = sw2.getProperty("securityDefinitions");
+ if (s2SecurityDefs != null) {
+ comps.setProperty("securitySchemes", s2SecurityDefs);
+ }
+
+ sw3.setProperty("components", comps);
+
+ }
+ private static void setPathsProperty(JsonMapObject sw2, JsonMapObject sw3) {
+ JsonMapObject sw2Paths = sw2.getJsonMapProperty("paths");
+ for (Map.Entry<String, Object> sw2PathEntries : sw2Paths.asMap().entrySet()) {
+ Map<String, Object> sw2PathVerbs = CastUtils.cast((Map<?, ?>)sw2PathEntries.getValue());
+ for (Map.Entry<String, Object> sw2PathVerbEntries : sw2PathVerbs.entrySet()) {
+ JsonMapObject sw2PathVerbProps =
+ new JsonMapObject(CastUtils.cast((Map<?, ?>)sw2PathVerbEntries.getValue()));
+
+ List<String> sw2PathVerbConsumes =
+ CastUtils.cast((List<?>)sw2PathVerbProps.removeProperty("consumes"));
+ List<String> sw2PathVerbProduces =
+ CastUtils.cast((List<?>)sw2PathVerbProps.removeProperty("produces"));
+
+ JsonMapObject sw3RequestBody = null;
+ List<JsonMapObject> sw2PathVerbParamsList =
+ sw2PathVerbProps.getListJsonMapProperty("parameters");
+ if (sw2PathVerbParamsList != null) {
+ for (Iterator<JsonMapObject> it = sw2PathVerbParamsList.iterator(); it.hasNext();) {
+ JsonMapObject sw2PathVerbParamMap = it.next();
+ if ("body".equals(sw2PathVerbParamMap.getStringProperty("in"))) {
+ it.remove();
+
+ sw3RequestBody = new JsonMapObject();
+ String description = sw2PathVerbParamMap.getStringProperty("description");
+ if (description != null) {
+ sw3RequestBody.setProperty("description", description);
+ }
+ Boolean required = sw2PathVerbParamMap.getBooleanProperty("required");
+ if (required != null) {
+ sw3RequestBody.setProperty("required", required);
+ }
+ JsonMapObject schema = sw2PathVerbParamMap.getJsonMapProperty("schema");
+ if (schema != null) {
+ JsonMapObject content = prepareContentFromSchema(schema, sw2PathVerbConsumes);
+ if (content != null) {
+ sw3RequestBody.setProperty("content", content);
+ }
+
+ }
+ break;
+ }
+ }
+ }
+ if (sw2PathVerbParamsList.isEmpty()) {
+ sw2PathVerbProps.removeProperty("parameters");
+ }
+ if (sw3RequestBody != null) {
+ // Inline for now, or the map of requestBodies can be created instead
+ // and added to the /components
+ sw2PathVerbProps.setProperty("requestBody", sw3RequestBody);
+ }
+
+ Map<String, Object> sw3PathVerbResps = null;
+ JsonMapObject sw2PathVerbResps = sw2PathVerbProps.getJsonMapProperty("responses");
+ if (sw2PathVerbResps != null) {
+ sw3PathVerbResps = new LinkedHashMap<>();
+ for (Map.Entry<String, Object> entry : sw2PathVerbResps.asMap().entrySet()) {
+ String statusCode = entry.getKey();
+ if ("200".equals(statusCode)) {
+ JsonMapObject responseMap = new JsonMapObject(CastUtils.cast((Map<?, ?>)entry.getValue()));
+ JsonMapObject okResp = new JsonMapObject();
+ String description = responseMap.getStringProperty("description");
+ if (description != null) {
+ okResp.setProperty("description", description);
+ }
+
+ JsonMapObject schema = responseMap.getJsonMapProperty("schema");
+ if (schema != null) {
+ JsonMapObject content = prepareContentFromSchema(schema, sw2PathVerbProduces);
+ if (content != null) {
+ okResp.setProperty("content", content);
+ }
+
+ }
+ sw3PathVerbResps.put("200", okResp);
+ continue;
+ }
+ sw3PathVerbResps.put(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+ }
+
+ sw3.setProperty("paths", sw2Paths);
+
+
+ }
+ private static JsonMapObject prepareContentFromSchema(JsonMapObject schema,
+ List<String> mediaTypes) {
+ JsonMapObject content = null;
+ String type = schema.getStringProperty("type");
+ String ref = null;
+ Map<String, Object> items = null;
+ if ("array".equals(type)) {
+ items = schema.getMapProperty("items");
+ ref = (String)items.get("$ref");
+ } else {
+ ref = schema.getStringProperty("$ref");
+ }
+ if (ref != null) {
+ content = new JsonMapObject();
+
+ int index = ref.lastIndexOf("/");
+ String modelName = ref.substring(index + 1);
+ if (items == null) {
+ schema.setProperty("$ref", "#components/schemas/" + modelName);
+ } else {
+ items.put("$ref", "#components/schemas/" + modelName);
+ }
+
+ List<String> mediaTypesList = mediaTypes == null
+ ? Collections.singletonList("*/*") : mediaTypes;
+
+ for (String mediaType : mediaTypesList) {
+ content.setProperty(mediaType,
+ Collections.singletonMap("schema", schema));
+
+ }
+ }
+ return content;
+ }
+
+ private static void setServersProperty(JsonMapObject sw2, JsonMapObject sw3) {
+ String sw2Host = sw2.getStringProperty("host");
+ String sw2BasePath = sw2.getStringProperty("basePath");
+ String sw2Scheme = null;
+ List<String> sw2Schemes = sw2.getListStringProperty("schemes");
+ if (StringUtils.isEmpty(sw2Schemes)) {
+ sw2Scheme = "https";
+ } else {
+ sw2Scheme = sw2Schemes.get(0);
+ }
+ String sw3ServerUrl = sw2Scheme + "://" + sw2Host + sw2BasePath;
+ sw3.setProperty("servers",
+ Collections.singletonList(
+ Collections.singletonMap("url", sw3ServerUrl)));
+
+ }
+
+
+}
diff --git a/rt/rs/description-swagger/src/test/java/org/apache/cxf/jaxrs/swagger/parse/SwaggerOpenApiUtilsTest.java b/rt/rs/description-swagger/src/test/java/org/apache/cxf/jaxrs/swagger/parse/SwaggerOpenApiUtilsTest.java
new file mode 100644
index 0000000..64f75db
--- /dev/null
+++ b/rt/rs/description-swagger/src/test/java/org/apache/cxf/jaxrs/swagger/parse/SwaggerOpenApiUtilsTest.java
@@ -0,0 +1,139 @@
+/**
+ * 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.cxf.jaxrs.swagger.parse;
+
+import java.util.List;
+
+import org.apache.cxf.jaxrs.json.basic.JsonMapObject;
+import org.apache.cxf.jaxrs.json.basic.JsonMapObjectReaderWriter;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class SwaggerOpenApiUtilsTest extends Assert {
+
+ @Test
+ public void testConvertFromSwaggerToOpenApi() {
+
+ String s = SwaggerOpenApiUtils.getOpenApiFromSwaggerLoc("/swagger2petShop.json");
+ JsonMapObjectReaderWriter readerWriter = new JsonMapObjectReaderWriter();
+ JsonMapObject sw3 = readerWriter.fromJsonToJsonObject(s);
+ assertEquals("3.0.0", sw3.getStringProperty("openapi"));
+ verifyServersProperty(sw3);
+ verifyInfoProperty(sw3);
+ verifyTagsProperty(sw3);
+ verifyPathsProperty(sw3);
+ verifyComponentsProperty(sw3);
+ }
+
+ private void verifyPathsProperty(JsonMapObject sw3) {
+ JsonMapObject paths = sw3.getJsonMapProperty("paths");
+ assertEquals(14, paths.size());
+ verifyPetPath(paths);
+ }
+
+ private void verifyPetPath(JsonMapObject paths) {
+ // /pet
+ JsonMapObject pet = paths.getJsonMapProperty("/pet");
+ assertEquals(2, pet.size());
+ verifyPetPathPost(pet);
+ verifyPetPathPut(pet);
+ }
+
+ private void verifyPetPathPost(JsonMapObject pet) {
+ JsonMapObject petPost = pet.getJsonMapProperty("post");
+ assertEquals(7, petPost.size());
+ assertNotNull(petPost.getProperty("tags"));
+ assertNotNull(petPost.getProperty("summary"));
+ assertNotNull(petPost.getProperty("description"));
+ assertNotNull(petPost.getProperty("security"));
+ assertEquals("addPet", petPost.getStringProperty("operationId"));
+ JsonMapObject requestBody = petPost.getJsonMapProperty("requestBody");
+ assertEquals(3, requestBody.size());
+ assertNotNull(requestBody.getProperty("description"));
+ assertTrue(requestBody.getBooleanProperty("required"));
+ JsonMapObject content = requestBody.getJsonMapProperty("content");
+ assertEquals(2, content.size());
+ verifySimpleContent(content, "application/json", "Pet");
+ verifySimpleContent(content, "application/xml", "Pet");
+ JsonMapObject responses = petPost.getJsonMapProperty("responses");
+ assertEquals(1, responses.size());
+ assertNotNull(responses.getProperty("405"));
+ }
+ private void verifyPetPathPut(JsonMapObject pet) {
+ JsonMapObject petPut = pet.getJsonMapProperty("put");
+ assertEquals(7, petPut.size());
+ assertNotNull(petPut.getProperty("tags"));
+ assertNotNull(petPut.getProperty("summary"));
+ assertNotNull(petPut.getProperty("description"));
+ assertNotNull(petPut.getProperty("security"));
+ assertEquals("updatePet", petPut.getStringProperty("operationId"));
+ JsonMapObject requestBody = petPut.getJsonMapProperty("requestBody");
+ assertEquals(3, requestBody.size());
+ assertNotNull(requestBody.getProperty("description"));
+ assertTrue(requestBody.getBooleanProperty("required"));
+ JsonMapObject content = requestBody.getJsonMapProperty("content");
+ assertEquals(2, content.size());
+ verifySimpleContent(content, "application/json", "Pet");
+ verifySimpleContent(content, "application/xml", "Pet");
+ JsonMapObject responses = petPut.getJsonMapProperty("responses");
+ assertEquals(3, responses.size());
+ assertNotNull(responses.getProperty("400"));
+ assertNotNull(responses.getProperty("404"));
+ assertNotNull(responses.getProperty("405"));
+ }
+
+
+ private void verifySimpleContent(JsonMapObject contentMap, String mediaType, String modelName) {
+ JsonMapObject content = contentMap.getJsonMapProperty(mediaType);
+ assertEquals(1, content.size());
+ JsonMapObject schema = content.getJsonMapProperty("schema");
+ assertEquals(1, schema.size());
+ assertEquals("#components/schemas/" + modelName, schema.getStringProperty("$ref"));
+ }
+
+ private void verifyServersProperty(JsonMapObject sw3) {
+ List<JsonMapObject> servers = sw3.getListJsonMapProperty("servers");
+ assertEquals(1, servers.size());
+ JsonMapObject server = servers.get(0);
+ assertEquals(1, server.asMap().size());
+ assertEquals("http://petstore.swagger.io/v2", server.getStringProperty("url"));
+ }
+
+ private void verifyInfoProperty(JsonMapObject sw3) {
+ //TODO: check info properties as well, though it's only copied from the original doc
+ assertNotNull(sw3.getJsonMapProperty("info"));
+ }
+
+ private void verifyTagsProperty(JsonMapObject sw3) {
+ //TODO: check info properties as well, though it's only copied from the original doc
+ assertNotNull(sw3.getListJsonMapProperty("tags"));
+ }
+
+ private void verifyComponentsProperty(JsonMapObject sw3) {
+ JsonMapObject comps = sw3.getJsonMapProperty("components");
+ assertEquals(3, comps.size());
+ JsonMapObject requestBodies = comps.getJsonMapProperty("requestBodies");
+ assertEquals(0, requestBodies.size());
+ assertNotNull(comps.getJsonMapProperty("schemas"));
+ assertNotNull(comps.getJsonMapProperty("securitySchemes"));
+
+ }
+
+}
diff --git a/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObject.java b/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObject.java
index edf5f62..3096cef 100644
--- a/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObject.java
+++ b/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObject.java
@@ -20,6 +20,7 @@
package org.apache.cxf.jaxrs.json.basic;
import java.io.Serializable;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
@@ -48,6 +49,9 @@ public class JsonMapObject implements Serializable {
count = count == null ? 2 : count++;
updateCount.put(name, count);
}
+ if (value instanceof JsonMapObject) {
+ value = ((JsonMapObject)value).asMap();
+ }
values.put(name, value);
}
@@ -66,6 +70,14 @@ public class JsonMapObject implements Serializable {
}
return null;
}
+
+ public JsonMapObject getJsonMapProperty(String name) {
+ Map<String, Object> value = getMapProperty(name);
+ if (value != null) {
+ return new JsonMapObject(value);
+ }
+ return null;
+ }
public Map<String, Object> asMap() {
return values;
@@ -105,6 +117,18 @@ public class JsonMapObject implements Serializable {
}
return null;
}
+ public List<JsonMapObject> getListJsonMapProperty(String name) {
+ Object value = getProperty(name);
+ if (value != null) {
+ List<Map<String, Object>> list = CastUtils.cast((List<?>)value);
+ List<JsonMapObject> newList = new ArrayList<>(list.size());
+ for (Map<String, Object> map : list) {
+ newList.add(new JsonMapObject(map));
+ }
+ return newList;
+ }
+ return null;
+ }
public int hashCode() {
return values.hashCode();
}
@@ -112,6 +136,11 @@ public class JsonMapObject implements Serializable {
public boolean equals(Object obj) {
return obj instanceof JsonMapObject && ((JsonMapObject)obj).values.equals(this.values);
}
+
+ public int size() {
+ return values.size();
+ }
+
public Map<String, Object> getUpdateCount() {
return updateCount == null ? null : Collections.<String, Object>unmodifiableMap(updateCount);
}
--
To stop receiving notification emails like this one, please contact
['"commits@cxf.apache.org" <co...@cxf.apache.org>'].