diff --git a/README.md b/README.md index b0002ef..d7d517d 100644 --- a/README.md +++ b/README.md @@ -178,6 +178,7 @@ Currently, this plugin has some limitations that will be addressed in the future - This plugin allows the use of AllOfs and AnyOfs in the Response section. However, OpenApi does not support AllOfs in this section and AnyOf usage might not work depending on the OpenApi version you are using. - Some OpenApi functionalities are not implemented yet, such as creating example objects, instead you must use the example tag in every property of the object. +- Due to the OpenApi Parser code, when you use a $ref that points to an external file, there are some limitations when using $ref again in that same file. **Async Api implementation**: @@ -191,3 +192,4 @@ Currently, this plugin has some limitations that will be addressed in the future - Add support for generating contracts from avro files. - Further investigation for OpenApi/AsyncApi and Spring Cloud Contract possibilities. - More testing and fixing possible bugs that may occur in the future. +- Get rid of the OpenApi parser in order to control our own code. diff --git a/pom.xml b/pom.xml index 55d0ec1..aee415d 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.coru scc-multiapi-converter - 2.6.1 + 2.6.2 SCC-MultiApi-Converter Generates Spring Cloud Contracts based on an OpenApi and AsyncApi document https://github.com/corunet/scc-multiapi-converter @@ -62,7 +62,7 @@ Corunet https://corunet.github.io/ - Junior Developer + Developer Europe/Madrid @@ -73,7 +73,7 @@ Corunet https://corunet.github.io/ - Junior Developer + Developer Europe/Madrid diff --git a/src/main/java/net/coru/multiapi/converter/openapi/OpenApiContractConverter.java b/src/main/java/net/coru/multiapi/converter/openapi/OpenApiContractConverter.java index 9d06e97..1f29b42 100644 --- a/src/main/java/net/coru/multiapi/converter/openapi/OpenApiContractConverter.java +++ b/src/main/java/net/coru/multiapi/converter/openapi/OpenApiContractConverter.java @@ -131,7 +131,15 @@ private void processResponseContent(OpenAPI openAPI, ApiResponse apiResponse, Re OpenApiContractConverterUtils.processBasicResponseTypeBody(response, schema); } else { processBodyAndMatchers(bodyMap, schema, openAPI, responseBodyMatchers); - response.setBody(new Body(bodyMap)); + Schema checkArraySchema = new Schema<>(); + if (schema.get$ref() != null){ + checkArraySchema = openAPI.getComponents().getSchemas().get(OpenApiContractConverterUtils.mapRefName(schema)); + } + if ((schema.getType() != null && "array".equalsIgnoreCase(schema.getType())) || (checkArraySchema.getType() != null && "array".equalsIgnoreCase(checkArraySchema.getType()))){ + response.setBody(new Body(bodyMap.values().toArray()[0])); + } else { + response.setBody(new Body(bodyMap)); + } response.setBodyMatchers(responseBodyMatchers); } } @@ -185,15 +193,19 @@ private void processRequestContent(final OpenAPI openAPI, Operation operation, R private void processBodyAndMatchers(final Map bodyMap, Schema schema, OpenAPI openAPI, BodyMatchers bodyMatchers) { if (Objects.nonNull(schema.getType())) { - final Map basicObjectProperties = schema.getProperties(); - for (Entry property : basicObjectProperties.entrySet()) { - if (Objects.nonNull(property.getValue().get$ref())) { - final String subRef = OpenApiContractConverterUtils.mapRefName(property.getValue()); - final HashMap subProperties = (HashMap) openAPI.getComponents().getSchemas().get(subRef).getProperties(); - bodyMap.put(property.getKey(), processComplexBodyAndMatchers(property.getKey(), subProperties, openAPI, bodyMatchers)); - } else { - writeBodyMatcher(bodyMap, openAPI, bodyMatchers, property.getKey(), property.getValue(), property.getValue().getType()); + if (Objects.nonNull(schema.getProperties())){ + final Map basicObjectProperties = schema.getProperties(); + for (Entry property : basicObjectProperties.entrySet()) { + if (Objects.nonNull(property.getValue().get$ref())) { + final String subRef = OpenApiContractConverterUtils.mapRefName(property.getValue()); + final HashMap subProperties = (HashMap) openAPI.getComponents().getSchemas().get(subRef).getProperties(); + bodyMap.put(property.getKey(), processComplexBodyAndMatchers(property.getKey(), subProperties, openAPI, bodyMatchers)); + } else { + writeBodyMatcher(bodyMap, openAPI, bodyMatchers, property.getKey(), property.getValue(), property.getValue().getType()); + } } + } else { + writeBodyMatcher(bodyMap, openAPI, bodyMatchers, "[0]", schema, schema.getType()); } } if (Objects.nonNull(schema.get$ref())) { @@ -230,7 +242,7 @@ private void processBodyAndMatchers(final Map bodyMap, Schema sc } } else { Schema arraySchema = openAPI.getComponents().getSchemas().get(ref); - writeBodyMatcher(bodyMap, openAPI, bodyMatchers, ref, arraySchema, arraySchema.getType()); + writeBodyMatcher(bodyMap, openAPI, bodyMatchers, "[0]", arraySchema, arraySchema.getType()); } } } @@ -306,8 +318,14 @@ private HashMap processComplexBodyAndMatchers(final String objec final String newObjectName = objectName + "." + property.getKey(); if (Objects.nonNull(property.getValue().get$ref())) { final String ref = OpenApiContractConverterUtils.mapRefName(property.getValue()); - final HashMap subProperties = (HashMap) openAPI.getComponents().getSchemas().get(ref).getProperties(); - propertyMap.put(property.getKey(), processComplexBodyAndMatchers(newObjectName, subProperties, openAPI, bodyMatchers)); + if (Objects.nonNull(openAPI.getComponents().getSchemas().get(ref).getProperties())){ + final HashMap subProperties = (HashMap) openAPI.getComponents().getSchemas().get(ref).getProperties(); + propertyMap.put(property.getKey(), processComplexBodyAndMatchers(newObjectName, subProperties, openAPI, bodyMatchers)); + } else { + final var subProperties = ((ArraySchema) openAPI.getComponents().getSchemas().get(ref)).getItems(); + final List propertyList = new ArrayList<>(); + propertyMap.put(property.getKey(), processArray(subProperties, propertyList, newObjectName, bodyMatchers, openAPI)); + } } else { final String type; if (Objects.nonNull(property.getValue().getEnum())) { @@ -386,7 +404,7 @@ private List processArray(final Schema arraySchema, List prop if (Objects.nonNull(arraySchema.get$ref())) { final String ref = OpenApiContractConverterUtils.mapRefName(arraySchema); final HashMap subObject = (HashMap) openAPI.getComponents().getSchemas().get(ref).getProperties(); - propertyList.add(processComplexBodyAndMatchers(objectName + "[0]", subObject, openAPI, bodyMatchers)); + propertyList.add(processComplexBodyAndMatchers("[0]", subObject, openAPI, bodyMatchers)); } else { final String type = arraySchema.getType(); switch (type) { diff --git a/src/test/java/net/coru/multiapi/converter/openapi/OpenApiContractConverterTest.java b/src/test/java/net/coru/multiapi/converter/openapi/OpenApiContractConverterTest.java index bf818c4..766e847 100644 --- a/src/test/java/net/coru/multiapi/converter/openapi/OpenApiContractConverterTest.java +++ b/src/test/java/net/coru/multiapi/converter/openapi/OpenApiContractConverterTest.java @@ -178,7 +178,7 @@ void testArrays() { assertThat(contract).isNotNull(); assertThat(contract.getRequest()).isNotNull(); assertThat(contract.getResponse()).isNotNull(); - final Map bodyServerValueMap = (HashMap) contract.getResponse().getBody().getServerValue(); + final Map bodyServerValueMap = ((ArrayList>) contract.getResponse().getBody().getServerValue()).get(0); assertThat(bodyServerValueMap) .containsKey(openApiContractConverterTestFixtures.NAME) .containsKey(openApiContractConverterTestFixtures.ADDRESS) @@ -331,15 +331,15 @@ void testRefsInsideArrays() { List contractList = new ArrayList<>(contracts); Contract contract = contractList.get(0); Response response = contract.getResponse(); - final Map bodyServerValueMap = (Map) response.getBody().getServerValue(); - final List> refMap = (List>) bodyServerValueMap.get(openApiContractConverterTestFixtures.SIMILAR_GAMES); + final List> serverValueList = (List>) response.getBody().getServerValue(); + final Map bodyServerValueMap = serverValueList.get(0); assertThat(response).isNotNull(); assertThat(bodyServerValueMap) .isNotNull() - .containsKey(openApiContractConverterTestFixtures.SIMILAR_GAMES); - assertThat(refMap.get(0)) - .isNotNull() - .containsKey(openApiContractConverterTestFixtures.PRICE) + .containsKeys(openApiContractConverterTestFixtures.PRICE, + openApiContractConverterTestFixtures.AVAILABILITY, + openApiContractConverterTestFixtures.ID, + openApiContractConverterTestFixtures.NAME) .isInstanceOf(HashMap.class); } diff --git a/src/test/java/net/coru/multiapi/converter/openapi/OpenApiContractConverterTestFixtures.java b/src/test/java/net/coru/multiapi/converter/openapi/OpenApiContractConverterTestFixtures.java index b89b2f1..6502cef 100644 --- a/src/test/java/net/coru/multiapi/converter/openapi/OpenApiContractConverterTestFixtures.java +++ b/src/test/java/net/coru/multiapi/converter/openapi/OpenApiContractConverterTestFixtures.java @@ -6,6 +6,10 @@ public class OpenApiContractConverterTestFixtures { protected final String[] OPENAPI_TEXT_EXTERNAL_REF_KEYS = {"schemaRegistryName", "topic", "kafkaName", "schemaName", "repetitions"}; + protected final String AVAILABILITY = "availability"; + + protected final String ID = "id"; + protected final String PRICE = "price"; protected final String SIMILAR_GAMES = "SimilarGames"; diff --git a/src/test/resources/openapi/testArrays.yml b/src/test/resources/openapi/testArrays.yml index 2e18600..8b51862 100644 --- a/src/test/resources/openapi/testArrays.yml +++ b/src/test/resources/openapi/testArrays.yml @@ -27,7 +27,9 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Game" + type: array + items: + $ref: "#/components/schemas/Game" components: schemas: Game: