Skip to content

Commit 756c973

Browse files
authored
58 support arrays to produce or consume (#76)
1 parent 97ba4ef commit 756c973

File tree

3 files changed

+152
-58
lines changed

3 files changed

+152
-58
lines changed

pom.xml

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>net.coru</groupId>
88
<artifactId>scc-multiapi-converter</artifactId>
9-
<version>3.1.0</version>
9+
<version>3.2.0</version>
1010
<name>SCC-MultiApi-Converter</name>
1111
<description>Generates Spring Cloud Contracts based on an OpenApi and AsyncApi document</description>
1212
<url>https://github.com/corunet/scc-multiapi-converter</url>
@@ -308,22 +308,14 @@
308308
</configuration>
309309
</plugin>
310310
<plugin>
311-
<groupId>org.apache.maven.plugins</groupId>
312-
<artifactId>maven-gpg-plugin</artifactId>
313-
<version>${maven-gpg-plugin.version}</version>
311+
<groupId>org.simplify4u.plugins</groupId>
312+
<artifactId>sign-maven-plugin</artifactId>
313+
<version>1.0.1</version>
314314
<executions>
315315
<execution>
316-
<id>sign-artifacts</id>
317316
<goals>
318317
<goal>sign</goal>
319318
</goals>
320-
<phase>verify</phase>
321-
<configuration>
322-
<gpgArguments>
323-
<arg>--pinentry-mode</arg>
324-
<arg>loopback</arg>
325-
</gpgArguments>
326-
</configuration>
327319
</execution>
328320
</executions>
329321
</plugin>

src/main/java/net/coru/multiapi/converter/openapi/OpenApiContractConverter.java

Lines changed: 146 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import io.swagger.v3.oas.models.media.ComposedSchema;
3232
import io.swagger.v3.oas.models.media.MapSchema;
3333
import io.swagger.v3.oas.models.media.MediaType;
34+
import io.swagger.v3.oas.models.media.ObjectSchema;
3435
import io.swagger.v3.oas.models.media.Schema;
3536
import io.swagger.v3.oas.models.parameters.Parameter;
3637
import io.swagger.v3.oas.models.responses.ApiResponse;
@@ -42,6 +43,7 @@
4243
import net.coru.multiapi.converter.openapi.model.ConverterPathItem;
4344
import net.coru.multiapi.converter.openapi.model.OperationType;
4445
import net.coru.multiapi.converter.utils.BasicTypeConstants;
46+
import org.apache.commons.lang3.ObjectUtils;
4547
import org.apache.commons.lang3.RandomStringUtils;
4648
import org.apache.commons.lang3.tuple.Pair;
4749
import org.springframework.cloud.contract.spec.Contract;
@@ -208,6 +210,7 @@ private List<Response> processResponse(final String name, final ApiResponse apiR
208210
final var response = new Response();
209211
response.body(response.anyAlphaNumeric());
210212
response.setBodyMatchers(new ResponseBodyMatchers());
213+
response.status(solveStatus(name));
211214
responseList.add(response);
212215
}
213216
}
@@ -259,8 +262,7 @@ private Integer solveStatus(final String name) {
259262
return "default".equalsIgnoreCase(name) ? 200 : Integer.parseInt(name);
260263
}
261264

262-
private List<Pair<Body, BodyMatchers>> processResponseBody(
263-
final Schema schema) {
265+
private List<Pair<Body, BodyMatchers>> processResponseBody(final Schema schema) {
264266
final var bodyList = new ArrayList<Pair<Body, BodyMatchers>>();
265267
if (schema instanceof ComposedSchema) {
266268
final ComposedSchema composedSchema = (ComposedSchema) schema;
@@ -342,7 +344,7 @@ private List<Pair<Body, BodyMatchers>> processBodyAndMatchers(final Schema schem
342344

343345
final var result = new LinkedList<Pair<Body, BodyMatchers>>();
344346
if (Objects.nonNull(schema.getType())) {
345-
result.add(processBodyAndMatchersByType(schema));
347+
result.addAll(processBodyAndMatchersByType(schema));
346348
}
347349
if (Objects.nonNull(schema.get$ref())) {
348350
result.addAll(processBodyAndMatchersByRef(schema));
@@ -360,7 +362,11 @@ private List<Pair<Body, BodyMatchers>> processBodyAndMatchersByRef(final Schema
360362
}
361363
} else {
362364
final Schema arraySchema = getSchemaFromComponent(ref);
363-
bodyList = this.applyObjectToBodyList(bodyList, null, writeBodyMatcher(null, "[0]", arraySchema, arraySchema.getType()));
365+
if (Objects.nonNull(arraySchema)) {
366+
bodyList = this.applyObjectToBodyList(bodyList, null, writeBodyMatcher(null, "[0]", arraySchema, arraySchema.getType()));
367+
} else {
368+
throw new MultiApiContractConverterException("Unsupported Schema");
369+
}
364370
}
365371
return bodyList;
366372
}
@@ -481,44 +487,70 @@ private Object addProperty(final Object dslValue, final String property, final O
481487
return result;
482488
}
483489

484-
private Pair<Body, BodyMatchers> processBodyAndMatchersByType(final Schema schema) {
490+
private List<Pair<Body, BodyMatchers>> processBodyAndMatchersByType(final Schema schema) {
491+
final List<Pair<Body, BodyMatchers>> bodyBodyMatList = new LinkedList<>();
485492
final Body body;
486493
final BodyMatchers bodyMatchers = new BodyMatchers();
487-
if (Objects.nonNull(schema.getProperties())) {
488-
final Map<String, Object> bodyMap = new HashMap<>();
489-
final Map<String, Schema> basicObjectProperties = schema.getProperties();
490-
for (Entry<String, Schema> property : basicObjectProperties.entrySet()) {
491-
if (Objects.nonNull(property.getValue().get$ref())) {
492-
final String subRef = OpenApiContractConverterUtils.mapRefName(property.getValue());
493-
final HashMap<String, Schema> subProperties = (HashMap<String, Schema>) getSchemaFromComponent(subRef).getProperties();
494-
final var result = processComplexBodyAndMatchers(property.getKey(), subProperties);
495-
bodyMap.put(property.getKey(), result.getLeft());
496-
bodyMatchers.matchers().addAll(result.getRight().matchers());
494+
if (schema instanceof ObjectSchema) {
495+
if (Objects.nonNull(schema.getProperties())) {
496+
final Map<String, Object> bodyMap = new HashMap<>();
497+
final Map<String, Schema> basicObjectProperties = schema.getProperties();
498+
final List<Pair<Body, BodyMatchers>> composedElement = new LinkedList<>();
499+
for (Entry<String, Schema> property : basicObjectProperties.entrySet()) {
500+
if (Objects.nonNull(property.getValue().get$ref())) {
501+
final String subRef = OpenApiContractConverterUtils.mapRefName(property.getValue());
502+
final var componentSchema = getSchemaFromComponent(subRef);
503+
if (Objects.nonNull(componentSchema.getProperties())) {
504+
final Map<String, Schema> subProperties = new HashMap<>(componentSchema.getProperties());
505+
final var result = processComplexBodyAndMatchers(property.getKey(), subProperties);
506+
bodyMap.put(property.getKey(), result.getLeft());
507+
bodyMatchers.matchers().addAll(result.getRight().matchers());
508+
} else if (componentSchema instanceof ArraySchema) {
509+
final var array = processArray(componentSchema, property.getKey());
510+
bodyMap.put(property.getKey(), array.getLeft());
511+
bodyMatchers.matchers().addAll(array.getRight().matchers());
512+
}
513+
} else {
514+
final var result = writeBodyMatcher(null, property.getKey(), property.getValue(), property.getValue().getType());
515+
bodyMap.put(property.getKey(), result.getLeft());
516+
bodyMatchers.matchers().addAll(result.getRight().matchers());
517+
}
518+
}
519+
body = new Body(bodyMap);
520+
if (composedElement.isEmpty()) {
521+
bodyBodyMatList.add(Pair.of(body, bodyMatchers));
497522
} else {
498-
final var result = writeBodyMatcher(null, property.getKey(), property.getValue(), property.getValue().getType());
499-
bodyMap.put(property.getKey(), result.getLeft());
500-
bodyMatchers.matchers().addAll(result.getRight().matchers());
523+
for (var halfy : composedElement) {
524+
bodyBodyMatList.add(bodyJoin(halfy, body, bodyMatchers));
525+
}
501526
}
502527
}
503-
body = new Body(bodyMap);
528+
} else if (schema instanceof ArraySchema) {
529+
final var array = processArray(schema, "[0]");
530+
body = new Body(array.getLeft());
531+
bodyMatchers.matchers().addAll(array.getRight().matchers());
532+
bodyBodyMatList.add(Pair.of(body, bodyMatchers));
533+
} else if (schema instanceof ComposedSchema) {
534+
bodyBodyMatList.addAll(processComposedSchema((ComposedSchema) schema));
504535
} else {
505536
final var result = writeBodyMatcher(null, "[0]", schema, schema.getType());
506537
body = new Body(result.getLeft());
507538
bodyMatchers.matchers().addAll(result.getRight().matchers());
539+
bodyBodyMatList.add(Pair.of(body, bodyMatchers));
508540
}
509-
return Pair.of(body, bodyMatchers);
541+
return bodyBodyMatList;
510542
}
511543

512544
private Pair<Object, BodyMatchers> writeBodyMatcher(final Entry<String, Schema> property, final String fieldName, final Schema schema, final String type) {
513-
final var example = Objects.nonNull(property) ? property.getValue().getExample() : schema.getExample();
545+
final var example = getSafeExample(property, schema);
514546
final var bodyMatchers = new BodyMatchers();
515547
final Pair<Object, BodyMatchers> result;
516548
if (Objects.nonNull(example)) {
517549
result = Pair.of(schema.getExample(), bodyMatchers);
518550
} else {
519551
final String mapKey = Objects.nonNull(property) ? property.getKey() : fieldName;
520552

521-
switch (type) {
553+
switch (ObjectUtils.defaultIfNull(type, BasicTypeConstants.GENERIC)) {
522554
case BasicTypeConstants.STRING:
523555
bodyMatchers.jsonPath(fieldName, bodyMatchers.byRegex(BasicTypeConstants.STRING_REGEX));
524556
result = Pair.of(RandomStringUtils.random(5, true, true), bodyMatchers);
@@ -537,7 +569,7 @@ private Pair<Object, BodyMatchers> writeBodyMatcher(final Entry<String, Schema>
537569
result = processObjectBodyMatcher(property, fieldName, schema);
538570
break;
539571
case BasicTypeConstants.ARRAY:
540-
final var arraySchema = Objects.nonNull(property) ? null : (ArraySchema) schema;
572+
final var arraySchema = Objects.nonNull(property) ? null : schema;
541573
result = processArrayBodyMatcher(property, fieldName, arraySchema);
542574
break;
543575
case BasicTypeConstants.ENUM:
@@ -546,6 +578,9 @@ private Pair<Object, BodyMatchers> writeBodyMatcher(final Entry<String, Schema>
546578
case BasicTypeConstants.MAP:
547579
result = processMapBodyMatcher(schema, fieldName);
548580
break;
581+
case BasicTypeConstants.GENERIC:
582+
result = processEmptyObject(fieldName);
583+
break;
549584
default:
550585
bodyMatchers.jsonPath(mapKey, bodyMatchers.byRegex(BasicTypeConstants.DEFAULT_REGEX));
551586
result = Pair.of(RandomStringUtils.random(5, true, true), bodyMatchers);
@@ -555,17 +590,36 @@ private Pair<Object, BodyMatchers> writeBodyMatcher(final Entry<String, Schema>
555590
return result;
556591
}
557592

558-
private Pair<Object, BodyMatchers> processArrayBodyMatcher(final Entry<String, Schema> property, final String fieldName, final ArraySchema schema) {
593+
private static Object getSafeExample(final Entry<String, Schema> property, final Schema schema) {
594+
final var propertyExample = Objects.nonNull(property) ? property.getValue().getExample() : null;
595+
final var schemaExample = Objects.nonNull(schema) ? schema.getExample() : null;
596+
597+
return ObjectUtils.defaultIfNull(propertyExample, schemaExample);
598+
}
599+
600+
private Pair<Object, BodyMatchers> processArrayBodyMatcher(final Entry<String, Schema> property, final String fieldName, final Schema schema) {
559601
final Object result;
560-
final Schema<?> arraySchema = Objects.nonNull(property) ? ((ArraySchema) property.getValue()).getItems() : schema.getItems();
561-
if (Objects.nonNull(arraySchema.getExample())) {
562-
result = Pair.of(arraySchema.getExample(), new BodyMatchers());
602+
final Schema<?> arraySchema = getArraySchema(property, schema);
603+
if (Objects.nonNull(arraySchema)) {
604+
if (Objects.nonNull(arraySchema.getExample())) {
605+
result = Pair.of(arraySchema.getExample(), new BodyMatchers());
606+
} else {
607+
result = processArray(arraySchema, fieldName);
608+
}
563609
} else {
564-
result = processArray(arraySchema, fieldName);
610+
result = processEmptyObject(property.getKey());
565611
}
566612
return (Pair<Object, BodyMatchers>) result;
567613
}
568614

615+
private static Schema<?> getArraySchema(final Entry<String, Schema> property, final Schema schema) {
616+
var schemaItems = schema instanceof ArraySchema ? ((ArraySchema) schema).getItems() : schema;
617+
if (Objects.nonNull(property) && property.getValue() instanceof ArraySchema) {
618+
schemaItems = ((ArraySchema) property.getValue()).getItems();
619+
}
620+
return schemaItems;
621+
}
622+
569623
private Pair<Object, BodyMatchers> processObjectBodyMatcher(final Entry<String, Schema> property, final String fieldName, final Schema schema) {
570624
final Pair<Object, BodyMatchers> result;
571625
final String ref = Objects.nonNull(property) ? property.getValue().get$ref() : schema.get$ref();
@@ -578,9 +632,13 @@ private Pair<Object, BodyMatchers> processObjectBodyMatcher(final Entry<String,
578632
} else if (Objects.nonNull(internalRef.getProperties())) {
579633
final Map<String, Schema> subProperties = internalRef.getProperties();
580634
result = processComplexBodyAndMatchers(fieldName, subProperties);
581-
} else {
635+
} else if (Objects.nonNull(internalRef.getAdditionalProperties())){
582636
final Schema subProperties = (Schema) internalRef.getAdditionalProperties();
583637
result = writeBodyMatcher(null, fieldName, subProperties, BasicTypeConstants.MAP);
638+
} else {
639+
var matcher = new BodyMatchers();
640+
matcher.jsonPath("", new BodyMatchers().byRegex(BasicTypeConstants.DEFAULT_REGEX));
641+
result = Pair.of(new Object(), matcher);
584642
}
585643
return result;
586644
}
@@ -702,7 +760,7 @@ private Pair<List<Object>, BodyMatchers> processArray(final Schema<?> arraySchem
702760
} else {
703761
final String type = arraySchema.getType();
704762
final Pair tempValue;
705-
switch (type) {
763+
switch (ObjectUtils.defaultIfNull(type, BasicTypeConstants.GENERIC)) {
706764
case BasicTypeConstants.STRING:
707765
tempValue = processStringArray(arraySchema, objectName);
708766
break;
@@ -716,11 +774,23 @@ private Pair<List<Object>, BodyMatchers> processArray(final Schema<?> arraySchem
716774
tempValue = processBooleanArray(arraySchema, objectName);
717775
break;
718776
case BasicTypeConstants.ARRAY:
719-
tempValue = processArrayArray((ArraySchema) arraySchema, objectName);
777+
if (arraySchema instanceof ArraySchema) {
778+
final var calculatedValue = processArrayArray((ArraySchema) arraySchema, objectName);
779+
if (Objects.nonNull(((ArraySchema) arraySchema).getItems().getType())) {
780+
tempValue = calculatedValue;
781+
} else {
782+
tempValue = Pair.of(calculatedValue.getLeft().get(0), calculatedValue.getRight());
783+
}
784+
} else {
785+
tempValue = processEmptyObjectArray(objectName);
786+
}
720787
break;
721788
case BasicTypeConstants.OBJECT:
722789
tempValue = processObjectArray(arraySchema, objectName);
723790
break;
791+
case BasicTypeConstants.GENERIC:
792+
tempValue = processEmptyObjectArray(objectName);
793+
break;
724794
default:
725795
tempValue = null;
726796
log.error("Format not supported");
@@ -732,7 +802,6 @@ private Pair<List<Object>, BodyMatchers> processArray(final Schema<?> arraySchem
732802
bodyMatchers.matchers().addAll(((BodyMatchers) tempValue.getRight()).matchers());
733803
} else {
734804
bodyMatchers.matchers().add((BodyMatcher) tempValue.getRight());
735-
736805
}
737806
}
738807
}
@@ -741,7 +810,25 @@ private Pair<List<Object>, BodyMatchers> processArray(final Schema<?> arraySchem
741810

742811
private Pair<Object, BodyMatchers> processObjectArray(final Schema<?> arraySchema, final String objectName) {
743812
final HashMap<String, Schema> subObject = (HashMap<String, Schema>) arraySchema.getProperties();
744-
return processComplexBodyAndMatchers(objectName, subObject);
813+
final Pair<Object, BodyMatchers> result;
814+
if (Objects.nonNull(subObject)) {
815+
result = processComplexBodyAndMatchers(objectName, subObject);
816+
} else {
817+
result = processEmptyObjectArray(objectName);
818+
}
819+
return result;
820+
}
821+
822+
private Pair<Object, BodyMatchers> processEmptyObjectArray(final String objectName) {
823+
var matcher = new BodyMatchers();
824+
matcher.jsonPath(objectName + "[0]", new BodyMatchers().byRegex(BasicTypeConstants.DEFAULT_REGEX));
825+
return Pair.of(Collections.emptyList(), matcher);
826+
}
827+
828+
private Pair<Object, BodyMatchers> processEmptyObject(final String objectName) {
829+
var matcher = new BodyMatchers();
830+
matcher.jsonPath(objectName, new BodyMatchers().byRegex(BasicTypeConstants.DEFAULT_REGEX));
831+
return Pair.of(Collections.emptyList(), matcher);
745832
}
746833

747834
private Pair<List<Object>, BodyMatchers> processArrayArray(final ArraySchema arraySchema, final String objectName) {
@@ -896,19 +983,28 @@ private Pair<Body, BodyMatchers> unify(final List<Pair<Body, BodyMatchers>> temp
896983
return Pair.of(body, bodyMatchers);
897984
}
898985

986+
private Pair<Body, BodyMatchers> bodyJoin(final Pair<Body, BodyMatchers> tempBody, final Body body, final BodyMatchers matchers) {
987+
final BodyMatchers bodyMatchers = new BodyMatchers();
988+
final var newBody = combineProperties(body, tempBody.getLeft());
989+
bodyMatchers.matchers().addAll(tempBody.getRight().matchers());
990+
bodyMatchers.matchers().addAll(matchers.matchers());
991+
return Pair.of(newBody, bodyMatchers);
992+
}
899993
private List<Schema<?>> combineSchema(final List<Schema> anyOfThis) {
900994
final List<Schema<?>> finalList = new LinkedList<>();
901-
final var anySchema = solveReferenced(anyOfThis.remove(0));
902-
if (anyOfThis.isEmpty()) {
903-
finalList.add(cloneSchema(anySchema));
904-
} else {
905-
finalList.add(anySchema);
906-
final List<Schema<?>> tempList = combineSchema(anyOfThis);
907-
finalList.addAll(tempList);
908-
for (var temp : tempList) {
909-
final var swap = cloneSchema(temp);
910-
swap.getProperties().putAll(anySchema.getProperties());
911-
finalList.add(swap);
995+
if (!anyOfThis.isEmpty()) {
996+
final var anySchema = solveReferenced(anyOfThis.remove(0));
997+
if (anyOfThis.isEmpty()) {
998+
finalList.add(cloneSchema(anySchema));
999+
} else {
1000+
finalList.add(anySchema);
1001+
final List<Schema<?>> tempList = combineSchema(anyOfThis);
1002+
finalList.addAll(tempList);
1003+
for (var temp : tempList) {
1004+
final var swap = cloneSchema(temp);
1005+
swap.getProperties().putAll(anySchema.getProperties());
1006+
finalList.add(swap);
1007+
}
9121008
}
9131009
}
9141010

@@ -994,7 +1090,11 @@ private Map<String, Schema> cloneProperties(final Map<String, Schema> properties
9941090
if (Objects.nonNull(properties)) {
9951091
properties.forEach((key, property) -> {
9961092
if ("array".equalsIgnoreCase(property.getType())) {
997-
propertiesMap.put(key, cloneArraySchema((ArraySchema) property));
1093+
if (property instanceof ArraySchema) {
1094+
propertiesMap.put(key, cloneArraySchema((ArraySchema) property));
1095+
} else {
1096+
propertiesMap.put(key, cloneSchema(property));
1097+
}
9981098
} else if (Objects.nonNull(property.getAdditionalProperties())) {
9991099
propertiesMap.put(key, cloneMapSchema((MapSchema) property));
10001100
} else {
@@ -1051,7 +1151,7 @@ private Schema solveReferenced(final Schema schema) {
10511151
}
10521152

10531153
private boolean existSchemaWithPropertiesInComponent(final String ref) {
1054-
return Objects.nonNull(componentsMap.get(ref).getProperties());
1154+
return componentsMap.containsKey(ref) && Objects.nonNull(componentsMap.get(ref).getProperties());
10551155
}
10561156

10571157
private Schema<?> getSchemaFromComponent(final String ref) {

src/main/java/net/coru/multiapi/converter/utils/BasicTypeConstants.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ public final class BasicTypeConstants {
4040

4141
public static final String OBJECT = "object";
4242

43+
public static final String GENERIC = "generic";
44+
4345
public static final String ARRAY = "array";
4446

4547
public static final String MAP = "map";

0 commit comments

Comments
 (0)