From c310a459030cc74baf6b5858d52ce084f8877251 Mon Sep 17 00:00:00 2001 From: marineotter <70787551+marineotter@users.noreply.github.com> Date: Mon, 16 Mar 2026 12:45:52 +0000 Subject: [PATCH 1/2] fix: generate array model when items contain $ref, properties, or composed schema Previously, shouldGenerateArrayModel() only checked schema.getProperties() to decide whether to generate a model class for a top-level array schema. Since array schemas use 'items' rather than 'properties', this check always returned false, causing all array schemas to be treated as simple aliases and skipped during model generation. After InlineModelResolver.flatten() runs, complex inline items are extracted to #/components/schemas/ and replaced with a $ref. The updated check now inspects the items schema for: - $ref (resolved reference to an extracted component) - inline properties - composed schema (oneOf/anyOf/allOf) Simple primitive aliases like List or List remain correctly skipped as they match none of the above conditions. Fixes #7802 --- .../codegen/utils/ModelUtils.java | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java index 3e355713e7f9..2905c1338e5c 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java @@ -969,7 +969,32 @@ public static boolean shouldGenerateMapModel(Schema schema) { } public static boolean shouldGenerateArrayModel(Schema schema) { - return ModelUtils.isGenerateAliasAsModel(schema) || !(schema.getProperties() == null || schema.getProperties().isEmpty()); + if (ModelUtils.isGenerateAliasAsModel(schema)) { + return true; + } + // Generate if the array schema itself has properties (unusual but valid) + if (schema.getProperties() != null && !schema.getProperties().isEmpty()) { + return true; + } + // Generate if items are non-trivial (not a simple primitive alias like List). + // After InlineModelResolver runs, complex inline items are extracted to components + // and replaced with a $ref, so we check for $ref as well as inline properties. + Schema items = schema.getItems(); + if (items != null) { + // Items resolved to a $ref (inline object was extracted to components) + if (items.get$ref() != null && !items.get$ref().isEmpty()) { + return true; + } + // Items with inline properties + if (items.getProperties() != null && !items.getProperties().isEmpty()) { + return true; + } + // Items with composed schema (oneOf/anyOf/allOf) + if (ModelUtils.isComposedSchema(items)) { + return true; + } + } + return false; } /** From ad8b6d4854d4e848a74a2f683235ae47d7ede4b1 Mon Sep 17 00:00:00 2001 From: marineotter <70787551+marineotter@users.noreply.github.com> Date: Mon, 16 Mar 2026 14:30:01 +0000 Subject: [PATCH 2/2] test: add unit tests for shouldGenerateArrayModel and update expected file count --- .../codegen/java/JavaClientCodegenTest.java | 2 +- .../codegen/utils/ModelUtilsTest.java | 56 +++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java index 8f64f07e2c38..a349a3882c21 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java @@ -598,7 +598,7 @@ public void testJdkHttpClientWithAndWithoutDiscriminator() { generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "true"); List files = generator.opts(configurator.toClientOptInput()).generate(); - assertThat(files).hasSize(153); + assertThat(files).hasSize(156); validateJavaSourceFiles(files); assertThat(output.resolve("src/main/java/xyz/abcdef/model/Dog.java")).content() .contains("import xyz.abcdef.invoker.JSON;"); diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/utils/ModelUtilsTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/utils/ModelUtilsTest.java index 48f1340cf137..eab739e72e5b 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/utils/ModelUtilsTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/utils/ModelUtilsTest.java @@ -724,4 +724,60 @@ public void getParentNameMultipleInterfacesTest() { Schema composedSchema = allSchemas.get("RandomAnimalsResponse_animals_inner"); assertNull(ModelUtils.getParentName(composedSchema, allSchemas)); } + + @Test + public void shouldGenerateArrayModelWithRefItems() { + // array with items.$ref should generate a model (most common case after InlineModelResolver) + Schema items = new Schema<>(); + items.set$ref("#/components/schemas/Foo"); + Schema arraySchema = new ArraySchema().items(items); + assertTrue(ModelUtils.shouldGenerateArrayModel(arraySchema)); + } + + @Test + public void shouldNotGenerateArrayModelWithPrimitiveItems() { + // array with simple string items is a plain alias (e.g. List) — skip + Schema arraySchema = new ArraySchema().items(new StringSchema()); + assertFalse(ModelUtils.shouldGenerateArrayModel(arraySchema)); + } + + @Test + public void shouldNotGenerateArrayModelWithPrimitiveIntegerItems() { + // array with simple integer items is a plain alias (e.g. List) — skip + Schema arraySchema = new ArraySchema().items(new IntegerSchema()); + assertFalse(ModelUtils.shouldGenerateArrayModel(arraySchema)); + } + + @Test + public void shouldGenerateArrayModelWithComposedItems() { + // array with oneOf items should generate a model + Schema items = new Schema<>(); + items.oneOf(List.of(new Schema<>().$ref("#/components/schemas/A"), new Schema<>().$ref("#/components/schemas/B"))); + Schema arraySchema = new ArraySchema().items(items); + assertTrue(ModelUtils.shouldGenerateArrayModel(arraySchema)); + } + + @Test + public void shouldGenerateArrayModelWithInlineObjectItems() { + // array with items that have inline properties should generate a model + Schema items = new ObjectSchema(); + items.addProperty("name", new StringSchema()); + Schema arraySchema = new ArraySchema().items(items); + assertTrue(ModelUtils.shouldGenerateArrayModel(arraySchema)); + } + + @Test + public void shouldNotGenerateArrayModelWithNullItems() { + // array with no items at all — alias, skip + Schema arraySchema = new ArraySchema(); + assertFalse(ModelUtils.shouldGenerateArrayModel(arraySchema)); + } + + @Test + public void shouldGenerateArrayModelWhenGenerateAliasAsModelExtensionIsSet() { + // with x-generate-alias-as-model extension, even a simple alias should generate + Schema arraySchema = new ArraySchema().items(new StringSchema()); + arraySchema.addExtension("x-generate-alias-as-model", true); + assertTrue(ModelUtils.shouldGenerateArrayModel(arraySchema)); + } }