Skip to content

Commit a9f9ba9

Browse files
author
Swapneswar Sundar Ray
committed
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.
1 parent 2917ce8 commit a9f9ba9

2 files changed

Lines changed: 73 additions & 1 deletion

File tree

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: 72 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,73 @@ 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+
// Verify the example contains properties in the correct order
390+
// The order should be: zebra, apple, mango, cherry, banana
391+
assertTrue(exampleOutput.contains("\"zebra\" : 1"));
392+
assertTrue(exampleOutput.contains("\"apple\" : 2"));
393+
assertTrue(exampleOutput.contains("\"mango\" : 3"));
394+
assertTrue(exampleOutput.contains("\"cherry\" : 4"));
395+
assertTrue(exampleOutput.contains("\"banana\" : 5"));
396+
397+
// Verify the order by checking the position of each field in the string
398+
int zebraPos = exampleOutput.indexOf("\"zebra\"");
399+
int applePos = exampleOutput.indexOf("\"apple\"");
400+
int mangoPos = exampleOutput.indexOf("\"mango\"");
401+
int cherryPos = exampleOutput.indexOf("\"cherry\"");
402+
int bananaPos = exampleOutput.indexOf("\"banana\"");
403+
404+
assertTrue("zebra should come before apple", zebraPos < applePos);
405+
assertTrue("apple should come before mango", applePos < mangoPos);
406+
assertTrue("mango should come before cherry", mangoPos < cherryPos);
407+
assertTrue("cherry should come before banana", cherryPos < bananaPos);
408+
}
337409
}

0 commit comments

Comments
 (0)