diff --git a/multiapi-engine/pom.xml b/multiapi-engine/pom.xml index 6c668e8a..86cffc01 100644 --- a/multiapi-engine/pom.xml +++ b/multiapi-engine/pom.xml @@ -4,7 +4,7 @@ com.sngular multiapi-engine - 6.5.0 + 6.5.1 jar diff --git a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/ModelBuilder.java b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/ModelBuilder.java index 736f476e..5172950e 100644 --- a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/ModelBuilder.java +++ b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/ModelBuilder.java @@ -448,15 +448,15 @@ private static List processArray( final List fieldObjectArrayList = new LinkedList<>(); if (!ApiTool.hasItems(schema) || ApiTool.getItems(schema).isBoolean()) { - // No `items` schema, or `items: false` (JSON Schema 2020-12). If the array - // declares positional `prefixItems` (tuple), or nothing typable at all, the - // element type degrades to Object -> List. + // No `items` schema, or `items: false` (JSON Schema 2020-12). A `prefixItems` + // tuple becomes a List of its common element type when every position shares one + // type, otherwise (mixed types, or nothing typable) the element type is Object. final boolean isTuple = ApiTool.hasPrefixItems(schema); fieldObjectArrayList.add(SchemaFieldObject .builder() .baseName(fieldName) .dataType(isTuple - ? SchemaFieldObjectType.fromTypeList(TypeConstants.ARRAY, TypeConstants.OBJECT) + ? SchemaFieldObjectType.fromTypeList(TypeConstants.ARRAY, uniformPrefixItemType(schema, specFile)) : new SchemaFieldObjectType(TypeConstants.OBJECT)) .build()); } else { @@ -922,8 +922,35 @@ private static String resolveArrayItemType(final JsonNode schema, final CommonSp if (Objects.nonNull(items) && !items.isBoolean()) { return ApiTool.hasRef(items) ? MapperUtil.getPojoNameFromRef(items, specFile, null) : ApiTool.getType(items); } - // `prefixItems` (tuple) or `items: false` -> degrade the element type to Object. - return TypeConstants.OBJECT; + // `prefixItems` (tuple): common element type if uniform, else Object. `items: false` -> Object. + return uniformPrefixItemType(schema, specFile); + } + + private static String uniformPrefixItemType(final JsonNode schema, final CommonSpecFile specFile) { + if (!ApiTool.hasPrefixItems(schema)) { + return TypeConstants.OBJECT; + } + final JsonNode prefixItems = ApiTool.getPrefixItems(schema); + if (Objects.isNull(prefixItems) || !prefixItems.isArray() || !prefixItems.elements().hasNext()) { + return TypeConstants.OBJECT; + } + String common = null; + for (final JsonNode item : prefixItems) { + final String type; + if (ApiTool.hasRef(item)) { + type = MapperUtil.getPojoNameFromRef(item, specFile, null); + } else if (ApiTool.hasType(item)) { + type = MapperUtil.getSimpleType(item, specFile); + } else { + return TypeConstants.OBJECT; + } + if (Objects.isNull(common)) { + common = type; + } else if (!common.equals(type)) { + return TypeConstants.OBJECT; + } + } + return Objects.isNull(common) ? TypeConstants.OBJECT : common; } private static SchemaFieldObject buildPatternPropertiesField( diff --git a/multiapi-engine/src/test/resources/openapigenerator/testOpenApi31Completeness/assets/GadgetDTO.java b/multiapi-engine/src/test/resources/openapigenerator/testOpenApi31Completeness/assets/GadgetDTO.java index 414b1cfc..2356a400 100644 --- a/multiapi-engine/src/test/resources/openapigenerator/testOpenApi31Completeness/assets/GadgetDTO.java +++ b/multiapi-engine/src/test/resources/openapigenerator/testOpenApi31Completeness/assets/GadgetDTO.java @@ -9,6 +9,7 @@ import org.springframework.web.multipart.MultipartFile; import java.util.List; import java.util.ArrayList; +import java.math.BigDecimal; import java.util.Map; import java.util.HashMap; @@ -24,7 +25,7 @@ public class GadgetDTO { @JsonProperty(value ="metadata") private Map metadata; @JsonProperty(value ="coords") - private List coords; + private List coords; @JsonProperty(value ="owner") private PersonDTO owner; @JsonProperty(value ="serial") @@ -52,7 +53,7 @@ public static class GadgetDTOBuilder { private Object nothing; private String id; private Map metadata = new HashMap(); - private List coords = new ArrayList(); + private List coords = new ArrayList(); private PersonDTO owner; private String serial; @@ -81,14 +82,14 @@ public GadgetDTO.GadgetDTOBuilder metadataValue(String key, String value) { return this; } - public GadgetDTO.GadgetDTOBuilder coords(List coords) { + public GadgetDTO.GadgetDTOBuilder coords(List coords) { if (!coords.isEmpty()) { this.coords.addAll(coords); } return this; } - public GadgetDTO.GadgetDTOBuilder coord(Object coord) { + public GadgetDTO.GadgetDTOBuilder coord(BigDecimal coord) { if (Objects.nonNull(coord)) { this.coords.add(coord); } @@ -144,10 +145,10 @@ public void setMetadata(Map metadata) { } @Schema(name = "coords", required = false) - public List getCoords() { + public List getCoords() { return coords; } - public void setCoords(List coords) { + public void setCoords(List coords) { this.coords = coords; } diff --git a/scs-multiapi-gradle-plugin/build.gradle b/scs-multiapi-gradle-plugin/build.gradle index bc031991..d750506a 100644 --- a/scs-multiapi-gradle-plugin/build.gradle +++ b/scs-multiapi-gradle-plugin/build.gradle @@ -21,7 +21,7 @@ repositories { } group = 'com.sngular' -version = '6.5.0' +version = '6.5.1' def SCSMultiApiPluginGroupId = group def SCSMultiApiPluginVersion = version @@ -31,7 +31,7 @@ dependencies { shadow localGroovy() shadow gradleApi() - implementation 'com.sngular:multiapi-engine:6.5.0' + implementation 'com.sngular:multiapi-engine:6.5.1' testImplementation 'org.assertj:assertj-core:3.24.2' testImplementation 'com.puppycrawl.tools:checkstyle:10.12.3' testImplementation 'org.junit.platform:junit-platform-launcher:1.9.2' @@ -100,7 +100,7 @@ testing { integrationTest(JvmTestSuite) { dependencies { - implementation 'com.sngular:scs-multiapi-gradle-plugin:6.5.0' + implementation 'com.sngular:scs-multiapi-gradle-plugin:6.5.1' implementation 'org.assertj:assertj-core:3.24.2' } diff --git a/scs-multiapi-maven-plugin/pom.xml b/scs-multiapi-maven-plugin/pom.xml index d70d56f0..eaa78b50 100644 --- a/scs-multiapi-maven-plugin/pom.xml +++ b/scs-multiapi-maven-plugin/pom.xml @@ -4,7 +4,7 @@ com.sngular scs-multiapi-maven-plugin - 6.5.0 + 6.5.1 maven-plugin AsyncApi - OpenApi Code Generator Maven Plugin @@ -271,7 +271,7 @@ com.sngular multiapi-engine - 6.5.0 + 6.5.1 org.apache.maven @@ -560,7 +560,7 @@ org.sonatype.central central-publishing-maven-plugin - 0.6.0 + 0.11.0 true true