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

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


The following commit(s) were added to refs/heads/main by this push:
     new 0ad9e02  CAMEL-15503 camel-openapi-java - Schema Definitions not 
generating correctly (#5477)
0ad9e02 is described below

commit 0ad9e0242eede44bc8dce2c843fd021be6d7b7c5
Author: electrosaur <sramamoor...@guidewire.com>
AuthorDate: Tue May 11 03:54:52 2021 -0700

    CAMEL-15503 camel-openapi-java - Schema Definitions not generating 
correctly (#5477)
---
 components/camel-openapi-java/pom.xml              |   6 +
 .../apache/camel/openapi/RestModelConverters.java  | 148 +++++++++++++++---
 .../apache/camel/openapi/RestOpenApiReader.java    | 133 ++++++++++++++--
 .../org/apache/camel/openapi/ComplexTypesTest.java | 169 +++++++++++++++++++++
 .../RestOpenApiReaderModelBookOrderTest.java       |  10 ++
 .../org/apache/camel/openapi/model/CustomData.java |  26 ++++
 .../openapi/model/GenericComplexRequestType.java   |  52 +++++++
 .../apache/camel/openapi/model/GenericData.java    |  23 +++
 .../openapi/model/SampleComplexRequestType.java    |  71 +++++++++
 .../openapi/model/SampleComplexResponseType.java   |  59 +++++++
 .../openapi/V2SchemaForComplexTypesRequest.json    | 159 +++++++++++++++++++
 .../openapi/V2SchemaForComplexTypesResponse.json   | 102 +++++++++++++
 .../openapi/V3SchemaForComplexTypesRequest.json    | 169 +++++++++++++++++++++
 .../openapi/V3SchemaForComplexTypesResponse.json   | 112 ++++++++++++++
 14 files changed, 1209 insertions(+), 30 deletions(-)

diff --git a/components/camel-openapi-java/pom.xml 
b/components/camel-openapi-java/pom.xml
index 2a20972..203f836 100644
--- a/components/camel-openapi-java/pom.xml
+++ b/components/camel-openapi-java/pom.xml
@@ -82,6 +82,12 @@
             <artifactId>apicurio-data-models</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>io.swagger.core.v3</groupId>
+            <artifactId>swagger-core</artifactId>
+            <version>2.1.9</version>
+        </dependency>
+
 
         <!-- servlet api -->
         <dependency>
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 eb8460f..1223624 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
@@ -16,25 +16,42 @@
  */
 package org.apache.camel.openapi;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
 import io.apicurio.datamodels.core.models.Extension;
 import io.apicurio.datamodels.openapi.models.OasDocument;
 import io.apicurio.datamodels.openapi.models.OasSchema;
-import io.apicurio.datamodels.openapi.v2.models.Oas20Definitions;
 import io.apicurio.datamodels.openapi.v2.models.Oas20Document;
+import io.apicurio.datamodels.openapi.v2.models.Oas20Schema;
 import io.apicurio.datamodels.openapi.v2.models.Oas20SchemaDefinition;
 import io.apicurio.datamodels.openapi.v3.models.Oas30Document;
 import io.apicurio.datamodels.openapi.v3.models.Oas30SchemaDefinition;
+import io.swagger.v3.core.converter.ModelConverters;
+import io.swagger.v3.core.jackson.ModelResolver;
+import io.swagger.v3.oas.models.media.ArraySchema;
+import io.swagger.v3.oas.models.media.Schema;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * A Camel extended {@link ModelConverters} where we appending vendor 
extensions to include the java class name of the
  * model classes.
  */
+@SuppressWarnings("rawtypes")
 public class RestModelConverters {
 
+    private static final Logger LOG = 
LoggerFactory.getLogger(RestModelConverters.class);
+    private static final ModelConverters MODEL_CONVERTERS;
+
+    static {
+        MODEL_CONVERTERS = ModelConverters.getInstance();
+        MODEL_CONVERTERS.addConverter(new FqnModelResolver());
+    }
+
     public List<? extends OasSchema> readClass(OasDocument oasDocument, 
Class<?> clazz) {
         if (clazz.equals(java.io.File.class)) {
             // File is a special type in OAS2 / OAS3 (no model)
@@ -53,19 +70,20 @@ public class RestModelConverters {
         if (!name.contains(".")) {
             return null;
         }
+
         if (oasDocument.components == null) {
             oasDocument.components = oasDocument.createComponents();
         }
-        Oas30SchemaDefinition model = 
oasDocument.components.createSchemaDefinition(clazz.getSimpleName());
-        oasDocument.components.addSchemaDefinition(clazz.getSimpleName(), 
model);
-        model.type = clazz.getSimpleName();
-        Extension extension = model.createExtension();
-        extension.name = "x-className";
-        Map<String, String> value = new HashMap<String, String>();
-        value.put("type", "string");
-        value.put("format", name);
-        extension.value = value;
-        model.addExtension("x-className", extension);
+
+        Map<String, Schema> swaggerModel = MODEL_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();
     }
 
@@ -74,20 +92,112 @@ public class RestModelConverters {
         if (!name.contains(".")) {
             return null;
         }
+
         if (oasDocument.definitions == null) {
             oasDocument.definitions = oasDocument.createDefinitions();
         }
-        Oas20Definitions resolved = oasDocument.definitions;
-        Oas20SchemaDefinition model = 
resolved.createSchemaDefinition(clazz.getSimpleName());
-        resolved.addDefinition(clazz.getSimpleName(), model);
-        model.type = clazz.getSimpleName();
-        Extension extension = model.createExtension();
+
+        Map<String, Schema> swaggerModel = 
MODEL_CONVERTERS.getInstance().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();
+    }
+
+    private void processSchema(OasSchema model, Schema schema) {
+        String type = schema.getType();
+        model.type = type;
+        model.format = schema.getFormat();
+
+        String ref = schema.get$ref();
+        if (ref != null) {
+            if (model instanceof Oas20Schema) {
+                // Change the prefix from 3.x to 2.x
+                model.$ref = RestOpenApiReader.OAS20_SCHEMA_DEFINITION_PREFIX +
+                             
ref.substring(RestOpenApiReader.OAS30_SCHEMA_DEFINITION_PREFIX.length());
+            } else {
+                model.$ref = ref;
+            }
+        }
+
+        if (type != null) {
+            switch (type) {
+                case "object":
+                    if (schema.getProperties() != null) {
+                        //noinspection unchecked
+                        schema.getProperties().forEach((p, v) -> {
+                            OasSchema property = 
model.createPropertySchema((String) p);
+                            model.addProperty((String) p, property);
+                            processSchema(property, (Schema) v);
+                        });
+                    }
+                    break;
+                case "array":
+                    Schema items = ((ArraySchema) schema).getItems();
+                    OasSchema modelItems = model.createItemsSchema();
+                    model.items = modelItems;
+                    processSchema(modelItems, items);
+                    break;
+                case "string":
+                    if (schema.getEnum() != null) {
+                        //noinspection unchecked
+                        model.enum_ = new ArrayList<String>(schema.getEnum());
+                    }
+                    break;
+                case "number":
+                case "integer":
+                    break;
+                default:
+                    LOG.warn("Encountered unexpected type " + type + " in 
processing schema.");
+                    break;
+            }
+        }
+
+        if (schema.getRequired() != null) {
+            //noinspection unchecked
+            model.required = new ArrayList<String>(schema.getRequired());
+        }
+
+        if (schema.getAdditionalProperties() instanceof Schema) {
+            OasSchema additionalProperties = 
model.createAdditionalPropertiesSchema();
+            model.additionalProperties = additionalProperties;
+            processSchema(additionalProperties, (Schema) 
schema.getAdditionalProperties());
+        }
+
+        if (schema.getExtensions() != null) {
+            //noinspection unchecked
+            schema.getExtensions().forEach((key, value) -> {
+                Extension extension = model.createExtension();
+                extension.name = (String) key;
+                extension.value = value;
+            });
+        }
+    }
+
+    private void addClassNameExtension(OasSchema schema, String name) {
+        Extension extension = schema.createExtension();
         extension.name = "x-className";
-        Map<String, String> value = new HashMap<String, String>();
+        Map<String, String> value = new HashMap<>();
         value.put("type", "string");
         value.put("format", name);
         extension.value = value;
-        model.addExtension("x-className", extension);
-        return resolved.getDefinitions();
+        schema.addExtension("x-className", extension);
+    }
+
+    private static class FqnModelResolver extends ModelResolver {
+        public FqnModelResolver() {
+            this(new ObjectMapper());
+        }
+
+        public FqnModelResolver(ObjectMapper mapper) {
+            super(mapper);
+            this._typeNameResolver.setUseFqn(true);
+        }
     }
+
 }
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 3ad4d5c..004d80d 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
@@ -20,22 +20,29 @@ import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodType;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Function;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
+import io.apicurio.datamodels.Library;
 import io.apicurio.datamodels.core.models.ExtensibleNode;
 import io.apicurio.datamodels.core.models.Extension;
+import io.apicurio.datamodels.core.models.Node;
 import io.apicurio.datamodels.core.models.common.AuthorizationCodeOAuthFlow;
 import io.apicurio.datamodels.core.models.common.ImplicitOAuthFlow;
 import io.apicurio.datamodels.core.models.common.OAuthFlow;
 import io.apicurio.datamodels.core.models.common.SecurityRequirement;
+import io.apicurio.datamodels.core.models.common.Tag;
+import io.apicurio.datamodels.core.visitors.TraverserDirection;
 import io.apicurio.datamodels.openapi.models.OasDocument;
 import io.apicurio.datamodels.openapi.models.OasOperation;
 import io.apicurio.datamodels.openapi.models.OasParameter;
@@ -50,6 +57,7 @@ import io.apicurio.datamodels.openapi.v2.models.Oas20Response;
 import io.apicurio.datamodels.openapi.v2.models.Oas20Schema;
 import io.apicurio.datamodels.openapi.v2.models.Oas20SchemaDefinition;
 import io.apicurio.datamodels.openapi.v2.models.Oas20SecurityScheme;
+import io.apicurio.datamodels.openapi.v2.visitors.Oas20AllNodeVisitor;
 import io.apicurio.datamodels.openapi.v3.models.Oas30Document;
 import io.apicurio.datamodels.openapi.v3.models.Oas30Header;
 import io.apicurio.datamodels.openapi.v3.models.Oas30MediaType;
@@ -59,6 +67,7 @@ import io.apicurio.datamodels.openapi.v3.models.Oas30Response;
 import io.apicurio.datamodels.openapi.v3.models.Oas30Schema;
 import io.apicurio.datamodels.openapi.v3.models.Oas30SchemaDefinition;
 import io.apicurio.datamodels.openapi.v3.models.Oas30SecurityScheme;
+import io.apicurio.datamodels.openapi.v3.visitors.Oas30AllNodeVisitor;
 import org.apache.camel.CamelContext;
 import org.apache.camel.model.rest.RestDefinition;
 import org.apache.camel.model.rest.RestOperationParamDefinition;
@@ -87,6 +96,15 @@ import static java.lang.invoke.MethodHandles.publicLookup;
  */
 public class RestOpenApiReader {
 
+    public static final String OAS20_SCHEMA_DEFINITION_PREFIX = 
"#/definitions/";
+    public static final String OAS30_SCHEMA_DEFINITION_PREFIX = 
"#/components/schemas/";
+    // Types that are not allowed in references.
+    private static final Set<String> NO_REFERENCE_TYPE_NAMES = new HashSet<>(
+            Arrays.asList(
+                    "byte", "char", "short", "int", "java.lang.Integer", 
"long", "java.lang.Long", "float", "java.lang.Float",
+                    "double", "java.lang.Double", "string", 
"java.lang.String", "boolean", "java.lang.Boolean",
+                    "file", "java.io.File"));
+
     private static String getValue(CamelContext camelContext, String text) {
         return camelContext.resolvePropertyPlaceholders(text);
     }
@@ -136,6 +154,27 @@ public class RestOpenApiReader {
             parse(camelContext, openApi, rest, camelContextId, classResolver);
         }
 
+        shortenClassNames(openApi);
+
+        /*
+         * Fixes the problem of not generating the "paths" section when no 
rest route is defined.
+         * A schema with no paths is considered invalid.
+         */
+        if (openApi.paths == null) {
+            openApi.paths = openApi.createPaths();
+        }
+
+        /*
+         * Fixes the problem of generating duplicated tags which is invalid 
per the specification
+         */
+        if (openApi.tags != null) {
+            openApi.tags = new ArrayList<>(
+                    openApi.tags
+                            .stream()
+                            .collect(Collectors.toMap(Tag::getName, 
Function.identity(), (prev, current) -> prev))
+                            .values());
+        }
+
         // configure before returning
         openApi = config.configure(openApi);
         return openApi;
@@ -148,7 +187,7 @@ public class RestOpenApiReader {
 
         List<VerbDefinition> verbs = new ArrayList<>(rest.getVerbs());
         // must sort the verbs by uri so we group them together when an uri 
has multiple operations
-        Collections.sort(verbs, new VerbOrdering(camelContext));
+        verbs.sort(new VerbOrdering(camelContext));
         // we need to group the operations within the same tag, so use the 
path as default if not
         // configured
         String pathAsTag = getValue(camelContext, rest.getTag() != null
@@ -567,7 +606,7 @@ public class RestOpenApiReader {
                             String ref = modelTypeAsRef(type, openApi);
                             if (ref != null) {
                                 Oas30Schema refModel = (Oas30Schema) 
bp.createSchema();
-                                refModel.$ref = "#/components/schemas/" + ref;
+                                refModel.$ref = OAS30_SCHEMA_DEFINITION_PREFIX 
+ ref;
                                 bp.schema = refModel;
                             } else {
                                 OasSchema model = (Oas30Schema) 
bp.createSchema();
@@ -790,7 +829,7 @@ public class RestOpenApiReader {
                             String ref = modelTypeAsRef(type, openApi);
                             if (ref != null) {
                                 Oas20Schema refModel = (Oas20Schema) 
bp.createSchema();
-                                refModel.$ref = "#/definitions/" + ref;
+                                refModel.$ref = OAS20_SCHEMA_DEFINITION_PREFIX 
+ ref;
                                 bp.schema = refModel;
                             } else {
                                 OasSchema model = (Oas20Schema) 
bp.createSchema();
@@ -1216,13 +1255,11 @@ public class RestOpenApiReader {
             typeName = typeName.substring(0, typeName.length() - 2);
         }
 
-        OasSchema model = asModel(typeName, openApi);
-        if (model != null) {
-            typeName = model.type;
-            return typeName;
+        if (NO_REFERENCE_TYPE_NAMES.contains(typeName)) {
+            return null;
         }
 
-        return null;
+        return typeName;
     }
 
     private OasSchema modelTypeAsProperty(String typeName, OasDocument 
openApi, OasSchema prop) {
@@ -1235,9 +1272,9 @@ public class RestOpenApiReader {
 
         if (ref != null) {
             if (openApi instanceof Oas20Document) {
-                prop.$ref = "#/definitions/" + ref;
+                prop.$ref = OAS20_SCHEMA_DEFINITION_PREFIX + ref;
             } else if (openApi instanceof Oas30Document) {
-                prop.$ref = "#/components/schemas/" + ref;
+                prop.$ref = OAS30_SCHEMA_DEFINITION_PREFIX + ref;
             }
         } else {
             // special for byte arrays
@@ -1372,4 +1409,78 @@ public class RestOpenApiReader {
         }
     }
 
+    private void shortenClassNames(OasDocument document) {
+        if (document instanceof Oas30Document) {
+            Oas30Document oas30Document = (Oas30Document) document;
+            if (oas30Document.components == null || 
oas30Document.components.schemas == null) {
+                return;
+            }
+        } else {
+            Oas20Document oas20Document = (Oas20Document) document;
+            if (oas20Document.definitions == null || 
oas20Document.definitions.getDefinitions() == null) {
+                return;
+            }
+        }
+
+        // Make a mapping from full name to possibly shortened name.
+        Map<String, String> names = new HashMap<>();
+        Stream<String> schemaStream;
+        if (document instanceof Oas30Document) {
+            schemaStream = ((Oas30Document) 
document).components.schemas.keySet().stream();
+        } else {
+            schemaStream = ((Oas20Document) 
document).definitions.getDefinitions().stream()
+                    .map(Oas20SchemaDefinition::getName);
+        }
+        schemaStream.forEach(key -> {
+            String s = key.replaceAll("[^a-zA-Z0-9.-_]", "_");
+            String shortName = s.substring(s.lastIndexOf('.') + 1);
+            names.put(key, names.containsValue(shortName) ? s : shortName);
+        });
+
+        if (document instanceof Oas30Document) {
+            Library.visitTree(document, new Oas30AllNodeVisitor() {
+                @Override
+                protected void visitNode(Node node) {
+                    if (node instanceof Oas30SchemaDefinition) {
+                        Oas30SchemaDefinition definition = 
(Oas30SchemaDefinition) node;
+                        
definition.rename(fixSchemaReference(definition.getName(), names, 
OAS30_SCHEMA_DEFINITION_PREFIX));
+                    } else if (node instanceof Oas30Schema) {
+                        Oas30Schema schema = (Oas30Schema) node;
+                        String ref = schema.$ref;
+                        if (ref != null) {
+                            schema.$ref = OAS30_SCHEMA_DEFINITION_PREFIX +
+                                          fixSchemaReference(ref, names, 
OAS30_SCHEMA_DEFINITION_PREFIX);
+                        }
+                    }
+                }
+            }, TraverserDirection.down);
+        } else {
+            Library.visitTree(document, new Oas20AllNodeVisitor() {
+                @Override
+                protected void visitNode(Node node) {
+                    if (node instanceof Oas20SchemaDefinition) {
+                        Oas20SchemaDefinition definition = 
(Oas20SchemaDefinition) node;
+                        
definition.rename(fixSchemaReference(definition.getName(), names, 
OAS20_SCHEMA_DEFINITION_PREFIX));
+                    } else if (node instanceof Oas20Schema) {
+                        Oas20Schema schema = (Oas20Schema) node;
+                        String ref = schema.$ref;
+                        if (ref != null) {
+                            schema.$ref = OAS20_SCHEMA_DEFINITION_PREFIX +
+                                          fixSchemaReference(ref, names, 
OAS20_SCHEMA_DEFINITION_PREFIX);
+                        }
+                    }
+                }
+            }, TraverserDirection.down);
+        }
+    }
+
+    private String fixSchemaReference(String ref, Map<String, String> names, 
String prefix) {
+        if (ref.startsWith(prefix)) {
+            ref = ref.substring(prefix.length());
+        }
+
+        String name = names.get(ref);
+        return name == null ? ref : name;
+    }
+
 }
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
new file mode 100644
index 0000000..5aeacea
--- /dev/null
+++ 
b/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/ComplexTypesTest.java
@@ -0,0 +1,169 @@
+/*
+ * 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;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import io.apicurio.datamodels.Library;
+import io.apicurio.datamodels.openapi.models.OasDocument;
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.builder.RouteBuilder;
+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.SampleComplexResponseType;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class ComplexTypesTest extends CamelTestSupport {
+    private static final Logger LOG = 
LoggerFactory.getLogger(ComplexTypesTest.class);
+
+    @SuppressWarnings("unused")
+    @BindToRegistry("dummy-rest")
+    private final DummyRestConsumerFactory factory = new 
DummyRestConsumerFactory();
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                rest().securityDefinitions()
+                    .oauth2("global")
+                    .accessCode("https://AUTHORIZATION_URL";, 
"https://TOKEN_URL";)
+                    .withScope("groups", "Required scopes for Camel REST 
APIs");
+
+                rest().post("/complexRequest")
+                    .description("Demo complex request type")
+                    .type(SampleComplexRequestType.class)
+                    .consumes("application/json")
+                    .produces("text/plain")
+                    .bindingMode(RestBindingMode.json)
+                    .responseMessage()
+                    .code(200)
+                    .message("Receives a complex object as parameter")
+                    .endResponseMessage()
+                    .outType(SampleComplexResponseType.InnerClass.class)
+                    .route()
+                    .routeId("complex request type")
+                    .log("/complex request invoked");
+
+                rest().get("/complexResponse")
+                    .description("Demo complex response type")
+                    .type(SampleComplexRequestType.InnerClass.class)
+                    .consumes("application/json")
+                    .outType(SampleComplexResponseType.class)
+                    .produces("application/json")
+                    .bindingMode(RestBindingMode.json)
+                    .responseMessage()
+                    .code(200)
+                    .message("Returns a complex object")
+                    .endResponseMessage()
+                    .route()
+                    .routeId("complex response type")
+                    .log("/complex invoked")
+                    .setBody(constant(new SampleComplexResponseType()));
+            }
+        };
+    }
+
+    @Test
+    public void testV3SchemaForComplexTypesRequest() throws Exception {
+        checkSchemaGeneration("/complexRequest", "3.0", 
"V3SchemaForComplexTypesRequest.json");
+    }
+
+    @Test
+    public void testV2SchemaForComplexTypesRequest() throws Exception {
+        checkSchemaGeneration("/complexRequest", "2.0", 
"V2SchemaForComplexTypesRequest.json");
+    }
+
+    @Test
+    public void testV3SchemaForComplexTypesResponse() throws Exception {
+        checkSchemaGeneration("/complexResponse", "3.0", 
"V3SchemaForComplexTypesResponse.json");
+    }
+
+    @Test
+    public void testV2SchemaForComplexTypesResponse() throws Exception {
+        checkSchemaGeneration("/complexResponse", "2.0", 
"V2SchemaForComplexTypesResponse.json");
+    }
+
+    private void checkSchemaGeneration(String uri, String apiVersion, String 
schemaResource) throws Exception {
+        BeanConfig config = getBeanConfig(apiVersion);
+
+        List<RestDefinition> rests = context.getRestDefinitions().stream()
+                // So we get the security schema and the route schema
+                .filter(def -> def.getVerbs().isEmpty() || 
def.getVerbs().get(0).getUri().equals(uri))
+                .collect(Collectors.toList());
+
+        RestOpenApiReader reader = new RestOpenApiReader();
+        OasDocument openApi = reader.read(context, rests, null, config, 
context.getName(), new DefaultClassResolver());
+        assertNotNull(openApi);
+
+        ObjectMapper mapper = new ObjectMapper();
+        mapper.enable(SerializationFeature.INDENT_OUTPUT);
+        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+        Object dump = Library.writeNode(openApi);
+        String json = mapper.writeValueAsString(dump);
+
+        LOG.info(json);
+
+        json = generify(json);
+
+        InputStream is = 
getClass().getClassLoader().getResourceAsStream("org/apache/camel/openapi/" + 
schemaResource);
+        assertNotNull(is);
+        String expected = new BufferedReader(
+                new InputStreamReader(is, StandardCharsets.UTF_8))
+                        .lines()
+                        .collect(Collectors.joining("\n"));
+        is.close();
+
+        assertEquals(expected, json);
+    }
+
+    private BeanConfig getBeanConfig(String apiVersion) {
+        BeanConfig config = new BeanConfig();
+        config.setHost("localhost:8080");
+        config.setSchemes(new String[] { "http" });
+        config.setBasePath("/api");
+        config.setTitle("Camel User store");
+        config.setLicense("Apache 2.0");
+        
config.setLicenseUrl("https://www.apache.org/licenses/LICENSE-2.0.html";);
+        config.setVersion(apiVersion);
+        return config;
+    }
+
+    private String generify(String input) {
+        input = input.replaceAll("\"openapi\" : \"3\\..*\",", "\"openapi\" : 
\"3.x\",");
+        input = input.replaceAll("\"swagger\" : \"2\\..*\",", "\"swagger\" : 
\"2.x\",");
+        input = input.replaceAll("\"operationId\" : \"verb.*\",", 
"\"operationId\" : \"verb\",");
+        input = input.replaceAll("\"x-camelContextId\" : \"camel.*\",", 
"\"x-camelContextId\" : \"camel\",");
+        return input;
+    }
+}
diff --git 
a/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/RestOpenApiReaderModelBookOrderTest.java
 
b/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/RestOpenApiReaderModelBookOrderTest.java
index 2e45e5b..b8257ab 100644
--- 
a/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/RestOpenApiReaderModelBookOrderTest.java
+++ 
b/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/RestOpenApiReaderModelBookOrderTest.java
@@ -48,6 +48,16 @@ public class RestOpenApiReaderModelBookOrderTest extends 
CamelTestSupport {
         return new RouteBuilder() {
             @Override
             public void configure() throws Exception {
+                rest()
+                    .securityDefinitions()
+                    .oauth2("global")
+                    .accessCode(
+                        "https://AUTHORIZATION_URL";,
+                        "https://TOKEN_URL";
+                    )
+                    .withScope("groups", "Required scopes for Camel REST APIs")
+                    .end();
+
                 // this user REST service is json only
                 rest("/books").tag("dude").description("Book order 
service").consumes("application/json")
                         .produces("application/json")
diff --git 
a/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/model/CustomData.java
 
b/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/model/CustomData.java
new file mode 100644
index 0000000..ff3c945
--- /dev/null
+++ 
b/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/model/CustomData.java
@@ -0,0 +1,26 @@
+/*
+ * 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;
+
+class CustomData 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/GenericComplexRequestType.java
 
b/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/model/GenericComplexRequestType.java
new file mode 100644
index 0000000..d10c4ed
--- /dev/null
+++ 
b/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/model/GenericComplexRequestType.java
@@ -0,0 +1,52 @@
+/*
+ * 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;
+
+/**
+ * Sample request POJO that uses Generics.
+ */
+public class GenericComplexRequestType<T extends GenericData> {
+
+    private T data;
+    private List<T> listOfData;
+    private List<List<T>> listOfListOfData;
+    private Map<String, T> mapOfData;
+    private Map<String, Map<String, T>> mapOfMapOfData;
+
+    public T getData() {
+        return data;
+    }
+
+    public List<T> getListOfData() {
+        return listOfData;
+    }
+
+    public Map<String, T> getMapOfData() {
+        return mapOfData;
+    }
+
+    public List<List<T>> getListOfListOfData() {
+        return listOfListOfData;
+    }
+
+    public Map<String, Map<String, T>> getMapOfMapOfData() {
+        return mapOfMapOfData;
+    }
+}
diff --git 
a/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/model/GenericData.java
 
b/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/model/GenericData.java
new file mode 100644
index 0000000..6e37cdf
--- /dev/null
+++ 
b/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/model/GenericData.java
@@ -0,0 +1,23 @@
+/*
+ * 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;
+
+/**
+ * Generic interface used to validate that inheritance and generics also works 
with the camel open-api compoment
+ */
+interface GenericData {
+}
diff --git 
a/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/model/SampleComplexRequestType.java
 
b/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/model/SampleComplexRequestType.java
new file mode 100644
index 0000000..16b9675
--- /dev/null
+++ 
b/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/model/SampleComplexRequestType.java
@@ -0,0 +1,71 @@
+/*
+ * 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;
+
+public class SampleComplexRequestType extends 
GenericComplexRequestType<CustomData> {
+    @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;
+    }
+
+    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/SampleComplexResponseType.java
 
b/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/model/SampleComplexResponseType.java
new file mode 100644
index 0000000..ba7dcdd
--- /dev/null
+++ 
b/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/model/SampleComplexResponseType.java
@@ -0,0 +1,59 @@
+/*
+ * 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;
+
+public class SampleComplexResponseType {
+    @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;
+    }
+
+    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/V2SchemaForComplexTypesRequest.json
 
b/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/V2SchemaForComplexTypesRequest.json
new file mode 100644
index 0000000..92d0fa7
--- /dev/null
+++ 
b/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/V2SchemaForComplexTypesRequest.json
@@ -0,0 +1,159 @@
+{
+  "swagger" : "2.x",
+  "host" : "localhost:8080",
+  "basePath" : "/api",
+  "schemes" : [ "http" ],
+  "paths" : {
+    "/complexRequest" : {
+      "post" : {
+        "consumes" : [ "application/json" ],
+        "produces" : [ "text/plain" ],
+        "parameters" : [ {
+          "name" : "body",
+          "schema" : {
+            "$ref" : "#/definitions/SampleComplexRequestType"
+          },
+          "in" : "body",
+          "required" : true
+        } ],
+        "responses" : {
+          "200" : {
+            "description" : "Receives a complex object as parameter",
+            "schema" : {
+              "$ref" : "#/definitions/SampleComplexResponseType_InnerClass"
+            }
+          }
+        },
+        "operationId" : "verb",
+        "summary" : "Demo complex request type",
+        "x-camelContextId" : "camel",
+        "x-routeId" : "complex request type"
+      }
+    }
+  },
+  "definitions" : {
+    "CustomData" : {
+      "type" : "object",
+      "properties" : {
+        "customDataField" : {
+          "type" : "string"
+        }
+      },
+      "x-className" : {
+        "format" : "org.apache.camel.openapi.model.CustomData",
+        "type" : "string"
+      }
+    },
+    "SampleComplexRequestType" : {
+      "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/SampleComplexRequestType_InnerClass"
+        }
+      },
+      "x-className" : {
+        "format" : "org.apache.camel.openapi.model.SampleComplexRequestType",
+        "type" : "string"
+      }
+    },
+    "SampleComplexRequestType_InnerClass" : {
+      "type" : "object",
+      "properties" : {
+        "longField" : {
+          "format" : "int64",
+          "type" : "integer"
+        }
+      },
+      "x-className" : {
+        "format" : 
"org.apache.camel.openapi.model.SampleComplexRequestType$InnerClass",
+        "type" : "string"
+      }
+    },
+    "SampleComplexResponseType_InnerClass" : {
+      "type" : "object",
+      "properties" : {
+        "doubleField" : {
+          "format" : "double",
+          "type" : "number"
+        }
+      },
+      "x-className" : {
+        "format" : 
"org.apache.camel.openapi.model.SampleComplexResponseType$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"
+    }
+  }
+}
\ No newline at end of file
diff --git 
a/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/V2SchemaForComplexTypesResponse.json
 
b/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/V2SchemaForComplexTypesResponse.json
new file mode 100644
index 0000000..752686d
--- /dev/null
+++ 
b/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/V2SchemaForComplexTypesResponse.json
@@ -0,0 +1,102 @@
+{
+  "swagger" : "2.x",
+  "host" : "localhost:8080",
+  "basePath" : "/api",
+  "schemes" : [ "http" ],
+  "paths" : {
+    "/complexResponse" : {
+      "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/SampleComplexResponseType"
+            }
+          }
+        },
+        "operationId" : "verb",
+        "summary" : "Demo complex response type",
+        "x-camelContextId" : "camel",
+        "x-routeId" : "complex response type"
+      }
+    }
+  },
+  "definitions" : {
+    "SampleComplexRequestType_InnerClass" : {
+      "type" : "object",
+      "properties" : {
+        "longField" : {
+          "format" : "int64",
+          "type" : "integer"
+        }
+      },
+      "x-className" : {
+        "format" : 
"org.apache.camel.openapi.model.SampleComplexRequestType$InnerClass",
+        "type" : "string"
+      }
+    },
+    "SampleComplexResponseType" : {
+      "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/SampleComplexResponseType_InnerClass"
+        }
+      },
+      "x-className" : {
+        "format" : "org.apache.camel.openapi.model.SampleComplexResponseType",
+        "type" : "string"
+      }
+    },
+    "SampleComplexResponseType_InnerClass" : {
+      "type" : "object",
+      "properties" : {
+        "doubleField" : {
+          "format" : "double",
+          "type" : "number"
+        }
+      },
+      "x-className" : {
+        "format" : 
"org.apache.camel.openapi.model.SampleComplexResponseType$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"
+    }
+  }
+}
\ No newline at end of file
diff --git 
a/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/V3SchemaForComplexTypesRequest.json
 
b/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/V3SchemaForComplexTypesRequest.json
new file mode 100644
index 0000000..873d791
--- /dev/null
+++ 
b/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/V3SchemaForComplexTypesRequest.json
@@ -0,0 +1,169 @@
+{
+  "openapi" : "3.x",
+  "servers" : [ {
+    "url" : "http://localhost:8080/api";
+  } ],
+  "paths" : {
+    "/complexRequest" : {
+      "post" : {
+        "requestBody" : {
+          "description" : "",
+          "content" : {
+            "application/json" : {
+              "schema" : {
+                "$ref" : "#/components/schemas/SampleComplexRequestType"
+              }
+            }
+          },
+          "required" : true
+        },
+        "responses" : {
+          "200" : {
+            "content" : {
+              "text/plain" : {
+                "schema" : {
+                  "$ref" : 
"#/components/schemas/SampleComplexResponseType_InnerClass"
+                }
+              }
+            },
+            "description" : "Receives a complex object as parameter"
+          }
+        },
+        "operationId" : "verb",
+        "summary" : "Demo complex request type",
+        "x-camelContextId" : "camel",
+        "x-routeId" : "complex request type"
+      }
+    }
+  },
+  "components" : {
+    "schemas" : {
+      "CustomData" : {
+        "type" : "object",
+        "properties" : {
+          "customDataField" : {
+            "type" : "string"
+          }
+        },
+        "x-className" : {
+          "format" : "org.apache.camel.openapi.model.CustomData",
+          "type" : "string"
+        }
+      },
+      "SampleComplexRequestType" : {
+        "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/SampleComplexRequestType_InnerClass"
+          }
+        },
+        "x-className" : {
+          "format" : "org.apache.camel.openapi.model.SampleComplexRequestType",
+          "type" : "string"
+        }
+      },
+      "SampleComplexRequestType_InnerClass" : {
+        "type" : "object",
+        "properties" : {
+          "longField" : {
+            "format" : "int64",
+            "type" : "integer"
+          }
+        },
+        "x-className" : {
+          "format" : 
"org.apache.camel.openapi.model.SampleComplexRequestType$InnerClass",
+          "type" : "string"
+        }
+      },
+      "SampleComplexResponseType_InnerClass" : {
+        "type" : "object",
+        "properties" : {
+          "doubleField" : {
+            "format" : "double",
+            "type" : "number"
+          }
+        },
+        "x-className" : {
+          "format" : 
"org.apache.camel.openapi.model.SampleComplexResponseType$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"
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git 
a/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/V3SchemaForComplexTypesResponse.json
 
b/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/V3SchemaForComplexTypesResponse.json
new file mode 100644
index 0000000..c4c691e
--- /dev/null
+++ 
b/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/V3SchemaForComplexTypesResponse.json
@@ -0,0 +1,112 @@
+{
+  "openapi" : "3.x",
+  "servers" : [ {
+    "url" : "http://localhost:8080/api";
+  } ],
+  "paths" : {
+    "/complexResponse" : {
+      "get" : {
+        "requestBody" : {
+          "description" : "",
+          "content" : {
+            "application/json" : {
+              "schema" : {
+                "$ref" : 
"#/components/schemas/SampleComplexRequestType_InnerClass"
+              }
+            }
+          },
+          "required" : true
+        },
+        "responses" : {
+          "200" : {
+            "content" : {
+              "application/json" : {
+                "schema" : {
+                  "$ref" : "#/components/schemas/SampleComplexResponseType"
+                }
+              }
+            },
+            "description" : "Returns a complex object"
+          }
+        },
+        "operationId" : "verb",
+        "summary" : "Demo complex response type",
+        "x-camelContextId" : "camel",
+        "x-routeId" : "complex response type"
+      }
+    }
+  },
+  "components" : {
+    "schemas" : {
+      "SampleComplexRequestType_InnerClass" : {
+        "type" : "object",
+        "properties" : {
+          "longField" : {
+            "format" : "int64",
+            "type" : "integer"
+          }
+        },
+        "x-className" : {
+          "format" : 
"org.apache.camel.openapi.model.SampleComplexRequestType$InnerClass",
+          "type" : "string"
+        }
+      },
+      "SampleComplexResponseType" : {
+        "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/SampleComplexResponseType_InnerClass"
+          }
+        },
+        "x-className" : {
+          "format" : 
"org.apache.camel.openapi.model.SampleComplexResponseType",
+          "type" : "string"
+        }
+      },
+      "SampleComplexResponseType_InnerClass" : {
+        "type" : "object",
+        "properties" : {
+          "doubleField" : {
+            "format" : "double",
+            "type" : "number"
+          }
+        },
+        "x-className" : {
+          "format" : 
"org.apache.camel.openapi.model.SampleComplexResponseType$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"
+      }
+    }
+  }
+}
\ No newline at end of file

Reply via email to