Skip to content

Commit e62974f

Browse files
swapneswarsundarraySwapneswar Sundar Ray
andauthored
[BUG][openapi-yaml] Preserve field order in auto-generated object-level examples (#23664) (#23674)
* fix: preserve property order in auto-generated examples The openapi-yaml generator was using HashMap when building object-level examples from property examples, which caused unstable field ordering that didn't match the source spec declaration order. Switch to LinkedHashMap to preserve the order as defined in the OpenAPI spec. This improves readability in Swagger UI and other downstream tools that render the auto-generated examples. Add test to verify property order preservation. * fix: Preserve field order in auto-generated object-level examples (#23664) The openapi-yaml generator was using HashMap when building object-level examples from property examples, which caused unstable field ordering that didn't match the source spec declaration order. Switch to LinkedHashMap to preserve the order as defined in the OpenAPI spec. This improves readability in Swagger UI and other downstream tools that render the auto-generated examples. Add test to verify property order preservation. * fix: update samples after preserving field order in auto-generated examples --------- Co-authored-by: Swapneswar Sundar Ray <jayaguru@macbookair.mynetworksettings.com>
1 parent 49e548f commit e62974f

445 files changed

Lines changed: 5265 additions & 5189 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

modules/openapi-generator/src/main/java/org/openapitools/codegen/examples/ExampleGenerator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ private Object resolveModelToExample(String name, String mediaType, Schema schem
351351
}
352352

353353
processedModels.add(name);
354-
Map<String, Object> values = new HashMap<>();
354+
Map<String, Object> values = new LinkedHashMap<>();
355355
LOGGER.debug("Resolving model '{}' to example", name);
356356
if (schema.getExample() != null) {
357357
LOGGER.debug("Using example from spec: {}", schema.getExample());

modules/openapi-generator/src/test/java/org/openapitools/codegen/ExampleGeneratorTest.java

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package org.openapitools.codegen;
22

33
import io.swagger.v3.oas.models.OpenAPI;
4+
import io.swagger.v3.oas.models.media.Schema;
5+
import io.swagger.v3.oas.models.media.IntegerSchema;
46
import org.openapitools.codegen.examples.ExampleGenerator;
57
import org.testng.annotations.Test;
68

@@ -11,6 +13,7 @@
1113

1214
import static org.testng.AssertJUnit.assertEquals;
1315
import static org.testng.AssertJUnit.assertNull;
16+
import static org.testng.AssertJUnit.assertTrue;
1417

1518
public class ExampleGeneratorTest {
1619
@Test
@@ -334,4 +337,77 @@ public void generateFromResponseSchemaWithAnyOfComposedModel() {
334337
assertEquals(String.format(Locale.ROOT, "{%n \"example_schema_property\" : \"example schema property value\"%n}"), examples.get(0).get("example"));
335338
assertEquals("200", examples.get(0).get("statusCode"));
336339
}
340+
341+
@Test
342+
public void testExamplePropertyOrderPreservation() {
343+
OpenAPI openAPI = new OpenAPI();
344+
345+
// Create a schema with properties in a specific order
346+
Schema<?> testSchema = new Schema<>();
347+
testSchema.setType("object");
348+
349+
// Use LinkedHashMap to preserve property order as defined in spec
350+
Map<String, Schema> properties = new LinkedHashMap<>();
351+
352+
// Add properties in the specific order: zebra, apple, mango, cherry, banana
353+
IntegerSchema zebraSchema = new IntegerSchema();
354+
zebraSchema.setExample(1);
355+
properties.put("zebra", zebraSchema);
356+
357+
IntegerSchema appleSchema = new IntegerSchema();
358+
appleSchema.setExample(2);
359+
properties.put("apple", appleSchema);
360+
361+
IntegerSchema mangoSchema = new IntegerSchema();
362+
mangoSchema.setExample(3);
363+
properties.put("mango", mangoSchema);
364+
365+
IntegerSchema cherrySchema = new IntegerSchema();
366+
cherrySchema.setExample(4);
367+
properties.put("cherry", cherrySchema);
368+
369+
IntegerSchema bananaSchema = new IntegerSchema();
370+
bananaSchema.setExample(5);
371+
properties.put("banana", bananaSchema);
372+
373+
testSchema.setProperties(properties);
374+
375+
// Create examples map
376+
Map<String, Schema> examples = new HashMap<>();
377+
examples.put("TestModel", testSchema);
378+
379+
// Generate the example using the model name approach
380+
ExampleGenerator generator = new ExampleGenerator(examples, openAPI);
381+
Set<String> mediaTypeKeys = new TreeSet<>();
382+
mediaTypeKeys.add("application/json");
383+
384+
List<Map<String, String>> generatedExamples = generator.generate(null, new ArrayList<>(mediaTypeKeys), "TestModel");
385+
386+
assertEquals(1, generatedExamples.size());
387+
String exampleOutput = generatedExamples.get(0).get("example");
388+
389+
System.out.println("Generated example output: " + exampleOutput);
390+
391+
// Verify the example contains properties in the correct order
392+
// The order should be: zebra, apple, mango, cherry, banana
393+
assertTrue(exampleOutput.contains("\"zebra\" : 1"));
394+
assertTrue(exampleOutput.contains("\"apple\" : 2"));
395+
assertTrue(exampleOutput.contains("\"mango\" : 3"));
396+
assertTrue(exampleOutput.contains("\"cherry\" : 4"));
397+
assertTrue(exampleOutput.contains("\"banana\" : 5"));
398+
399+
// Verify the order by checking the position of each field in the string
400+
int zebraPos = exampleOutput.indexOf("\"zebra\"");
401+
int applePos = exampleOutput.indexOf("\"apple\"");
402+
int mangoPos = exampleOutput.indexOf("\"mango\"");
403+
int cherryPos = exampleOutput.indexOf("\"cherry\"");
404+
int bananaPos = exampleOutput.indexOf("\"banana\"");
405+
406+
System.out.println("Field positions: zebra=" + zebraPos + ", apple=" + applePos + ", mango=" + mangoPos + ", cherry=" + cherryPos + ", banana=" + bananaPos);
407+
408+
assertTrue("zebra should come before apple", zebraPos < applePos);
409+
assertTrue("apple should come before mango", applePos < mangoPos);
410+
assertTrue("mango should come before cherry", mangoPos < cherryPos);
411+
assertTrue("cherry should come before banana", cherryPos < bananaPos);
412+
}
337413
}

samples/client/echo_api/csharp/restsharp/net8/EchoApi/api/openapi.yaml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -698,8 +698,8 @@ components:
698698
schemas:
699699
Category:
700700
example:
701-
name: Dogs
702701
id: 1
702+
name: Dogs
703703
properties:
704704
id:
705705
example: 1
@@ -713,8 +713,8 @@ components:
713713
name: category
714714
Tag:
715715
example:
716-
name: name
717716
id: 0
717+
name: name
718718
properties:
719719
id:
720720
format: int64
@@ -726,19 +726,19 @@ components:
726726
name: tag
727727
Pet:
728728
example:
729-
photoUrls:
730-
- photoUrls
731-
- photoUrls
732-
name: doggie
733729
id: 10
730+
name: doggie
734731
category:
735-
name: Dogs
736732
id: 1
733+
name: Dogs
734+
photoUrls:
735+
- photoUrls
736+
- photoUrls
737737
tags:
738-
- name: name
739-
id: 0
740-
- name: name
741-
id: 0
738+
- id: 0
739+
name: name
740+
- id: 0
741+
name: name
742742
status: available
743743
properties:
744744
id:

samples/client/echo_api/go/api/openapi.yaml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -698,8 +698,8 @@ components:
698698
schemas:
699699
Category:
700700
example:
701-
name: Dogs
702701
id: 1
702+
name: Dogs
703703
properties:
704704
id:
705705
example: 1
@@ -713,8 +713,8 @@ components:
713713
name: category
714714
Tag:
715715
example:
716-
name: name
717716
id: 0
717+
name: name
718718
properties:
719719
id:
720720
format: int64
@@ -726,19 +726,19 @@ components:
726726
name: tag
727727
Pet:
728728
example:
729-
photoUrls:
730-
- photoUrls
731-
- photoUrls
732-
name: doggie
733729
id: 10
730+
name: doggie
734731
category:
735-
name: Dogs
736732
id: 1
733+
name: Dogs
734+
photoUrls:
735+
- photoUrls
736+
- photoUrls
737737
tags:
738-
- name: name
739-
id: 0
740-
- name: name
741-
id: 0
738+
- id: 0
739+
name: name
740+
- id: 0
741+
name: name
742742
status: available
743743
properties:
744744
id:

samples/client/echo_api/java/apache-httpclient/api/openapi.yaml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -766,8 +766,8 @@ components:
766766
schemas:
767767
Category:
768768
example:
769-
name: Dogs
770769
id: 1
770+
name: Dogs
771771
properties:
772772
id:
773773
example: 1
@@ -781,8 +781,8 @@ components:
781781
name: category
782782
Tag:
783783
example:
784-
name: name
785784
id: 0
785+
name: name
786786
properties:
787787
id:
788788
format: int64
@@ -794,19 +794,19 @@ components:
794794
name: tag
795795
Pet:
796796
example:
797-
photoUrls:
798-
- photoUrls
799-
- photoUrls
800-
name: doggie
801797
id: 10
798+
name: doggie
802799
category:
803-
name: Dogs
804800
id: 1
801+
name: Dogs
802+
photoUrls:
803+
- photoUrls
804+
- photoUrls
805805
tags:
806-
- name: name
807-
id: 0
808-
- name: name
809-
id: 0
806+
- id: 0
807+
name: name
808+
- id: 0
809+
name: name
810810
status: available
811811
properties:
812812
id:

samples/client/echo_api/java/feign-gson/api/openapi.yaml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -766,8 +766,8 @@ components:
766766
schemas:
767767
Category:
768768
example:
769-
name: Dogs
770769
id: 1
770+
name: Dogs
771771
properties:
772772
id:
773773
example: 1
@@ -781,8 +781,8 @@ components:
781781
name: category
782782
Tag:
783783
example:
784-
name: name
785784
id: 0
785+
name: name
786786
properties:
787787
id:
788788
format: int64
@@ -794,19 +794,19 @@ components:
794794
name: tag
795795
Pet:
796796
example:
797-
photoUrls:
798-
- photoUrls
799-
- photoUrls
800-
name: doggie
801797
id: 10
798+
name: doggie
802799
category:
803-
name: Dogs
804800
id: 1
801+
name: Dogs
802+
photoUrls:
803+
- photoUrls
804+
- photoUrls
805805
tags:
806-
- name: name
807-
id: 0
808-
- name: name
809-
id: 0
806+
- id: 0
807+
name: name
808+
- id: 0
809+
name: name
810810
status: available
811811
properties:
812812
id:

samples/client/echo_api/java/native/api/openapi.yaml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -766,8 +766,8 @@ components:
766766
schemas:
767767
Category:
768768
example:
769-
name: Dogs
770769
id: 1
770+
name: Dogs
771771
properties:
772772
id:
773773
example: 1
@@ -781,8 +781,8 @@ components:
781781
name: category
782782
Tag:
783783
example:
784-
name: name
785784
id: 0
785+
name: name
786786
properties:
787787
id:
788788
format: int64
@@ -794,19 +794,19 @@ components:
794794
name: tag
795795
Pet:
796796
example:
797-
photoUrls:
798-
- photoUrls
799-
- photoUrls
800-
name: doggie
801797
id: 10
798+
name: doggie
802799
category:
803-
name: Dogs
804800
id: 1
801+
name: Dogs
802+
photoUrls:
803+
- photoUrls
804+
- photoUrls
805805
tags:
806-
- name: name
807-
id: 0
808-
- name: name
809-
id: 0
806+
- id: 0
807+
name: name
808+
- id: 0
809+
name: name
810810
status: available
811811
properties:
812812
id:

0 commit comments

Comments
 (0)