You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2022/11/11 10:05:23 UTC
[camel] branch camel-3.18.x updated: [CAMEL-18711] OpenAPI Schema references not generating correctly (#8708)
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch camel-3.18.x
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-3.18.x by this push:
new d69cf258747 [CAMEL-18711] OpenAPI Schema references not generating correctly (#8708)
d69cf258747 is described below
commit d69cf25874791de36eeafb0cfdaf2fec5520c8fc
Author: iliya-gr <il...@gmail.com>
AuthorDate: Fri Nov 11 12:58:44 2022 +0300
[CAMEL-18711] OpenAPI Schema references not generating correctly (#8708)
Add custom ModelResolver to generate x-className extension
Use x-className extension to make correct type reference
---
.../apache/camel/openapi/RestModelConverters.java | 75 ++++++---
.../apache/camel/openapi/RestOpenApiReader.java | 32 +++-
.../org/apache/camel/openapi/ComplexTypesTest.java | 59 ++++++++
.../model/CustomDataWithSchemaAnnotation.java | 29 ++++
...mpleComplexRequestTypeWithSchemaAnnotation.java | 74 +++++++++
...pleComplexResponseTypeWithSchemaAnnotation.java | 62 ++++++++
...ForComplexTypesRequestWithSchemaAnnotation.json | 158 +++++++++++++++++++
...orComplexTypesResponseWithSchemaAnnotation.json | 101 +++++++++++++
...ForComplexTypesRequestWithSchemaAnnotation.json | 168 +++++++++++++++++++++
...orComplexTypesResponseWithSchemaAnnotation.json | 111 ++++++++++++++
10 files changed, 845 insertions(+), 24 deletions(-)
diff --git a/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/RestModelConverters.java b/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/RestModelConverters.java
index b19183e9182..51113ba5cff 100644
--- a/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/RestModelConverters.java
+++ b/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/RestModelConverters.java
@@ -18,9 +18,12 @@ package org.apache.camel.openapi;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
+import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.apicurio.datamodels.core.models.Extension;
import io.apicurio.datamodels.openapi.models.OasDocument;
@@ -33,6 +36,9 @@ import io.apicurio.datamodels.openapi.v3.models.Oas30Document;
import io.apicurio.datamodels.openapi.v3.models.Oas30Schema.Oas30AnyOfSchema;
import io.apicurio.datamodels.openapi.v3.models.Oas30Schema.Oas30OneOfSchema;
import io.apicurio.datamodels.openapi.v3.models.Oas30SchemaDefinition;
+import io.swagger.v3.core.converter.AnnotatedType;
+import io.swagger.v3.core.converter.ModelConverter;
+import io.swagger.v3.core.converter.ModelConverterContext;
import io.swagger.v3.core.converter.ModelConverters;
import io.swagger.v3.core.jackson.ModelResolver;
import io.swagger.v3.oas.models.media.ArraySchema;
@@ -50,11 +56,18 @@ import org.slf4j.LoggerFactory;
public class RestModelConverters {
private static final Logger LOG = LoggerFactory.getLogger(RestModelConverters.class);
- private static final ModelConverters MODEL_CONVERTERS;
+ private static final ModelConverters MODEL30_CONVERTERS;
static {
- MODEL_CONVERTERS = ModelConverters.getInstance();
- MODEL_CONVERTERS.addConverter(new FqnModelResolver());
+ MODEL30_CONVERTERS = ModelConverters.getInstance();
+ MODEL30_CONVERTERS.addConverter(new ClassNameExtensionModelResolver(new FqnModelResolver()));
+ }
+
+ private static final ModelConverters MODEL20_CONVERTERS;
+
+ static {
+ MODEL20_CONVERTERS = ModelConverters.getInstance();
+ MODEL20_CONVERTERS.addConverter(new ClassNameExtensionModelResolver());
}
public List<? extends OasSchema> readClass(OasDocument oasDocument, Class<?> clazz) {
@@ -80,13 +93,11 @@ public class RestModelConverters {
oasDocument.components = oasDocument.createComponents();
}
- Map<String, Schema> swaggerModel = MODEL_CONVERTERS.readAll(clazz);
+ Map<String, Schema> swaggerModel = MODEL30_CONVERTERS.readAll(clazz);
swaggerModel.forEach((key, schema) -> {
Oas30SchemaDefinition model = oasDocument.components.createSchemaDefinition(key);
oasDocument.components.addSchemaDefinition(key, model);
processSchema(model, schema);
-
- addClassNameExtension(model, key);
});
return oasDocument.components.getSchemaDefinitions();
@@ -102,13 +113,11 @@ public class RestModelConverters {
oasDocument.definitions = oasDocument.createDefinitions();
}
- Map<String, Schema> swaggerModel = ModelConverters.getInstance().readAll(clazz);
+ Map<String, Schema> swaggerModel = MODEL20_CONVERTERS.readAll(clazz);
swaggerModel.forEach((key, schema) -> {
Oas20SchemaDefinition model = oasDocument.definitions.createSchemaDefinition(key);
oasDocument.definitions.addDefinition(key, model);
processSchema(model, schema);
-
- addClassNameExtension(model, key);
});
return oasDocument.definitions.getDefinitions();
@@ -251,20 +260,12 @@ public class RestModelConverters {
Extension extension = model.createExtension();
extension.name = (String) key;
extension.value = value;
+
+ model.addExtension((String) key, extension);
});
}
}
- private void addClassNameExtension(OasSchema schema, String name) {
- Extension extension = schema.createExtension();
- extension.name = "x-className";
- Map<String, String> value = new HashMap<>();
- value.put("type", "string");
- value.put("format", name);
- extension.value = value;
- schema.addExtension("x-className", extension);
- }
-
private static class FqnModelResolver extends ModelResolver {
public FqnModelResolver() {
this(new ObjectMapper());
@@ -276,4 +277,40 @@ public class RestModelConverters {
}
}
+ private static class ClassNameExtensionModelResolver extends ModelResolver {
+ private final ModelResolver delegate;
+
+ public ClassNameExtensionModelResolver() {
+ this(new ModelResolver(new ObjectMapper()));
+ }
+
+ public ClassNameExtensionModelResolver(ModelResolver delegate) {
+ super(delegate.objectMapper());
+ this.delegate = delegate;
+ }
+
+ @Override
+ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context, Iterator<ModelConverter> next) {
+ Schema result = delegate.resolve(annotatedType, context, next);
+
+ if (result != null && Objects.equals("object", result.getType())) {
+ JavaType type;
+ if (annotatedType.getType() instanceof JavaType) {
+ type = (JavaType) annotatedType.getType();
+ } else {
+ type = _mapper.constructType(annotatedType.getType());
+ }
+
+ if (!type.isContainerType()) {
+ Map<String, String> value = new HashMap<>();
+ value.put("type", "string");
+ value.put("format", type.getRawClass().getName());
+
+ result.addExtension("x-className", value);
+ }
+ }
+ return result;
+ }
+ }
+
}
diff --git a/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/RestOpenApiReader.java b/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/RestOpenApiReader.java
index 2716f6806a1..eca73f2d131 100644
--- a/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/RestOpenApiReader.java
+++ b/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/RestOpenApiReader.java
@@ -707,7 +707,7 @@ public class RestOpenApiReader {
bp.schema = arrayModel;
} else {
- String ref = modelTypeAsRef(type);
+ String ref = modelTypeAsRef(type, openApi);
if (ref != null) {
Oas30Schema refModel = (Oas30Schema) bp.createSchema();
refModel.$ref = OAS30_SCHEMA_DEFINITION_PREFIX + ref;
@@ -930,7 +930,7 @@ public class RestOpenApiReader {
arrayModel = modelTypeAsProperty(type, openApi, arrayModel);
bp.schema = arrayModel;
} else {
- String ref = modelTypeAsRef(type);
+ String ref = modelTypeAsRef(type, openApi);
if (ref != null) {
Oas20Schema refModel = (Oas20Schema) bp.createSchema();
refModel.$ref = OAS20_SCHEMA_DEFINITION_PREFIX + ref;
@@ -1357,7 +1357,7 @@ public class RestOpenApiReader {
response.headers.addHeader(name, ip);
}
- private String modelTypeAsRef(String typeName) {
+ private String modelTypeAsRef(String typeName, OasDocument openApi) {
boolean array = typeName.endsWith("[]");
if (array) {
typeName = typeName.substring(0, typeName.length() - 2);
@@ -1367,7 +1367,29 @@ public class RestOpenApiReader {
return null;
}
- return typeName;
+ if (openApi instanceof Oas20Document) {
+ if (((Oas20Document) openApi).definitions != null) {
+ for (Oas20SchemaDefinition model : ((Oas20Document) openApi).definitions.getDefinitions()) {
+ @SuppressWarnings("rawtypes")
+ Map modelType = (Map) model.getExtension("x-className").value;
+ if (modelType != null && typeName.equals(modelType.get("format"))) {
+ return model.getName();
+ }
+ }
+ }
+ } else if (openApi instanceof Oas30Document) {
+ if (((Oas30Document) openApi).components != null
+ && ((Oas30Document) openApi).components.schemas != null) {
+ for (Oas30SchemaDefinition model : ((Oas30Document) openApi).components.schemas.values()) {
+ @SuppressWarnings("rawtypes")
+ Map modelType = (Map) model.getExtension("x-className").value;
+ if (modelType != null && typeName.equals(modelType.get("format"))) {
+ return model.getName();
+ }
+ }
+ }
+ }
+ return null;
}
private OasSchema modelTypeAsProperty(String typeName, OasDocument openApi, OasSchema prop) {
@@ -1376,7 +1398,7 @@ public class RestOpenApiReader {
typeName = typeName.substring(0, typeName.length() - 2);
}
- String ref = modelTypeAsRef(typeName);
+ String ref = modelTypeAsRef(typeName, openApi);
if (ref != null) {
if (openApi instanceof Oas20Document) {
diff --git a/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/ComplexTypesTest.java b/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/ComplexTypesTest.java
index 777feccfa57..92c29887ab0 100644
--- a/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/ComplexTypesTest.java
+++ b/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/ComplexTypesTest.java
@@ -34,7 +34,9 @@ import org.apache.camel.impl.engine.DefaultClassResolver;
import org.apache.camel.model.rest.RestBindingMode;
import org.apache.camel.model.rest.RestDefinition;
import org.apache.camel.openapi.model.SampleComplexRequestType;
+import org.apache.camel.openapi.model.SampleComplexRequestTypeWithSchemaAnnotation;
import org.apache.camel.openapi.model.SampleComplexResponseType;
+import org.apache.camel.openapi.model.SampleComplexResponseTypeWithSchemaAnnotation;
import org.apache.camel.test.junit5.CamelTestSupport;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
@@ -93,6 +95,39 @@ public class ComplexTypesTest extends CamelTestSupport {
.routeId("complex response type")
.log("/complex invoked")
.setBody(constant(new SampleComplexResponseType()));
+
+ rest().post("/complexRequestWithSchemaAnnotation")
+ .description("Demo complex request type")
+ .type(SampleComplexRequestTypeWithSchemaAnnotation.class)
+ .consumes("application/json")
+ .produces("text/plain")
+ .bindingMode(RestBindingMode.json)
+ .responseMessage()
+ .code(200)
+ .message("Receives a complex object as parameter")
+ .endResponseMessage()
+ .outType(SampleComplexResponseTypeWithSchemaAnnotation.InnerClass.class)
+ .to("direct:requestWithSchemaAnnotation");
+ from("direct:requestWithSchemaAnnotation")
+ .routeId("complex request type with schema annotation")
+ .log("/complex request invoked");
+
+ rest().get("/complexResponseWithSchemaAnnotation")
+ .description("Demo complex response type")
+ .type(SampleComplexRequestType.InnerClass.class)
+ .consumes("application/json")
+ .outType(SampleComplexResponseTypeWithSchemaAnnotation.class)
+ .produces("application/json")
+ .bindingMode(RestBindingMode.json)
+ .responseMessage()
+ .code(200)
+ .message("Returns a complex object")
+ .endResponseMessage()
+ .to("direct:responseWithSchemaAnnotation");
+ from("direct:responseWithSchemaAnnotation")
+ .routeId("complex response type with schema annotation")
+ .log("/complex invoked")
+ .setBody(constant(new SampleComplexResponseTypeWithSchemaAnnotation()));
}
};
}
@@ -117,6 +152,30 @@ public class ComplexTypesTest extends CamelTestSupport {
checkSchemaGeneration("/complexResponse", "2.0", "V2SchemaForComplexTypesResponse.json");
}
+ @Test
+ public void testV3SchemaForComplexTypesWithSchemaAnnotationRequest() throws Exception {
+ checkSchemaGeneration("/complexRequestWithSchemaAnnotation", "3.0",
+ "V3SchemaForComplexTypesRequestWithSchemaAnnotation.json");
+ }
+
+ @Test
+ public void testV2SchemaForComplexTypesWithSchemaAnnotationRequest() throws Exception {
+ checkSchemaGeneration("/complexRequestWithSchemaAnnotation", "2.0",
+ "V2SchemaForComplexTypesRequestWithSchemaAnnotation.json");
+ }
+
+ @Test
+ public void testV3SchemaForComplexTypesWithSchemaAnnotationResponse() throws Exception {
+ checkSchemaGeneration("/complexResponseWithSchemaAnnotation", "3.0",
+ "V3SchemaForComplexTypesResponseWithSchemaAnnotation.json");
+ }
+
+ @Test
+ public void testV2SchemaForComplexTypesWithSchemaAnnotationResponse() throws Exception {
+ checkSchemaGeneration("/complexResponseWithSchemaAnnotation", "2.0",
+ "V2SchemaForComplexTypesResponseWithSchemaAnnotation.json");
+ }
+
private void checkSchemaGeneration(String uri, String apiVersion, String schemaResource) throws Exception {
BeanConfig config = getBeanConfig(apiVersion);
diff --git a/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/model/CustomDataWithSchemaAnnotation.java b/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/model/CustomDataWithSchemaAnnotation.java
new file mode 100644
index 00000000000..4515cac7321
--- /dev/null
+++ b/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/model/CustomDataWithSchemaAnnotation.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.camel.openapi.model;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+
+@Schema(name = "customData")
+class CustomDataWithSchemaAnnotation implements GenericData {
+
+ private String customDataField;
+
+ public String getCustomDataField() {
+ return customDataField;
+ }
+}
diff --git a/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/model/SampleComplexRequestTypeWithSchemaAnnotation.java b/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/model/SampleComplexRequestTypeWithSchemaAnnotation.java
new file mode 100644
index 00000000000..c22d391b714
--- /dev/null
+++ b/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/model/SampleComplexRequestTypeWithSchemaAnnotation.java
@@ -0,0 +1,74 @@
+/*
+ * 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.openapi.model;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+@Schema(name = "sampleRequestWithSchema")
+public class SampleComplexRequestTypeWithSchemaAnnotation extends GenericComplexRequestType<CustomDataWithSchemaAnnotation> {
+ @JsonProperty(required = true)
+ private String requestField1;
+ private String requestField2;
+ private List<String> listOfStrings;
+ private String[] arrayOfString;
+ private Map<String, String> mapOfStrings;
+ private TimeUnit timeUnit;
+ private InnerClass innerClass;
+
+ public String getRequestField1() {
+ return requestField1;
+ }
+
+ public String getRequestField2() {
+ return requestField2;
+ }
+
+ public List<String> getListOfStrings() {
+ return listOfStrings;
+ }
+
+ public String[] getArrayOfString() {
+ return arrayOfString;
+ }
+
+ @JsonProperty(required = true)
+ public Map<String, String> getMapOfStrings() {
+ return mapOfStrings;
+ }
+
+ public TimeUnit getTimeUnit() {
+ return timeUnit;
+ }
+
+ public InnerClass getInnerClass() {
+ return innerClass;
+ }
+
+ @Schema(name = "requestInner")
+ public static class InnerClass {
+ private long longField;
+
+ public long getLongField() {
+ return longField;
+ }
+ }
+}
diff --git a/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/model/SampleComplexResponseTypeWithSchemaAnnotation.java b/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/model/SampleComplexResponseTypeWithSchemaAnnotation.java
new file mode 100644
index 00000000000..3d612df279a
--- /dev/null
+++ b/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/model/SampleComplexResponseTypeWithSchemaAnnotation.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.camel.openapi.model;
+
+import java.time.Month;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+@Schema(name = "sampleResponseWithSchema")
+public class SampleComplexResponseTypeWithSchemaAnnotation {
+ @JsonProperty(required = true)
+ private String responseField1 = "Response Field 1";
+ private String responseField2 = "Response Field 2";
+ private String[] arrayOfStrings;
+ private Month month;
+ private InnerClass innerClass;
+
+ public String getResponseField1() {
+ return responseField1;
+ }
+
+ public String getResponseField2() {
+ return responseField2;
+ }
+
+ @JsonProperty(required = true)
+ public String[] getArrayOfStrings() {
+ return arrayOfStrings;
+ }
+
+ public Month getMonth() {
+ return month;
+ }
+
+ public InnerClass getInnerClass() {
+ return innerClass;
+ }
+
+ @Schema(name = "responseInner")
+ public static class InnerClass {
+ double doubleField;
+
+ public double getDoubleField() {
+ return doubleField;
+ }
+ }
+}
diff --git a/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/V2SchemaForComplexTypesRequestWithSchemaAnnotation.json b/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/V2SchemaForComplexTypesRequestWithSchemaAnnotation.json
new file mode 100644
index 00000000000..dd744b9aa90
--- /dev/null
+++ b/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/V2SchemaForComplexTypesRequestWithSchemaAnnotation.json
@@ -0,0 +1,158 @@
+{
+ "swagger" : "2.x",
+ "host" : "localhost:8080",
+ "basePath" : "/api",
+ "schemes" : [ "http" ],
+ "paths" : {
+ "/complexRequestWithSchemaAnnotation" : {
+ "post" : {
+ "consumes" : [ "application/json" ],
+ "produces" : [ "text/plain" ],
+ "parameters" : [ {
+ "name" : "body",
+ "schema" : {
+ "$ref" : "#/definitions/sampleRequestWithSchema"
+ },
+ "in" : "body",
+ "required" : true
+ } ],
+ "responses" : {
+ "200" : {
+ "description" : "Receives a complex object as parameter",
+ "schema" : {
+ "$ref" : "#/definitions/responseInner"
+ }
+ }
+ },
+ "operationId" : "verb",
+ "summary" : "Demo complex request type",
+ "x-camelContextId" : "camel"
+ }
+ }
+ },
+ "definitions" : {
+ "customData" : {
+ "type" : "object",
+ "properties" : {
+ "customDataField" : {
+ "type" : "string"
+ }
+ },
+ "x-className" : {
+ "format" : "org.apache.camel.openapi.model.CustomDataWithSchemaAnnotation",
+ "type" : "string"
+ }
+ },
+ "requestInner" : {
+ "type" : "object",
+ "properties" : {
+ "longField" : {
+ "format" : "int64",
+ "type" : "integer"
+ }
+ },
+ "x-className" : {
+ "format" : "org.apache.camel.openapi.model.SampleComplexRequestTypeWithSchemaAnnotation$InnerClass",
+ "type" : "string"
+ }
+ },
+ "sampleRequestWithSchema" : {
+ "required" : [ "mapOfStrings", "requestField1" ],
+ "type" : "object",
+ "properties" : {
+ "data" : {
+ "$ref" : "#/definitions/customData"
+ },
+ "listOfData" : {
+ "type" : "array",
+ "items" : {
+ "$ref" : "#/definitions/customData"
+ }
+ },
+ "listOfListOfData" : {
+ "type" : "array",
+ "items" : {
+ "type" : "array",
+ "items" : {
+ "$ref" : "#/definitions/customData"
+ }
+ }
+ },
+ "mapOfData" : {
+ "type" : "object",
+ "additionalProperties" : {
+ "$ref" : "#/definitions/customData"
+ }
+ },
+ "mapOfMapOfData" : {
+ "type" : "object",
+ "additionalProperties" : {
+ "type" : "object",
+ "additionalProperties" : {
+ "$ref" : "#/definitions/customData"
+ }
+ }
+ },
+ "requestField1" : {
+ "type" : "string"
+ },
+ "requestField2" : {
+ "type" : "string"
+ },
+ "listOfStrings" : {
+ "type" : "array",
+ "items" : {
+ "type" : "string"
+ }
+ },
+ "arrayOfString" : {
+ "type" : "array",
+ "items" : {
+ "type" : "string"
+ }
+ },
+ "mapOfStrings" : {
+ "type" : "object",
+ "additionalProperties" : {
+ "type" : "string"
+ }
+ },
+ "timeUnit" : {
+ "enum" : [ "NANOSECONDS", "MICROSECONDS", "MILLISECONDS", "SECONDS", "MINUTES", "HOURS", "DAYS" ],
+ "type" : "string"
+ },
+ "innerClass" : {
+ "$ref" : "#/definitions/requestInner"
+ }
+ },
+ "x-className" : {
+ "format" : "org.apache.camel.openapi.model.SampleComplexRequestTypeWithSchemaAnnotation",
+ "type" : "string"
+ }
+ },
+ "responseInner" : {
+ "type" : "object",
+ "properties" : {
+ "doubleField" : {
+ "format" : "double",
+ "type" : "number"
+ }
+ },
+ "x-className" : {
+ "format" : "org.apache.camel.openapi.model.SampleComplexResponseTypeWithSchemaAnnotation$InnerClass",
+ "type" : "string"
+ }
+ }
+ },
+ "securityDefinitions" : {
+ "global" : {
+ "flow" : "accessCode",
+ "authorizationUrl" : "https://AUTHORIZATION_URL",
+ "tokenUrl" : "https://TOKEN_URL",
+ "scopes" : {
+ "groups" : "Required scopes for Camel REST APIs"
+ },
+ "type" : "oauth2"
+ }
+ }
+}
diff --git a/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/V2SchemaForComplexTypesResponseWithSchemaAnnotation.json b/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/V2SchemaForComplexTypesResponseWithSchemaAnnotation.json
new file mode 100644
index 00000000000..4823e969630
--- /dev/null
+++ b/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/V2SchemaForComplexTypesResponseWithSchemaAnnotation.json
@@ -0,0 +1,101 @@
+{
+ "swagger" : "2.x",
+ "host" : "localhost:8080",
+ "basePath" : "/api",
+ "schemes" : [ "http" ],
+ "paths" : {
+ "/complexResponseWithSchemaAnnotation" : {
+ "get" : {
+ "consumes" : [ "application/json" ],
+ "produces" : [ "application/json" ],
+ "parameters" : [ {
+ "name" : "body",
+ "schema" : {
+ "$ref" : "#/definitions/SampleComplexRequestType_InnerClass"
+ },
+ "in" : "body",
+ "required" : true
+ } ],
+ "responses" : {
+ "200" : {
+ "description" : "Returns a complex object",
+ "schema" : {
+ "$ref" : "#/definitions/sampleResponseWithSchema"
+ }
+ }
+ },
+ "operationId" : "verb",
+ "summary" : "Demo complex response type",
+ "x-camelContextId" : "camel"
+ }
+ }
+ },
+ "definitions" : {
+ "SampleComplexRequestType_InnerClass" : {
+ "type" : "object",
+ "properties" : {
+ "longField" : {
+ "format" : "int64",
+ "type" : "integer"
+ }
+ },
+ "x-className" : {
+ "format" : "org.apache.camel.openapi.model.SampleComplexRequestType$InnerClass",
+ "type" : "string"
+ }
+ },
+ "responseInner" : {
+ "type" : "object",
+ "properties" : {
+ "doubleField" : {
+ "format" : "double",
+ "type" : "number"
+ }
+ },
+ "x-className" : {
+ "format" : "org.apache.camel.openapi.model.SampleComplexResponseTypeWithSchemaAnnotation$InnerClass",
+ "type" : "string"
+ }
+ },
+ "sampleResponseWithSchema" : {
+ "required" : [ "arrayOfStrings", "responseField1" ],
+ "type" : "object",
+ "properties" : {
+ "responseField1" : {
+ "type" : "string"
+ },
+ "responseField2" : {
+ "type" : "string"
+ },
+ "arrayOfStrings" : {
+ "type" : "array",
+ "items" : {
+ "type" : "string"
+ }
+ },
+ "month" : {
+ "enum" : [ "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE", "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER" ],
+ "type" : "string"
+ },
+ "innerClass" : {
+ "$ref" : "#/definitions/responseInner"
+ }
+ },
+ "x-className" : {
+ "format" : "org.apache.camel.openapi.model.SampleComplexResponseTypeWithSchemaAnnotation",
+ "type" : "string"
+ }
+ }
+ },
+ "securityDefinitions" : {
+ "global" : {
+ "flow" : "accessCode",
+ "authorizationUrl" : "https://AUTHORIZATION_URL",
+ "tokenUrl" : "https://TOKEN_URL",
+ "scopes" : {
+ "groups" : "Required scopes for Camel REST APIs"
+ },
+ "type" : "oauth2"
+ }
+ }
+}
diff --git a/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/V3SchemaForComplexTypesRequestWithSchemaAnnotation.json b/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/V3SchemaForComplexTypesRequestWithSchemaAnnotation.json
new file mode 100644
index 00000000000..6b6cc5301a4
--- /dev/null
+++ b/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/V3SchemaForComplexTypesRequestWithSchemaAnnotation.json
@@ -0,0 +1,168 @@
+{
+ "openapi" : "3.x",
+ "servers" : [ {
+ "url" : "http://localhost:8080/api"
+ } ],
+ "paths" : {
+ "/complexRequestWithSchemaAnnotation" : {
+ "post" : {
+ "requestBody" : {
+ "description" : "",
+ "content" : {
+ "application/json" : {
+ "schema" : {
+ "$ref" : "#/components/schemas/sampleRequestWithSchema"
+ }
+ }
+ },
+ "required" : true
+ },
+ "responses" : {
+ "200" : {
+ "content" : {
+ "text/plain" : {
+ "schema" : {
+ "$ref" : "#/components/schemas/responseInner"
+ }
+ }
+ },
+ "description" : "Receives a complex object as parameter"
+ }
+ },
+ "operationId" : "verb",
+ "summary" : "Demo complex request type",
+ "x-camelContextId" : "camel"
+ }
+ }
+ },
+ "components" : {
+ "schemas" : {
+ "customData" : {
+ "type" : "object",
+ "properties" : {
+ "customDataField" : {
+ "type" : "string"
+ }
+ },
+ "x-className" : {
+ "format" : "org.apache.camel.openapi.model.CustomDataWithSchemaAnnotation",
+ "type" : "string"
+ }
+ },
+ "requestInner" : {
+ "type" : "object",
+ "properties" : {
+ "longField" : {
+ "format" : "int64",
+ "type" : "integer"
+ }
+ },
+ "x-className" : {
+ "format" : "org.apache.camel.openapi.model.SampleComplexRequestTypeWithSchemaAnnotation$InnerClass",
+ "type" : "string"
+ }
+ },
+ "sampleRequestWithSchema" : {
+ "required" : [ "mapOfStrings", "requestField1" ],
+ "type" : "object",
+ "properties" : {
+ "data" : {
+ "$ref" : "#/components/schemas/customData"
+ },
+ "listOfData" : {
+ "type" : "array",
+ "items" : {
+ "$ref" : "#/components/schemas/customData"
+ }
+ },
+ "listOfListOfData" : {
+ "type" : "array",
+ "items" : {
+ "type" : "array",
+ "items" : {
+ "$ref" : "#/components/schemas/customData"
+ }
+ }
+ },
+ "mapOfData" : {
+ "type" : "object",
+ "additionalProperties" : {
+ "$ref" : "#/components/schemas/customData"
+ }
+ },
+ "mapOfMapOfData" : {
+ "type" : "object",
+ "additionalProperties" : {
+ "type" : "object",
+ "additionalProperties" : {
+ "$ref" : "#/components/schemas/customData"
+ }
+ }
+ },
+ "requestField1" : {
+ "type" : "string"
+ },
+ "requestField2" : {
+ "type" : "string"
+ },
+ "listOfStrings" : {
+ "type" : "array",
+ "items" : {
+ "type" : "string"
+ }
+ },
+ "arrayOfString" : {
+ "type" : "array",
+ "items" : {
+ "type" : "string"
+ }
+ },
+ "mapOfStrings" : {
+ "type" : "object",
+ "additionalProperties" : {
+ "type" : "string"
+ }
+ },
+ "timeUnit" : {
+ "enum" : [ "NANOSECONDS", "MICROSECONDS", "MILLISECONDS", "SECONDS", "MINUTES", "HOURS", "DAYS" ],
+ "type" : "string"
+ },
+ "innerClass" : {
+ "$ref" : "#/components/schemas/requestInner"
+ }
+ },
+ "x-className" : {
+ "format" : "org.apache.camel.openapi.model.SampleComplexRequestTypeWithSchemaAnnotation",
+ "type" : "string"
+ }
+ },
+ "responseInner" : {
+ "type" : "object",
+ "properties" : {
+ "doubleField" : {
+ "format" : "double",
+ "type" : "number"
+ }
+ },
+ "x-className" : {
+ "format" : "org.apache.camel.openapi.model.SampleComplexResponseTypeWithSchemaAnnotation$InnerClass",
+ "type" : "string"
+ }
+ }
+ },
+ "securitySchemes" : {
+ "global" : {
+ "flows" : {
+ "authorizationCode" : {
+ "authorizationUrl" : "https://AUTHORIZATION_URL",
+ "tokenUrl" : "https://TOKEN_URL",
+ "scopes" : {
+ "groups" : "Required scopes for Camel REST APIs"
+ }
+ }
+ },
+ "type" : "oauth2"
+ }
+ }
+ }
+}
diff --git a/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/V3SchemaForComplexTypesResponseWithSchemaAnnotation.json b/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/V3SchemaForComplexTypesResponseWithSchemaAnnotation.json
new file mode 100644
index 00000000000..bb5191c16d7
--- /dev/null
+++ b/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/V3SchemaForComplexTypesResponseWithSchemaAnnotation.json
@@ -0,0 +1,111 @@
+{
+ "openapi" : "3.x",
+ "servers" : [ {
+ "url" : "http://localhost:8080/api"
+ } ],
+ "paths" : {
+ "/complexResponseWithSchemaAnnotation" : {
+ "get" : {
+ "requestBody" : {
+ "description" : "",
+ "content" : {
+ "application/json" : {
+ "schema" : {
+ "$ref" : "#/components/schemas/SampleComplexRequestType_InnerClass"
+ }
+ }
+ },
+ "required" : true
+ },
+ "responses" : {
+ "200" : {
+ "content" : {
+ "application/json" : {
+ "schema" : {
+ "$ref" : "#/components/schemas/sampleResponseWithSchema"
+ }
+ }
+ },
+ "description" : "Returns a complex object"
+ }
+ },
+ "operationId" : "verb",
+ "summary" : "Demo complex response type",
+ "x-camelContextId" : "camel"
+ }
+ }
+ },
+ "components" : {
+ "schemas" : {
+ "SampleComplexRequestType_InnerClass" : {
+ "type" : "object",
+ "properties" : {
+ "longField" : {
+ "format" : "int64",
+ "type" : "integer"
+ }
+ },
+ "x-className" : {
+ "format" : "org.apache.camel.openapi.model.SampleComplexRequestType$InnerClass",
+ "type" : "string"
+ }
+ },
+ "responseInner" : {
+ "type" : "object",
+ "properties" : {
+ "doubleField" : {
+ "format" : "double",
+ "type" : "number"
+ }
+ },
+ "x-className" : {
+ "format" : "org.apache.camel.openapi.model.SampleComplexResponseTypeWithSchemaAnnotation$InnerClass",
+ "type" : "string"
+ }
+ },
+ "sampleResponseWithSchema" : {
+ "required" : [ "arrayOfStrings", "responseField1" ],
+ "type" : "object",
+ "properties" : {
+ "responseField1" : {
+ "type" : "string"
+ },
+ "responseField2" : {
+ "type" : "string"
+ },
+ "arrayOfStrings" : {
+ "type" : "array",
+ "items" : {
+ "type" : "string"
+ }
+ },
+ "month" : {
+ "enum" : [ "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE", "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER" ],
+ "type" : "string"
+ },
+ "innerClass" : {
+ "$ref" : "#/components/schemas/responseInner"
+ }
+ },
+ "x-className" : {
+ "format" : "org.apache.camel.openapi.model.SampleComplexResponseTypeWithSchemaAnnotation",
+ "type" : "string"
+ }
+ }
+ },
+ "securitySchemes" : {
+ "global" : {
+ "flows" : {
+ "authorizationCode" : {
+ "authorizationUrl" : "https://AUTHORIZATION_URL",
+ "tokenUrl" : "https://TOKEN_URL",
+ "scopes" : {
+ "groups" : "Required scopes for Camel REST APIs"
+ }
+ }
+ },
+ "type" : "oauth2"
+ }
+ }
+ }
+}